diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 0000000..c7821f6 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,4 @@ +version 0.0.9 +-- supporting anomaly detection +-- simple management web dashboard +-- simple cache implementation with linkedlist (replaced redis for connection polling and performance issue) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..a552aa1 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,570 @@ +cmake_minimum_required(VERSION 3.17) +project(ironfox) + +set(CMAKE_CXX_STANDARD 14) + +include_directories(modules/ngx_http_header_inspect) +include_directories(modules/ngx_http_vts/src) +include_directories(modules/replace-filter-nginx-module/src) +include_directories(nginx-1.19.2/objs) +include_directories(nginx-1.19.2/src/core) +include_directories(nginx-1.19.2/src/event) +include_directories(nginx-1.19.2/src/http) +include_directories(nginx-1.19.2/src/http/modules) +include_directories(nginx-1.19.2/src/http/modules/perl) +include_directories(nginx-1.19.2/src/http/v2) +include_directories(nginx-1.19.2/src/mail) +include_directories(nginx-1.19.2/src/os/unix) +include_directories(nginx-1.19.2/src/stream) + +add_executable(ironfox + cert/nginx-selfsigned.crt + cert/nginx-selfsigned.key + html/40x.html + html/50x.html + html/bot.html + html/fingerprint.js + html/hourglass.gif + html/iron.js + html/sweet-alert.css + html/sweet-alert.min.js + manager/application.properties + manager/innovera.service + manager/runservice.sh + modules/nginx-eval-module/Changelog + modules/nginx-eval-module/config + modules/nginx-eval-module/LICENCE + modules/nginx-eval-module/ngx_http_eval_module.c + modules/nginx-eval-module/README + modules/nginx-http-footer-filter/config + modules/nginx-http-footer-filter/ngx_http_footer_filter_module.c + modules/nginx-http-footer-filter/README.md + modules/ngx_http_bot_protection_module/doc/usecases.txt + modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.c + modules/ngx_http_bot_protection_module/t/00base.t + modules/ngx_http_bot_protection_module/t/01crypto.t + modules/ngx_http_bot_protection_module/util/back/aes.js + modules/ngx_http_bot_protection_module/util/back/aes.patch + modules/ngx_http_bot_protection_module/util/back/tests.sh + modules/ngx_http_bot_protection_module/util/back/valgrind.sh + modules/ngx_http_bot_protection_module/util/Iron.js + modules/ngx_http_bot_protection_module/util/tests.sh + modules/ngx_http_bot_protection_module/util/valgrind.sh + modules/ngx_http_bot_protection_module/config + modules/ngx_http_captcha_module/config + modules/ngx_http_captcha_module/ngx_http_captcha_module.c + modules/ngx_http_captcha_module/README.md + modules/ngx_http_header_inspect/config + modules/ngx_http_header_inspect/ironaes.c + modules/ngx_http_header_inspect/ironaes.h + modules/ngx_http_header_inspect/ngx_http_header_inspect.c + modules/ngx_http_header_inspect/README + modules/ngx_http_vts/share/status.compress.html + modules/ngx_http_vts/share/status.template.html + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module_html.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.h + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.c + modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.h + modules/ngx_http_vts/t/000.display_html.t + modules/ngx_http_vts/t/001.display_json.t + modules/ngx_http_vts/t/002.check_json_syntax.t + modules/ngx_http_vts/t/003.filter_by_host.t + modules/ngx_http_vts/t/004.filter_by_set_key.t + modules/ngx_http_vts/t/005.filter_check_duplicate.t + modules/ngx_http_vts/t/006.control_status_fully.t + modules/ngx_http_vts/t/007.control_status_group.t + modules/ngx_http_vts/t/008.control_status_zone.t + modules/ngx_http_vts/t/009.control_reset_fully.t + modules/ngx_http_vts/t/010.control_reset_group.t + modules/ngx_http_vts/t/011.control_reset_zone.t + modules/ngx_http_vts/t/012.control_delete_fully.t + modules/ngx_http_vts/t/013.control_delete_group.t + modules/ngx_http_vts/t/014.control_delete_zone.t + modules/ngx_http_vts/t/015.vts_variables_by_lua.t + modules/ngx_http_vts/t/016.limit_traffic_by_lua.t + modules/ngx_http_vts/t/017.limit_traffic.t + modules/ngx_http_vts/t/018.limit_traffic_by_set_key.t + modules/ngx_http_vts/t/019.limit_traffic_check_duplicate.t + modules/ngx_http_vts/t/020.display_sum_key.t + modules/ngx_http_vts/t/021.set_by_filter.t + modules/ngx_http_vts/util/fileToHex.pl + modules/ngx_http_vts/util/tplToBuffer.sh + modules/ngx_http_vts/util/tplToDefine.sh + modules/ngx_http_vts/Changes + modules/ngx_http_vts/config + modules/ngx_http_vts/LICENSE + modules/ngx_http_vts/README.md + modules/ngx_input_validation_module/config + modules/ngx_input_validation_module/ngx_input_validation_module.c + modules/ngx_input_validation_module/readme.txt + modules/replace-filter-nginx-module/src/ddebug.h + modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.c + modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.h + modules/replace-filter-nginx-module/src/ngx_http_replace_parse.c + modules/replace-filter-nginx-module/src/ngx_http_replace_parse.h + modules/replace-filter-nginx-module/src/ngx_http_replace_script.c + modules/replace-filter-nginx-module/src/ngx_http_replace_script.h + modules/replace-filter-nginx-module/src/ngx_http_replace_util.c + modules/replace-filter-nginx-module/src/ngx_http_replace_util.h + modules/replace-filter-nginx-module/t/01-sanity.t + modules/replace-filter-nginx-module/t/02-max-buffered.t + modules/replace-filter-nginx-module/t/03-var.t + modules/replace-filter-nginx-module/t/04-capturing.t + modules/replace-filter-nginx-module/t/05-capturing-max-buffered.t + modules/replace-filter-nginx-module/t/06-if.t + modules/replace-filter-nginx-module/t/07-multi.t + modules/replace-filter-nginx-module/t/08-gzip.t + modules/replace-filter-nginx-module/t/09-unused.t + modules/replace-filter-nginx-module/t/10-last-modified.t + modules/replace-filter-nginx-module/t/11-skip.t + modules/replace-filter-nginx-module/util/build.sh + modules/replace-filter-nginx-module/config + modules/replace-filter-nginx-module/README.markdown + modules/replace-filter-nginx-module/valgrind.suppress + nginx-1.19.2/auto/cc/acc + nginx-1.19.2/auto/cc/bcc + nginx-1.19.2/auto/cc/ccc + nginx-1.19.2/auto/cc/clang + nginx-1.19.2/auto/cc/conf + nginx-1.19.2/auto/cc/gcc + nginx-1.19.2/auto/cc/icc + nginx-1.19.2/auto/cc/msvc + nginx-1.19.2/auto/cc/name + nginx-1.19.2/auto/cc/owc + nginx-1.19.2/auto/cc/sunc + nginx-1.19.2/auto/lib/geoip/conf + nginx-1.19.2/auto/lib/google-perftools/conf + nginx-1.19.2/auto/lib/libatomic/conf + nginx-1.19.2/auto/lib/libatomic/make + nginx-1.19.2/auto/lib/libgd/conf + nginx-1.19.2/auto/lib/libxslt/conf + nginx-1.19.2/auto/lib/openssl/conf + nginx-1.19.2/auto/lib/openssl/make + nginx-1.19.2/auto/lib/openssl/makefile.bcc + nginx-1.19.2/auto/lib/openssl/makefile.msvc + nginx-1.19.2/auto/lib/pcre/conf + nginx-1.19.2/auto/lib/pcre/make + nginx-1.19.2/auto/lib/pcre/makefile.bcc + nginx-1.19.2/auto/lib/pcre/makefile.msvc + nginx-1.19.2/auto/lib/pcre/makefile.owc + nginx-1.19.2/auto/lib/perl/conf + nginx-1.19.2/auto/lib/perl/make + nginx-1.19.2/auto/lib/zlib/conf + nginx-1.19.2/auto/lib/zlib/make + nginx-1.19.2/auto/lib/zlib/makefile.bcc + nginx-1.19.2/auto/lib/zlib/makefile.msvc + nginx-1.19.2/auto/lib/zlib/makefile.owc + nginx-1.19.2/auto/lib/conf + nginx-1.19.2/auto/lib/make + nginx-1.19.2/auto/os/conf + nginx-1.19.2/auto/os/darwin + nginx-1.19.2/auto/os/freebsd + nginx-1.19.2/auto/os/linux + nginx-1.19.2/auto/os/solaris + nginx-1.19.2/auto/os/win32 + nginx-1.19.2/auto/types/sizeof + nginx-1.19.2/auto/types/typedef + nginx-1.19.2/auto/types/uintptr_t + nginx-1.19.2/auto/types/value + nginx-1.19.2/auto/define + nginx-1.19.2/auto/endianness + nginx-1.19.2/auto/feature + nginx-1.19.2/auto/have + nginx-1.19.2/auto/have_headers + nginx-1.19.2/auto/headers + nginx-1.19.2/auto/include + nginx-1.19.2/auto/init + nginx-1.19.2/auto/install + nginx-1.19.2/auto/make + nginx-1.19.2/auto/module + nginx-1.19.2/auto/modules + nginx-1.19.2/auto/nohave + nginx-1.19.2/auto/options + nginx-1.19.2/auto/sources + nginx-1.19.2/auto/stubs + nginx-1.19.2/auto/summary + nginx-1.19.2/auto/threads + nginx-1.19.2/auto/unix + nginx-1.19.2/conf/fastcgi.conf + nginx-1.19.2/conf/fastcgi_params + nginx-1.19.2/conf/koi-utf + nginx-1.19.2/conf/koi-win + nginx-1.19.2/conf/mime.types + nginx-1.19.2/conf/nginx.conf + nginx-1.19.2/conf/scgi_params + nginx-1.19.2/conf/uwsgi_params + nginx-1.19.2/conf/win-utf + nginx-1.19.2/contrib/unicode2nginx/koi-utf + nginx-1.19.2/contrib/unicode2nginx/unicode-to-nginx.pl + nginx-1.19.2/contrib/unicode2nginx/win-utf + nginx-1.19.2/contrib/vim/ftdetect/nginx.vim + nginx-1.19.2/contrib/vim/ftplugin/nginx.vim + nginx-1.19.2/contrib/vim/indent/nginx.vim + nginx-1.19.2/contrib/vim/syntax/nginx.vim + nginx-1.19.2/contrib/geo2nginx.pl + nginx-1.19.2/contrib/README + nginx-1.19.2/html/50x.html + nginx-1.19.2/html/index.html + nginx-1.19.2/man/nginx.8 + nginx-1.19.2/objs/autoconf.err + nginx-1.19.2/objs/Makefile + nginx-1.19.2/objs/nginx + nginx-1.19.2/objs/nginx.8 + nginx-1.19.2/objs/ngx_auto_config.h + nginx-1.19.2/objs/ngx_auto_headers.h + nginx-1.19.2/objs/ngx_http_bot_protection_module.so + nginx-1.19.2/objs/ngx_http_bot_protection_module_modules.c + nginx-1.19.2/objs/ngx_http_header_inspect_module.so + nginx-1.19.2/objs/ngx_http_header_inspect_module_modules.c + nginx-1.19.2/objs/ngx_http_replace_filter_module.so + nginx-1.19.2/objs/ngx_http_replace_filter_module_modules.c + nginx-1.19.2/objs/ngx_modules.c + nginx-1.19.2/src/core/nginx.c + nginx-1.19.2/src/core/nginx.h + nginx-1.19.2/src/core/ngx_array.c + nginx-1.19.2/src/core/ngx_array.h + nginx-1.19.2/src/core/ngx_buf.c + nginx-1.19.2/src/core/ngx_buf.h + nginx-1.19.2/src/core/ngx_conf_file.c + nginx-1.19.2/src/core/ngx_conf_file.h + nginx-1.19.2/src/core/ngx_config.h + nginx-1.19.2/src/core/ngx_connection.c + nginx-1.19.2/src/core/ngx_connection.h + nginx-1.19.2/src/core/ngx_core.h + nginx-1.19.2/src/core/ngx_cpuinfo.c + nginx-1.19.2/src/core/ngx_crc.h + nginx-1.19.2/src/core/ngx_crc32.c + nginx-1.19.2/src/core/ngx_crc32.h + nginx-1.19.2/src/core/ngx_crypt.c + nginx-1.19.2/src/core/ngx_crypt.h + nginx-1.19.2/src/core/ngx_cycle.c + nginx-1.19.2/src/core/ngx_cycle.h + nginx-1.19.2/src/core/ngx_file.c + nginx-1.19.2/src/core/ngx_file.h + nginx-1.19.2/src/core/ngx_hash.c + nginx-1.19.2/src/core/ngx_hash.h + nginx-1.19.2/src/core/ngx_inet.c + nginx-1.19.2/src/core/ngx_inet.h + nginx-1.19.2/src/core/ngx_list.c + nginx-1.19.2/src/core/ngx_list.h + nginx-1.19.2/src/core/ngx_log.c + nginx-1.19.2/src/core/ngx_log.h + nginx-1.19.2/src/core/ngx_md5.c + nginx-1.19.2/src/core/ngx_md5.h + nginx-1.19.2/src/core/ngx_module.c + nginx-1.19.2/src/core/ngx_module.h + nginx-1.19.2/src/core/ngx_murmurhash.c + nginx-1.19.2/src/core/ngx_murmurhash.h + nginx-1.19.2/src/core/ngx_open_file_cache.c + nginx-1.19.2/src/core/ngx_open_file_cache.h + nginx-1.19.2/src/core/ngx_output_chain.c + nginx-1.19.2/src/core/ngx_palloc.c + nginx-1.19.2/src/core/ngx_palloc.h + nginx-1.19.2/src/core/ngx_parse.c + nginx-1.19.2/src/core/ngx_parse.h + nginx-1.19.2/src/core/ngx_parse_time.c + nginx-1.19.2/src/core/ngx_parse_time.h + nginx-1.19.2/src/core/ngx_proxy_protocol.c + nginx-1.19.2/src/core/ngx_proxy_protocol.h + nginx-1.19.2/src/core/ngx_queue.c + nginx-1.19.2/src/core/ngx_queue.h + nginx-1.19.2/src/core/ngx_radix_tree.c + nginx-1.19.2/src/core/ngx_radix_tree.h + nginx-1.19.2/src/core/ngx_rbtree.c + nginx-1.19.2/src/core/ngx_rbtree.h + nginx-1.19.2/src/core/ngx_regex.c + nginx-1.19.2/src/core/ngx_regex.h + nginx-1.19.2/src/core/ngx_resolver.c + nginx-1.19.2/src/core/ngx_resolver.h + nginx-1.19.2/src/core/ngx_rwlock.c + nginx-1.19.2/src/core/ngx_rwlock.h + nginx-1.19.2/src/core/ngx_sha1.c + nginx-1.19.2/src/core/ngx_sha1.h + nginx-1.19.2/src/core/ngx_shmtx.c + nginx-1.19.2/src/core/ngx_shmtx.h + nginx-1.19.2/src/core/ngx_slab.c + nginx-1.19.2/src/core/ngx_slab.h + nginx-1.19.2/src/core/ngx_spinlock.c + nginx-1.19.2/src/core/ngx_string.c + nginx-1.19.2/src/core/ngx_string.h + nginx-1.19.2/src/core/ngx_syslog.c + nginx-1.19.2/src/core/ngx_syslog.h + nginx-1.19.2/src/core/ngx_thread_pool.c + nginx-1.19.2/src/core/ngx_thread_pool.h + nginx-1.19.2/src/core/ngx_times.c + nginx-1.19.2/src/core/ngx_times.h + nginx-1.19.2/src/event/modules/ngx_devpoll_module.c + nginx-1.19.2/src/event/modules/ngx_epoll_module.c + nginx-1.19.2/src/event/modules/ngx_eventport_module.c + nginx-1.19.2/src/event/modules/ngx_kqueue_module.c + nginx-1.19.2/src/event/modules/ngx_poll_module.c + nginx-1.19.2/src/event/modules/ngx_select_module.c + nginx-1.19.2/src/event/modules/ngx_win32_poll_module.c + nginx-1.19.2/src/event/modules/ngx_win32_select_module.c + nginx-1.19.2/src/event/ngx_event.c + nginx-1.19.2/src/event/ngx_event.h + nginx-1.19.2/src/event/ngx_event_accept.c + nginx-1.19.2/src/event/ngx_event_connect.c + nginx-1.19.2/src/event/ngx_event_connect.h + nginx-1.19.2/src/event/ngx_event_openssl.c + nginx-1.19.2/src/event/ngx_event_openssl.h + nginx-1.19.2/src/event/ngx_event_openssl_stapling.c + nginx-1.19.2/src/event/ngx_event_pipe.c + nginx-1.19.2/src/event/ngx_event_pipe.h + nginx-1.19.2/src/event/ngx_event_posted.c + nginx-1.19.2/src/event/ngx_event_posted.h + nginx-1.19.2/src/event/ngx_event_timer.c + nginx-1.19.2/src/event/ngx_event_timer.h + nginx-1.19.2/src/event/ngx_event_udp.c + nginx-1.19.2/src/http/modules/perl/Makefile.PL + nginx-1.19.2/src/http/modules/perl/nginx.pm + nginx-1.19.2/src/http/modules/perl/nginx.xs + nginx-1.19.2/src/http/modules/perl/ngx_http_perl_module.c + nginx-1.19.2/src/http/modules/perl/ngx_http_perl_module.h + nginx-1.19.2/src/http/modules/perl/typemap + nginx-1.19.2/src/http/modules/ngx_http_access_module.c + nginx-1.19.2/src/http/modules/ngx_http_addition_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_auth_basic_module.c + nginx-1.19.2/src/http/modules/ngx_http_auth_request_module.c + nginx-1.19.2/src/http/modules/ngx_http_autoindex_module.c + nginx-1.19.2/src/http/modules/ngx_http_browser_module.c + nginx-1.19.2/src/http/modules/ngx_http_charset_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_chunked_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_dav_module.c + nginx-1.19.2/src/http/modules/ngx_http_degradation_module.c + nginx-1.19.2/src/http/modules/ngx_http_empty_gif_module.c + nginx-1.19.2/src/http/modules/ngx_http_fastcgi_module.c + nginx-1.19.2/src/http/modules/ngx_http_flv_module.c + nginx-1.19.2/src/http/modules/ngx_http_geo_module.c + nginx-1.19.2/src/http/modules/ngx_http_geoip_module.c + nginx-1.19.2/src/http/modules/ngx_http_grpc_module.c + nginx-1.19.2/src/http/modules/ngx_http_gunzip_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_gzip_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_gzip_static_module.c + nginx-1.19.2/src/http/modules/ngx_http_headers_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_image_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_index_module.c + nginx-1.19.2/src/http/modules/ngx_http_limit_conn_module.c + nginx-1.19.2/src/http/modules/ngx_http_limit_req_module.c + nginx-1.19.2/src/http/modules/ngx_http_log_module.c + nginx-1.19.2/src/http/modules/ngx_http_map_module.c + nginx-1.19.2/src/http/modules/ngx_http_memcached_module.c + nginx-1.19.2/src/http/modules/ngx_http_mirror_module.c + nginx-1.19.2/src/http/modules/ngx_http_mp4_module.c + nginx-1.19.2/src/http/modules/ngx_http_not_modified_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_proxy_module.c + nginx-1.19.2/src/http/modules/ngx_http_random_index_module.c + nginx-1.19.2/src/http/modules/ngx_http_range_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_realip_module.c + nginx-1.19.2/src/http/modules/ngx_http_referer_module.c + nginx-1.19.2/src/http/modules/ngx_http_rewrite_module.c + nginx-1.19.2/src/http/modules/ngx_http_scgi_module.c + nginx-1.19.2/src/http/modules/ngx_http_secure_link_module.c + nginx-1.19.2/src/http/modules/ngx_http_slice_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_split_clients_module.c + nginx-1.19.2/src/http/modules/ngx_http_ssi_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_ssi_filter_module.h + nginx-1.19.2/src/http/modules/ngx_http_ssl_module.c + nginx-1.19.2/src/http/modules/ngx_http_ssl_module.h + nginx-1.19.2/src/http/modules/ngx_http_static_module.c + nginx-1.19.2/src/http/modules/ngx_http_stub_status_module.c + nginx-1.19.2/src/http/modules/ngx_http_sub_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_try_files_module.c + nginx-1.19.2/src/http/modules/ngx_http_upstream_hash_module.c + nginx-1.19.2/src/http/modules/ngx_http_upstream_ip_hash_module.c + nginx-1.19.2/src/http/modules/ngx_http_upstream_keepalive_module.c + nginx-1.19.2/src/http/modules/ngx_http_upstream_least_conn_module.c + nginx-1.19.2/src/http/modules/ngx_http_upstream_random_module.c + nginx-1.19.2/src/http/modules/ngx_http_upstream_zone_module.c + nginx-1.19.2/src/http/modules/ngx_http_userid_filter_module.c + nginx-1.19.2/src/http/modules/ngx_http_uwsgi_module.c + nginx-1.19.2/src/http/modules/ngx_http_xslt_filter_module.c + nginx-1.19.2/src/http/v2/ngx_http_v2.c + nginx-1.19.2/src/http/v2/ngx_http_v2.h + nginx-1.19.2/src/http/v2/ngx_http_v2_encode.c + nginx-1.19.2/src/http/v2/ngx_http_v2_filter_module.c + nginx-1.19.2/src/http/v2/ngx_http_v2_huff_decode.c + nginx-1.19.2/src/http/v2/ngx_http_v2_huff_encode.c + nginx-1.19.2/src/http/v2/ngx_http_v2_module.c + nginx-1.19.2/src/http/v2/ngx_http_v2_module.h + nginx-1.19.2/src/http/v2/ngx_http_v2_table.c + nginx-1.19.2/src/http/ngx_http.c + nginx-1.19.2/src/http/ngx_http.h + nginx-1.19.2/src/http/ngx_http_cache.h + nginx-1.19.2/src/http/ngx_http_config.h + nginx-1.19.2/src/http/ngx_http_copy_filter_module.c + nginx-1.19.2/src/http/ngx_http_core_module.c + nginx-1.19.2/src/http/ngx_http_core_module.h + nginx-1.19.2/src/http/ngx_http_file_cache.c + nginx-1.19.2/src/http/ngx_http_header_filter_module.c + nginx-1.19.2/src/http/ngx_http_parse.c + nginx-1.19.2/src/http/ngx_http_postpone_filter_module.c + nginx-1.19.2/src/http/ngx_http_request.c + nginx-1.19.2/src/http/ngx_http_request.h + nginx-1.19.2/src/http/ngx_http_request_body.c + nginx-1.19.2/src/http/ngx_http_script.c + nginx-1.19.2/src/http/ngx_http_script.h + nginx-1.19.2/src/http/ngx_http_special_response.c + nginx-1.19.2/src/http/ngx_http_upstream.c + nginx-1.19.2/src/http/ngx_http_upstream.h + nginx-1.19.2/src/http/ngx_http_upstream_round_robin.c + nginx-1.19.2/src/http/ngx_http_upstream_round_robin.h + nginx-1.19.2/src/http/ngx_http_variables.c + nginx-1.19.2/src/http/ngx_http_variables.h + nginx-1.19.2/src/http/ngx_http_write_filter_module.c + nginx-1.19.2/src/mail/ngx_mail.c + nginx-1.19.2/src/mail/ngx_mail.h + nginx-1.19.2/src/mail/ngx_mail_auth_http_module.c + nginx-1.19.2/src/mail/ngx_mail_core_module.c + nginx-1.19.2/src/mail/ngx_mail_handler.c + nginx-1.19.2/src/mail/ngx_mail_imap_handler.c + nginx-1.19.2/src/mail/ngx_mail_imap_module.c + nginx-1.19.2/src/mail/ngx_mail_imap_module.h + nginx-1.19.2/src/mail/ngx_mail_parse.c + nginx-1.19.2/src/mail/ngx_mail_pop3_handler.c + nginx-1.19.2/src/mail/ngx_mail_pop3_module.c + nginx-1.19.2/src/mail/ngx_mail_pop3_module.h + nginx-1.19.2/src/mail/ngx_mail_proxy_module.c + nginx-1.19.2/src/mail/ngx_mail_smtp_handler.c + nginx-1.19.2/src/mail/ngx_mail_smtp_module.c + nginx-1.19.2/src/mail/ngx_mail_smtp_module.h + nginx-1.19.2/src/mail/ngx_mail_ssl_module.c + nginx-1.19.2/src/mail/ngx_mail_ssl_module.h + nginx-1.19.2/src/misc/ngx_cpp_test_module.cpp + nginx-1.19.2/src/misc/ngx_google_perftools_module.c + nginx-1.19.2/src/os/unix/ngx_alloc.c + nginx-1.19.2/src/os/unix/ngx_alloc.h + nginx-1.19.2/src/os/unix/ngx_atomic.h + nginx-1.19.2/src/os/unix/ngx_channel.c + nginx-1.19.2/src/os/unix/ngx_channel.h + nginx-1.19.2/src/os/unix/ngx_daemon.c + nginx-1.19.2/src/os/unix/ngx_darwin.h + nginx-1.19.2/src/os/unix/ngx_darwin_config.h + nginx-1.19.2/src/os/unix/ngx_darwin_init.c + nginx-1.19.2/src/os/unix/ngx_darwin_sendfile_chain.c + nginx-1.19.2/src/os/unix/ngx_dlopen.c + nginx-1.19.2/src/os/unix/ngx_dlopen.h + nginx-1.19.2/src/os/unix/ngx_errno.c + nginx-1.19.2/src/os/unix/ngx_errno.h + nginx-1.19.2/src/os/unix/ngx_file_aio_read.c + nginx-1.19.2/src/os/unix/ngx_files.c + nginx-1.19.2/src/os/unix/ngx_files.h + nginx-1.19.2/src/os/unix/ngx_freebsd.h + nginx-1.19.2/src/os/unix/ngx_freebsd_config.h + nginx-1.19.2/src/os/unix/ngx_freebsd_init.c + nginx-1.19.2/src/os/unix/ngx_freebsd_sendfile_chain.c + nginx-1.19.2/src/os/unix/ngx_gcc_atomic_amd64.h + nginx-1.19.2/src/os/unix/ngx_gcc_atomic_ppc.h + nginx-1.19.2/src/os/unix/ngx_gcc_atomic_sparc64.h + nginx-1.19.2/src/os/unix/ngx_gcc_atomic_x86.h + nginx-1.19.2/src/os/unix/ngx_linux.h + nginx-1.19.2/src/os/unix/ngx_linux_aio_read.c + nginx-1.19.2/src/os/unix/ngx_linux_config.h + nginx-1.19.2/src/os/unix/ngx_linux_init.c + nginx-1.19.2/src/os/unix/ngx_linux_sendfile_chain.c + nginx-1.19.2/src/os/unix/ngx_os.h + nginx-1.19.2/src/os/unix/ngx_posix_config.h + nginx-1.19.2/src/os/unix/ngx_posix_init.c + nginx-1.19.2/src/os/unix/ngx_process.c + nginx-1.19.2/src/os/unix/ngx_process.h + nginx-1.19.2/src/os/unix/ngx_process_cycle.c + nginx-1.19.2/src/os/unix/ngx_process_cycle.h + nginx-1.19.2/src/os/unix/ngx_readv_chain.c + nginx-1.19.2/src/os/unix/ngx_recv.c + nginx-1.19.2/src/os/unix/ngx_send.c + nginx-1.19.2/src/os/unix/ngx_setaffinity.c + nginx-1.19.2/src/os/unix/ngx_setaffinity.h + nginx-1.19.2/src/os/unix/ngx_setproctitle.c + nginx-1.19.2/src/os/unix/ngx_setproctitle.h + nginx-1.19.2/src/os/unix/ngx_shmem.c + nginx-1.19.2/src/os/unix/ngx_shmem.h + nginx-1.19.2/src/os/unix/ngx_socket.c + nginx-1.19.2/src/os/unix/ngx_socket.h + nginx-1.19.2/src/os/unix/ngx_solaris.h + nginx-1.19.2/src/os/unix/ngx_solaris_config.h + nginx-1.19.2/src/os/unix/ngx_solaris_init.c + nginx-1.19.2/src/os/unix/ngx_solaris_sendfilev_chain.c + nginx-1.19.2/src/os/unix/ngx_sunpro_amd64.il + nginx-1.19.2/src/os/unix/ngx_sunpro_atomic_sparc64.h + nginx-1.19.2/src/os/unix/ngx_sunpro_sparc64.il + nginx-1.19.2/src/os/unix/ngx_sunpro_x86.il + nginx-1.19.2/src/os/unix/ngx_thread.h + nginx-1.19.2/src/os/unix/ngx_thread_cond.c + nginx-1.19.2/src/os/unix/ngx_thread_id.c + nginx-1.19.2/src/os/unix/ngx_thread_mutex.c + nginx-1.19.2/src/os/unix/ngx_time.c + nginx-1.19.2/src/os/unix/ngx_time.h + nginx-1.19.2/src/os/unix/ngx_udp_recv.c + nginx-1.19.2/src/os/unix/ngx_udp_send.c + nginx-1.19.2/src/os/unix/ngx_udp_sendmsg_chain.c + nginx-1.19.2/src/os/unix/ngx_user.c + nginx-1.19.2/src/os/unix/ngx_user.h + nginx-1.19.2/src/os/unix/ngx_writev_chain.c + nginx-1.19.2/src/stream/ngx_stream.c + nginx-1.19.2/src/stream/ngx_stream.h + nginx-1.19.2/src/stream/ngx_stream_access_module.c + nginx-1.19.2/src/stream/ngx_stream_core_module.c + nginx-1.19.2/src/stream/ngx_stream_geo_module.c + nginx-1.19.2/src/stream/ngx_stream_geoip_module.c + nginx-1.19.2/src/stream/ngx_stream_handler.c + nginx-1.19.2/src/stream/ngx_stream_limit_conn_module.c + nginx-1.19.2/src/stream/ngx_stream_log_module.c + nginx-1.19.2/src/stream/ngx_stream_map_module.c + nginx-1.19.2/src/stream/ngx_stream_proxy_module.c + nginx-1.19.2/src/stream/ngx_stream_realip_module.c + nginx-1.19.2/src/stream/ngx_stream_return_module.c + nginx-1.19.2/src/stream/ngx_stream_script.c + nginx-1.19.2/src/stream/ngx_stream_script.h + nginx-1.19.2/src/stream/ngx_stream_split_clients_module.c + nginx-1.19.2/src/stream/ngx_stream_ssl_module.c + nginx-1.19.2/src/stream/ngx_stream_ssl_module.h + nginx-1.19.2/src/stream/ngx_stream_ssl_preread_module.c + nginx-1.19.2/src/stream/ngx_stream_upstream.c + nginx-1.19.2/src/stream/ngx_stream_upstream.h + nginx-1.19.2/src/stream/ngx_stream_upstream_hash_module.c + nginx-1.19.2/src/stream/ngx_stream_upstream_least_conn_module.c + nginx-1.19.2/src/stream/ngx_stream_upstream_random_module.c + nginx-1.19.2/src/stream/ngx_stream_upstream_round_robin.c + nginx-1.19.2/src/stream/ngx_stream_upstream_round_robin.h + nginx-1.19.2/src/stream/ngx_stream_upstream_zone_module.c + nginx-1.19.2/src/stream/ngx_stream_variables.c + nginx-1.19.2/src/stream/ngx_stream_variables.h + nginx-1.19.2/src/stream/ngx_stream_write_filter_module.c + nginx-1.19.2/CHANGES + nginx-1.19.2/CHANGES.ru + nginx-1.19.2/configure + nginx-1.19.2/LICENSE + nginx-1.19.2/Makefile + nginx-1.19.2/README + html/development/template/fingerPerRequest.js + html/development/template/Iron.js + html/development/template/setcookie.html + html/development/template/setCookieRedefined.html + html/development/template/tmp.html + html/development/template/tmp.js + CMakeLists.txt + install.sh + nginx.patch modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.h) diff --git a/Development b/Development new file mode 100644 index 0000000..40a0498 --- /dev/null +++ b/Development @@ -0,0 +1,5 @@ +todo change default error pages like 403,404, etc. +todo update dashboard and show all suspected, blocked and req statistical information +todo build multi arch/ multi linux distribution package (RPM, DEB) +todo replace module libsregex.so.0 automation +todo rename all javascripts such as cryptojs \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8dbab01 --- /dev/null +++ b/README.md @@ -0,0 +1,128 @@ +![](ironfox.png) + + REAL-TIME BOT PROTECTION CHALLENGE +IronFox +================== + +Sponsored by: ***Safe Instrument*** (https://safeinst.com/) + +IronFox is a real-time and high performance bot protection, that using Nginx as a reverse proxy. +With a stateless approach for request processing, simple architect and anomaly detection it is possible +for IronFox to handle millions session/second in distributed mode with zero latency. + +- Core + - [x] Anomaly Detection + - [x] server side analyzing + - [x] client side browser fingerprinting + - [ ] AI based protection + - [ ] detection based on Neutral Networks + - [ ] enhancement and detection score based on Fuzzy Logic +- Management + - [x] basic web dashboard + - [ ] enhancement +- Documents + - [x] Wiki + + +release: 0.1.0 + +### Setup and configuration + + the latest version of IronFox has been successfully tested on Ubuntu Server 20.04.3 LTS + +run ./install.sh with root privilege, the install process automatically download and install all dependencies and services in your machine + +### Introduction + +With technology development and complexity of cyberattack strategies, the traditional technologies and current security methods are not able to perform all lines of +defence in preventing cyberattacks. +The first-generation firewalls and intrusion detection systems (IDS) used to meet the security requirements of all kinds of businesses. +The second generation of security products and solutions including Web Application Firewalls (WAF) also have played an acceptable role in cyberspace for a while. + +Securing e-commerce, web applications and mobile applications are crucial and even though the second and third generation of security techniques (IDS, IDP, NGF) have +been developed, bot and botnet attacks such as Denial of Service (DoS) attacks and Distributed Denial of Service (DDoS) attacks are still concerning as challenges in +cyberspace and online businesses security. + +According to published reports, botnet attacks or more generally botnet exploitation have caused irreparable damages for e-commerce and information exchange spaces. +The new generation of bots is intelligent attacks which their detection and identification are of great importance and complication. +Various solutions and articles have been proposed and published to confront bots and botnets. For instance, tracking the master (source of attacks) +and deactivating the slaves (bots) are two proposed methodologies when tackling DoS and DDoS attacks. + +Nonetheless, these methods are laborious or in most cases almost +impossible to perform.IronFox is a high-performance bot protection with sagacity in identifying and blocking the bots existing in layers of web applications (7th layer), +and capability of using new approaches to employ operational services and executive environments in an in-line form. This article is going to have a look at the content of bots, +their structure and attack and introduce the suggested solutions to oppose them. + +### What Is a Bot? +A bot is a software application that is designed to fulfil various purposes and perform different tasks. For example, crawler ( as a bots) help search engines to +browse the web and index information from websites. Bots can be both legitimate, such as search engines crawler (e.g., Google), and malicious, like the crawlers +which exploit broken authentication or access control of a weak web application or an online service. +These malicious crawlers steal data from the server and make +server source and services inaccessible by generating web traffic and putting pressure on the server. They also have many other nefarious capabilities, such as +automatic testing and exploiting one vulnerability for a thousand destinations. + +Depending on its goal, a bot’s structure could be simple or complicated and intelligent. +Currently, business development has left no choice but to accept bot prevalence and to find solutions for their recognition and classification. For example, search engine +crawlers cannot be excluded from indexing websites, using techniques such as Captcha. On the other hand, permitting destructive bots to remain active may lead to a severe +decline in the quality of online services and possibly render those services inaccessible for users. Therefore, to prevent and block corrupt attacks, solutions must be +proposed to recognize and segregate harmless and malicious bots. + +### Bots and Botnet Attacks +Bots run and execute large-scale attacks, such as: + + 1- Scanning vulnerability and performing malicious codes to exploit vulnerable services (e.g., WordPress vulnerable module). + 2- Crawling and theft of data: bots automatically crawl and steal data much faster than a human user. + 3- Generating demands and launching Denial of Service (DoS) attacks: by performing DoS and Distributed Denial of Service (DDoS) attacks, botnets can waste a server’s resources, services and make them unreachable for users. For instance, making traffic or fake requests by bots can easily slow the process down in trading systems, which depend greatly on time, until they become completely unavailable for the legitimate human users. + 4- Cheating: for example, in online polls, or similar systems, bots can act as a genuine user and automatically go through the entire process, from registration to voting. To design and develop such bots, having access to libraries or frameworks - such as Selenium – and writing a few lines of codes would be adequate. + 5- Identity theft and faking: bots can simply operate as a real person and create fake identities. + 6- Performing repetitive patterns: bots can be automated to run repetitive scripts continuously. They can easily abuse the API used by a standard mobile application. + 7- and sort of attacks are considerible. +Beyond this list, there are many other operations that bots can execute. + +### Structure of Bots +In general, (Application Layer) bots can be divided into four groups: + + * First-generation bots: these bots have fairly easy structures and they can run simple automatic patterns. They don’t have any understanding of the web’s basic contents like Cookies and Sessions and they are not difficult to detect and block. A simple script which calls the web content or an API with the GET/ POST method could be referred to as a first-generation bot. + * Second-generation bots: their structure is like the bots from the first generation but slightly more developed. They are not capable of rendering or running javascript codes and a stack of them is not like a complete browser. To distinguish and block the bots from the second generation, javascript tests, such as setting cookies, are sufficient. Tools like Scrapy are an example of second-generation bots. + * Third-generation bots: these kinds are comparatively more challenging to prevent against. They, like bots developed in PhantomJs and Selenium frameworks, can perform the demands step by step and execute challenges which are used to tackle the bots from the first and second generations. However, they have a slower run-time compared to the first and second-generation bots. Recognizing and blocking the third-generation bots could be achieved by executing challenging tests like Captcha. + * Fourth-generation bots: these bots can mimic the actions of a genuine browser. Examples of this generation of bots are Headless browser (such as headless Chromium), and to confront them using complex techniques based on artificial intelligence would be effective. + +### Bot Challenges and Their Current Confrontation Methods + +Without a doubt, firewalls and intrusion detection systems are known as some of the most important components in terms of defending and blocking cyberattacks. +The aforementioned systems monitor attacks based on their patterns and the behaviour of their demands. Therefore, they don’t have an actual understanding of the +sources of attacks and can’t distinguish whether the demand is made by a real user or a robot. In some cases, examination and recognition of bots by these systems +is successful. Nevertheless, they are not able to find the source of demands and block the attacks when facing bots from the third and fourth generations because +these bots can find a way around these systems. +In security architecture, finding, identifying and blocking the bots existing in 7th layer once posing in the network topology, are steps before the layer of security +tools such as web application firewalls (e.g., WAF) or servers/online services and after network equipment presented in 3/4th layer. In such architecture only requests +from authentic users will be sent to the next services and layers and the requests made by bots will be monitored and completely blocked. +Bot attacks and their distributed form have the capacity of taking the security appliances, like web application firewalls and attack detections, out of the orbit. + +Moreover, they can cause race condition or an extreme QoS deduction in the above-mentioned system's functionality by creating numerous requests. It is necessary to trace +and distinguish the requests from actual users and traffics and only the ones from users must be sent to the next layers and process chain. +IronFox is a bot identification and blocking system with high processability which is capable of agent-less identification the source of requests and dividing them into +the ones sent from legitimate users and the ones from robots. + +Also, it only sends the user’s requests towards the 7th layer security equipment and Back-End services.The notable point is that the mission of the 7th layer security +techniques is not different from IronFox system. However, the aforementioned techniques are not able to confront complex bot attacks, analyse the source of the attack +and the requests. + +Moreover, security equipment could have a severe decline in performance or could get bypassed or false positive. + + +### Commercial and Open-Source Solutions + +DataDome is one of the contenders and pioneers of technology companies in France which works in the field of bot detection and blocking. This company recommends +intelligence-based methods and offers bot protection services. Other well-known companies such as Cloudflare and Imperva are also offering services like CDN and +e-commerce protection. Besides, F5 products provide the required modules for bot recognition and confrontation and protection of the server’s API. +Cookie-test which has been designed and developed as a practical module for Nginx is an open-source solution. It evaluates and blocks invalid requests by creating +JavaScript challenge and setting Cookies on the user's browser. + +These methods are very easy to be dumped by the first-generation bots. By dumping the first request +headers (only once), decoding and setting Cookies, the attacker can resend the same number of requests towards the server (e.g., CSRF attacks including initialized +request headers and Cookie’s information). Since the valid information is sent to the server next time, such techniques can be easily bypassed. +To recognize and reject the malicious bots, security systems are employing techniques such as inspecting the agent, IP address or database of attacks pattern. +These strategies can be dumped effortlessly and have no complexity for attackers. +IronFox using sort of techniques with minimal latency for bot detections for real word and online business protections, based on server side analysing and client +side fingerprinting. diff --git a/cert/nginx-selfsigned.crt b/cert/nginx-selfsigned.crt new file mode 100644 index 0000000..7790276 --- /dev/null +++ b/cert/nginx-selfsigned.crt @@ -0,0 +1,24 @@ +-----BEGIN CERTIFICATE----- +MIID9TCCAt2gAwIBAgIUez3lAn0OJYYcRN9jOEJln0g9zRQwDQYJKoZIhvcNAQEL +BQAwgYkxCzAJBgNVBAYTAklSMQ8wDQYDVQQIDAZURUhSQU4xDzANBgNVBAcMBlRF +SFJBTjERMA8GA1UECgwISW5ub3ZlcmExCzAJBgNVBAsMAlJEMRAwDgYDVQQDDAdJ +cm9uRm94MSYwJAYJKoZIhvcNAQkBFhdraGFsZWdoc2FsZWhpQGdtYWlsLmNvbTAe +Fw0yMTExMTMxNzMwNDBaFw0zMTA5MjIxNzMwNDBaMIGJMQswCQYDVQQGEwJJUjEP +MA0GA1UECAwGVEVIUkFOMQ8wDQYDVQQHDAZURUhSQU4xETAPBgNVBAoMCElubm92 +ZXJhMQswCQYDVQQLDAJSRDEQMA4GA1UEAwwHSXJvbkZveDEmMCQGCSqGSIb3DQEJ +ARYXa2hhbGVnaHNhbGVoaUBnbWFpbC5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IB +DwAwggEKAoIBAQDKvzMfhj6rGdfFbxtzGMsKjl1FmzwT1wAqksuClxn/yABpAWyt +TuxzN4wtVQaUBixhwSV/LOHnb9KfetOrQgn9aKJ1Cavq1+7PIxVSYy2t1dwAEdNs +YsSh/UXuTrcjajGUE3MMSUq4OMVWQ1BpBNw2ylMufsYzNw0e7XP6AqPkKdmXNFfd +mobfWdaVY+DMqGmzPWQ3Be2fuAMg0Og0fxoFOeOfZIE7DYfka1SPw4T7Vr6yHc64 +NM640NwfzIDaPJ8hNVdUeo3qBcaBOk0qKX9HpTTBgyONPhOxx6BiEQkxTdtG9gXZ +52Eaj4BDpDQdcF5/+r2dVy2oCWFMogZoaWmXAgMBAAGjUzBRMB0GA1UdDgQWBBTn +586lUDH7eAxbfhACW2j5DO7bgDAfBgNVHSMEGDAWgBTn586lUDH7eAxbfhACW2j5 +DO7bgDAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQDAw12M6Hbu +0Ty/NU7nw9Ehd4ItJbC7igZdOoEBGlvnmk9i2HigbHCm+l3FIqFzgDmTlCDrCC2n +aE6cknYln8osjsBSwYsD4fRKxmnLTozfzH/jNTKmRXLyV9lcT6MS7TwDAxNnfGS9 +ikq+UxQ+3fvR7QdtH1Qnjfj0MkEiknK22RkkcHnH32WHJ1IxzQeeArpGR/I5q9y2 +qJ8K46xp62/Ze8R3S/ReTRdt9qwohs3goBbDVuM8rY9gAwpgzbDUmJlU4mYUobx/ +PoBoBLGAloB1iXDDxRieqLvUh3vZzwGqkzggH7aPMzX/WiLcVgTYv0S+t0f/ioGR +MIkJn4l4QXcZ +-----END CERTIFICATE----- \ No newline at end of file diff --git a/cert/nginx-selfsigned.key b/cert/nginx-selfsigned.key new file mode 100644 index 0000000..224651d --- /dev/null +++ b/cert/nginx-selfsigned.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDKvzMfhj6rGdfF +bxtzGMsKjl1FmzwT1wAqksuClxn/yABpAWytTuxzN4wtVQaUBixhwSV/LOHnb9Kf +etOrQgn9aKJ1Cavq1+7PIxVSYy2t1dwAEdNsYsSh/UXuTrcjajGUE3MMSUq4OMVW +Q1BpBNw2ylMufsYzNw0e7XP6AqPkKdmXNFfdmobfWdaVY+DMqGmzPWQ3Be2fuAMg +0Og0fxoFOeOfZIE7DYfka1SPw4T7Vr6yHc64NM640NwfzIDaPJ8hNVdUeo3qBcaB +Ok0qKX9HpTTBgyONPhOxx6BiEQkxTdtG9gXZ52Eaj4BDpDQdcF5/+r2dVy2oCWFM +ogZoaWmXAgMBAAECggEAE9LuJL7zkbdNKbjbbj2WXMnexNeQ4D+9fGwuCe7MU/4y +TBIfljKJXBqqUiRmKEMSQ9ym1fCFhiOg7IcN+0jRwT1h5R+095l1eDtt8khQRxcK +E9eqXIarw0sIc2yu63+OqXPdY+4mqCyk3vJmAl6/SXwu9fTfXFKdrdB57pAjhkOE +vOGOLmFJzcjcp8fRt7JoLZumhLzL9e4rQcxhS5WAGssFeTuOfL9/9ahxJ/pQJvvc +HKLj3/AnBbweDghvswxFImTOmUUiBUp6KAOBLjLQNl8ic2adLNk3nNVfAmllmY8I +s/wkzIZBt0D7XlXZAZ06LpfqtRibg6JjtpbYtdP+QQKBgQDmhUw5Yz45nejSLGS2 +K8osyojx9zZf28vyg3S1S6kfYEZj4tu0oiFLFTVHFu8QjOngwv06jX8iMfvFk+4S +Ff5SnrUJv68zaOULm6qGQE2GvXoKLUxaqT1J78WqYjy9ZMXraEGlW6i4f1ECuwVs +ot/wf6nb4N9X5nKC+tBbpAU1WwKBgQDhKAb/erOLnWFCYxCvSCyLh7aExUV1XeJt +8HiFDFwQXY4syjxtBk58hgGvfh/gFbxS41eHluSyXSisCJLHKB6msMQEygTACmBa +RyIbOFJJWe9eQMF35LTdVNMlTxLv9J2UV/WLSvySVXaionWTuZiWcBefDxy5dj9S +70egrDvFdQKBgAfCaORtoMSTuiiI8gLnynBjiOSMK7piTaUmI6GOoGy78uKd2kNk +SbabSiXQcc+ezqiQJ7H23VarVAw8hID7WIozaWigmScj2sHfRYgrVfC5JAh/qdhL +ZhK9DWxEzkKZx8e6xKrqQO2k63cqEG6ttNgFlBQgp6Pvz970zlqnVL2NAoGBAK20 +lNmLT3OaAowWI6wnMX6gQDbkfvbSbLtGt6Rl6a0SkHqLt9yg7fJx7GD5HBxkiHsm +O8Q2rM/SwWsf3iVaFXOikkfjl5CVMMrVcEGxzQIcKWj86oXV45eSNqfk/oYzoVLu +HVjOjFdVKgbE8ZL7r/X4GrEzFoUa7jXMtuUFm8N1AoGAZ59hPdHRU6PBvI6HXBH9 +3jJWVmau9Fy5aOkDwunp1KInByj2aEZ99AdLzjYM8XSzvumAg/uIEwdL5UtNrh9m +HbgNHUnpNIFQXHmGu4/im2YqnjAQMTmuRLPPRv5Z0QCcN57ChOX3cj6MkUPKuAf0 +4R+z09xy83iKSxtZEyi4ZOI= +-----END PRIVATE KEY----- \ No newline at end of file diff --git a/document/persian/innovera.pdf b/document/persian/innovera.pdf new file mode 100644 index 0000000..95a8dd9 Binary files /dev/null and b/document/persian/innovera.pdf differ diff --git a/document/persian/ironfox.pdf b/document/persian/ironfox.pdf new file mode 100644 index 0000000..c7eab51 Binary files /dev/null and b/document/persian/ironfox.pdf differ diff --git a/document/persian/ironfox_v0.0.9.pdf b/document/persian/ironfox_v0.0.9.pdf new file mode 100644 index 0000000..6bf2b9a Binary files /dev/null and b/document/persian/ironfox_v0.0.9.pdf differ diff --git a/html/development/40x.html b/html/development/40x.html new file mode 100644 index 0000000..d5aa1eb --- /dev/null +++ b/html/development/40x.html @@ -0,0 +1,17 @@ + + + +Error + + + +

Access Denied!

+

40x Error. custome message here

+ + diff --git a/html/development/50x.html b/html/development/50x.html new file mode 100644 index 0000000..7fe480b --- /dev/null +++ b/html/development/50x.html @@ -0,0 +1,18 @@ + + + + Error + + + +

Access Denied!

+

50x Error. custome message here

+ + +_modu \ No newline at end of file diff --git a/html/development/bot.html b/html/development/bot.html new file mode 100644 index 0000000..b123f6e --- /dev/null +++ b/html/development/bot.html @@ -0,0 +1,17 @@ + + + +Error + + + +

Access Denied!

+

Please surfing the pages with politeness.

+ + diff --git a/html/development/cryptojs.js b/html/development/cryptojs.js new file mode 100644 index 0000000..827503c --- /dev/null +++ b/html/development/cryptojs.js @@ -0,0 +1,35 @@ +/* +CryptoJS v3.1.2 +code.google.com/p/crypto-js +(c) 2009-2013 by Jeff Mott. All rights reserved. +code.google.com/p/crypto-js/wiki/License +*/ +var CryptoJS=CryptoJS||function(u,p){var d={},l=d.lib={},s=function(){},t=l.Base={extend:function(a){s.prototype=this;var c=new s;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, +r=l.WordArray=t.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=p?c:4*a.length},toString:function(a){return(a||v).stringify(this)},concat:function(a){var c=this.words,e=a.words,j=this.sigBytes;a=a.sigBytes;this.clamp();if(j%4)for(var k=0;k>>2]|=(e[k>>>2]>>>24-8*(k%4)&255)<<24-8*((j+k)%4);else if(65535>>2]=e[k>>>2];else c.push.apply(c,e);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< +32-8*(c%4);a.length=u.ceil(c/4)},clone:function(){var a=t.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],e=0;e>>2]>>>24-8*(j%4)&255;e.push((k>>>4).toString(16));e.push((k&15).toString(16))}return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j>>3]|=parseInt(a.substr(j, +2),16)<<24-4*(j%8);return new r.init(e,c/2)}},b=w.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var e=[],j=0;j>>2]>>>24-8*(j%4)&255));return e.join("")},parse:function(a){for(var c=a.length,e=[],j=0;j>>2]|=(a.charCodeAt(j)&255)<<24-8*(j%4);return new r.init(e,c)}},x=w.Utf8={stringify:function(a){try{return decodeURIComponent(escape(b.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return b.parse(unescape(encodeURIComponent(a)))}}, +q=l.BufferedBlockAlgorithm=t.extend({reset:function(){this._data=new r.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=x.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,e=c.words,j=c.sigBytes,k=this.blockSize,b=j/(4*k),b=a?u.ceil(b):u.max((b|0)-this._minBufferSize,0);a=b*k;j=u.min(4*a,j);if(a){for(var q=0;q>>2]>>>24-8*(r%4)&255)<<16|(l[r+1>>>2]>>>24-8*((r+1)%4)&255)<<8|l[r+2>>>2]>>>24-8*((r+2)%4)&255,v=0;4>v&&r+0.75*v>>6*(3-v)&63));if(l=t.charAt(64))for(;d.length%4;)d.push(l);return d.join("")},parse:function(d){var l=d.length,s=this._map,t=s.charAt(64);t&&(t=d.indexOf(t),-1!=t&&(l=t));for(var t=[],r=0,w=0;w< +l;w++)if(w%4){var v=s.indexOf(d.charAt(w-1))<<2*(w%4),b=s.indexOf(d.charAt(w))>>>6-2*(w%4);t[r>>>2]|=(v|b)<<24-8*(r%4);r++}return p.create(t,r)},_map:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="}})(); +(function(u){function p(b,n,a,c,e,j,k){b=b+(n&a|~n&c)+e+k;return(b<>>32-j)+n}function d(b,n,a,c,e,j,k){b=b+(n&c|a&~c)+e+k;return(b<>>32-j)+n}function l(b,n,a,c,e,j,k){b=b+(n^a^c)+e+k;return(b<>>32-j)+n}function s(b,n,a,c,e,j,k){b=b+(a^(n|~c))+e+k;return(b<>>32-j)+n}for(var t=CryptoJS,r=t.lib,w=r.WordArray,v=r.Hasher,r=t.algo,b=[],x=0;64>x;x++)b[x]=4294967296*u.abs(u.sin(x+1))|0;r=r.MD5=v.extend({_doReset:function(){this._hash=new w.init([1732584193,4023233417,2562383102,271733878])}, +_doProcessBlock:function(q,n){for(var a=0;16>a;a++){var c=n+a,e=q[c];q[c]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360}var a=this._hash.words,c=q[n+0],e=q[n+1],j=q[n+2],k=q[n+3],z=q[n+4],r=q[n+5],t=q[n+6],w=q[n+7],v=q[n+8],A=q[n+9],B=q[n+10],C=q[n+11],u=q[n+12],D=q[n+13],E=q[n+14],x=q[n+15],f=a[0],m=a[1],g=a[2],h=a[3],f=p(f,m,g,h,c,7,b[0]),h=p(h,f,m,g,e,12,b[1]),g=p(g,h,f,m,j,17,b[2]),m=p(m,g,h,f,k,22,b[3]),f=p(f,m,g,h,z,7,b[4]),h=p(h,f,m,g,r,12,b[5]),g=p(g,h,f,m,t,17,b[6]),m=p(m,g,h,f,w,22,b[7]), +f=p(f,m,g,h,v,7,b[8]),h=p(h,f,m,g,A,12,b[9]),g=p(g,h,f,m,B,17,b[10]),m=p(m,g,h,f,C,22,b[11]),f=p(f,m,g,h,u,7,b[12]),h=p(h,f,m,g,D,12,b[13]),g=p(g,h,f,m,E,17,b[14]),m=p(m,g,h,f,x,22,b[15]),f=d(f,m,g,h,e,5,b[16]),h=d(h,f,m,g,t,9,b[17]),g=d(g,h,f,m,C,14,b[18]),m=d(m,g,h,f,c,20,b[19]),f=d(f,m,g,h,r,5,b[20]),h=d(h,f,m,g,B,9,b[21]),g=d(g,h,f,m,x,14,b[22]),m=d(m,g,h,f,z,20,b[23]),f=d(f,m,g,h,A,5,b[24]),h=d(h,f,m,g,E,9,b[25]),g=d(g,h,f,m,k,14,b[26]),m=d(m,g,h,f,v,20,b[27]),f=d(f,m,g,h,D,5,b[28]),h=d(h,f, +m,g,j,9,b[29]),g=d(g,h,f,m,w,14,b[30]),m=d(m,g,h,f,u,20,b[31]),f=l(f,m,g,h,r,4,b[32]),h=l(h,f,m,g,v,11,b[33]),g=l(g,h,f,m,C,16,b[34]),m=l(m,g,h,f,E,23,b[35]),f=l(f,m,g,h,e,4,b[36]),h=l(h,f,m,g,z,11,b[37]),g=l(g,h,f,m,w,16,b[38]),m=l(m,g,h,f,B,23,b[39]),f=l(f,m,g,h,D,4,b[40]),h=l(h,f,m,g,c,11,b[41]),g=l(g,h,f,m,k,16,b[42]),m=l(m,g,h,f,t,23,b[43]),f=l(f,m,g,h,A,4,b[44]),h=l(h,f,m,g,u,11,b[45]),g=l(g,h,f,m,x,16,b[46]),m=l(m,g,h,f,j,23,b[47]),f=s(f,m,g,h,c,6,b[48]),h=s(h,f,m,g,w,10,b[49]),g=s(g,h,f,m, +E,15,b[50]),m=s(m,g,h,f,r,21,b[51]),f=s(f,m,g,h,u,6,b[52]),h=s(h,f,m,g,k,10,b[53]),g=s(g,h,f,m,B,15,b[54]),m=s(m,g,h,f,e,21,b[55]),f=s(f,m,g,h,v,6,b[56]),h=s(h,f,m,g,x,10,b[57]),g=s(g,h,f,m,t,15,b[58]),m=s(m,g,h,f,D,21,b[59]),f=s(f,m,g,h,z,6,b[60]),h=s(h,f,m,g,C,10,b[61]),g=s(g,h,f,m,j,15,b[62]),m=s(m,g,h,f,A,21,b[63]);a[0]=a[0]+f|0;a[1]=a[1]+m|0;a[2]=a[2]+g|0;a[3]=a[3]+h|0},_doFinalize:function(){var b=this._data,n=b.words,a=8*this._nDataBytes,c=8*b.sigBytes;n[c>>>5]|=128<<24-c%32;var e=u.floor(a/ +4294967296);n[(c+64>>>9<<4)+15]=(e<<8|e>>>24)&16711935|(e<<24|e>>>8)&4278255360;n[(c+64>>>9<<4)+14]=(a<<8|a>>>24)&16711935|(a<<24|a>>>8)&4278255360;b.sigBytes=4*(n.length+1);this._process();b=this._hash;n=b.words;for(a=0;4>a;a++)c=n[a],n[a]=(c<<8|c>>>24)&16711935|(c<<24|c>>>8)&4278255360;return b},clone:function(){var b=v.clone.call(this);b._hash=this._hash.clone();return b}});t.MD5=v._createHelper(r);t.HmacMD5=v._createHmacHelper(r)})(Math); +(function(){var u=CryptoJS,p=u.lib,d=p.Base,l=p.WordArray,p=u.algo,s=p.EvpKDF=d.extend({cfg:d.extend({keySize:4,hasher:p.MD5,iterations:1}),init:function(d){this.cfg=this.cfg.extend(d)},compute:function(d,r){for(var p=this.cfg,s=p.hasher.create(),b=l.create(),u=b.words,q=p.keySize,p=p.iterations;u.length>>2]&255}};d.BlockCipher=v.extend({cfg:v.cfg.extend({mode:b,padding:q}),reset:function(){v.reset.call(this);var a=this.cfg,b=a.iv,a=a.mode;if(this._xformMode==this._ENC_XFORM_MODE)var c=a.createEncryptor;else c=a.createDecryptor,this._minBufferSize=1;this._mode=c.call(a, +this,b&&b.words)},_doProcessBlock:function(a,b){this._mode.processBlock(a,b)},_doFinalize:function(){var a=this.cfg.padding;if(this._xformMode==this._ENC_XFORM_MODE){a.pad(this._data,this.blockSize);var b=this._process(!0)}else b=this._process(!0),a.unpad(b);return b},blockSize:4});var n=d.CipherParams=l.extend({init:function(a){this.mixIn(a)},toString:function(a){return(a||this.formatter).stringify(this)}}),b=(p.format={}).OpenSSL={stringify:function(a){var b=a.ciphertext;a=a.salt;return(a?s.create([1398893684, +1701076831]).concat(a).concat(b):b).toString(r)},parse:function(a){a=r.parse(a);var b=a.words;if(1398893684==b[0]&&1701076831==b[1]){var c=s.create(b.slice(2,4));b.splice(0,4);a.sigBytes-=16}return n.create({ciphertext:a,salt:c})}},a=d.SerializableCipher=l.extend({cfg:l.extend({format:b}),encrypt:function(a,b,c,d){d=this.cfg.extend(d);var l=a.createEncryptor(c,d);b=l.finalize(b);l=l.cfg;return n.create({ciphertext:b,key:c,iv:l.iv,algorithm:a,mode:l.mode,padding:l.padding,blockSize:a.blockSize,formatter:d.format})}, +decrypt:function(a,b,c,d){d=this.cfg.extend(d);b=this._parse(b,d.format);return a.createDecryptor(c,d).finalize(b.ciphertext)},_parse:function(a,b){return"string"==typeof a?b.parse(a,this):a}}),p=(p.kdf={}).OpenSSL={execute:function(a,b,c,d){d||(d=s.random(8));a=w.create({keySize:b+c}).compute(a,d);c=s.create(a.words.slice(b),4*c);a.sigBytes=4*b;return n.create({key:a,iv:c,salt:d})}},c=d.PasswordBasedCipher=a.extend({cfg:a.cfg.extend({kdf:p}),encrypt:function(b,c,d,l){l=this.cfg.extend(l);d=l.kdf.execute(d, +b.keySize,b.ivSize);l.iv=d.iv;b=a.encrypt.call(this,b,c,d.key,l);b.mixIn(d);return b},decrypt:function(b,c,d,l){l=this.cfg.extend(l);c=this._parse(c,l.format);d=l.kdf.execute(d,b.keySize,b.ivSize,c.salt);l.iv=d.iv;return a.decrypt.call(this,b,c,d.key,l)}})}(); +(function(){for(var u=CryptoJS,p=u.lib.BlockCipher,d=u.algo,l=[],s=[],t=[],r=[],w=[],v=[],b=[],x=[],q=[],n=[],a=[],c=0;256>c;c++)a[c]=128>c?c<<1:c<<1^283;for(var e=0,j=0,c=0;256>c;c++){var k=j^j<<1^j<<2^j<<3^j<<4,k=k>>>8^k&255^99;l[e]=k;s[k]=e;var z=a[e],F=a[z],G=a[F],y=257*a[k]^16843008*k;t[e]=y<<24|y>>>8;r[e]=y<<16|y>>>16;w[e]=y<<8|y>>>24;v[e]=y;y=16843009*G^65537*F^257*z^16843008*e;b[k]=y<<24|y>>>8;x[k]=y<<16|y>>>16;q[k]=y<<8|y>>>24;n[k]=y;e?(e=z^a[a[a[G^z]]],j^=a[a[j]]):e=j=1}var H=[0,1,2,4,8, +16,32,64,128,27,54],d=d.AES=p.extend({_doReset:function(){for(var a=this._key,c=a.words,d=a.sigBytes/4,a=4*((this._nRounds=d+6)+1),e=this._keySchedule=[],j=0;j>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255]):(k=k<<8|k>>>24,k=l[k>>>24]<<24|l[k>>>16&255]<<16|l[k>>>8&255]<<8|l[k&255],k^=H[j/d|0]<<24);e[j]=e[j-d]^k}c=this._invKeySchedule=[];for(d=0;dd||4>=j?k:b[l[k>>>24]]^x[l[k>>>16&255]]^q[l[k>>> +8&255]]^n[l[k&255]]},encryptBlock:function(a,b){this._doCryptBlock(a,b,this._keySchedule,t,r,w,v,l)},decryptBlock:function(a,c){var d=a[c+1];a[c+1]=a[c+3];a[c+3]=d;this._doCryptBlock(a,c,this._invKeySchedule,b,x,q,n,s);d=a[c+1];a[c+1]=a[c+3];a[c+3]=d},_doCryptBlock:function(a,b,c,d,e,j,l,f){for(var m=this._nRounds,g=a[b]^c[0],h=a[b+1]^c[1],k=a[b+2]^c[2],n=a[b+3]^c[3],p=4,r=1;r>>24]^e[h>>>16&255]^j[k>>>8&255]^l[n&255]^c[p++],s=d[h>>>24]^e[k>>>16&255]^j[n>>>8&255]^l[g&255]^c[p++],t= +d[k>>>24]^e[n>>>16&255]^j[g>>>8&255]^l[h&255]^c[p++],n=d[n>>>24]^e[g>>>16&255]^j[h>>>8&255]^l[k&255]^c[p++],g=q,h=s,k=t;q=(f[g>>>24]<<24|f[h>>>16&255]<<16|f[k>>>8&255]<<8|f[n&255])^c[p++];s=(f[h>>>24]<<24|f[k>>>16&255]<<16|f[n>>>8&255]<<8|f[g&255])^c[p++];t=(f[k>>>24]<<24|f[n>>>16&255]<<16|f[g>>>8&255]<<8|f[h&255])^c[p++];n=(f[n>>>24]<<24|f[g>>>16&255]<<16|f[h>>>8&255]<<8|f[k&255])^c[p++];a[b]=q;a[b+1]=s;a[b+2]=t;a[b+3]=n},keySize:8});u.AES=p._createHelper(d)})(); diff --git a/html/development/fingerprint.js b/html/development/fingerprint.js new file mode 100644 index 0000000..bb4ce78 --- /dev/null +++ b/html/development/fingerprint.js @@ -0,0 +1,1407 @@ +(function (name, context, definition) { + 'use strict' + if (typeof window !== 'undefined' && typeof define === 'function' && define.amd) { define(definition) } else if (typeof module !== 'undefined' && module.exports) { module.exports = definition() } else if (context.exports) { context.exports = definition() } else { context[name] = definition() } +})('Fingerprint2', this, function () { + 'use strict' + + /// MurmurHash3 related functions + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // added together as a 64bit int (as an array of two 32bit ints). + // + var x64Add = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] + n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] + n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] + n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += m[0] + n[0] + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // multiplied together as a 64bit int (as an array of two 32bit ints). + // + var x64Multiply = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] * n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] * n[3] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[2] += m[3] * n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] * n[3] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[2] * n[2] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[3] * n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]) + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) rotated left by that number of positions. + // + var x64Rotl = function (m, n) { + n %= 64 + if (n === 32) { + return [m[1], m[0]] + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))] + } else { + n -= 32 + return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))] + } + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) shifted left by that number of positions. + // + var x64LeftShift = function (m, n) { + n %= 64 + if (n === 0) { + return m + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n] + } else { + return [m[1] << (n - 32), 0] + } + } + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // xored together as a 64bit int (as an array of two 32bit ints). + // + var x64Xor = function (m, n) { + return [m[0] ^ n[0], m[1] ^ n[1]] + } + // + // Given a block, returns murmurHash3's final x64 mix of that block. + // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the + // only place where we need to right shift 64bit ints.) + // + var x64Fmix = function (h) { + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xff51afd7, 0xed558ccd]) + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]) + h = x64Xor(h, [0, h[0] >>> 1]) + return h + } + + // + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x64 flavor of MurmurHash3, as an unsigned hex. + // + var x64hash128 = function (key, seed) { + key = key || '' + seed = seed || 0 + var remainder = key.length % 16 + var bytes = key.length - remainder + var h1 = [0, seed] + var h2 = [0, seed] + var k1 = [0, 0] + var k2 = [0, 0] + var c1 = [0x87c37b91, 0x114253d5] + var c2 = [0x4cf5ad43, 0x2745937f] + for (var i = 0; i < bytes; i = i + 16) { + k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)] + k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)] + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + h1 = x64Rotl(h1, 27) + h1 = x64Add(h1, h2) + h1 = x64Add(x64Multiply(h1, [0, 5]), [0, 0x52dce729]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + h2 = x64Rotl(h2, 31) + h2 = x64Add(h2, h1) + h2 = x64Add(x64Multiply(h2, [0, 5]), [0, 0x38495ab5]) + } + k1 = [0, 0] + k2 = [0, 0] + switch (remainder) { + case 15: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 14)], 48)) + // fallthrough + case 14: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 13)], 40)) + // fallthrough + case 13: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 12)], 32)) + // fallthrough + case 12: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 11)], 24)) + // fallthrough + case 11: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 10)], 16)) + // fallthrough + case 10: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 9)], 8)) + // fallthrough + case 9: + k2 = x64Xor(k2, [0, key.charCodeAt(i + 8)]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + // fallthrough + case 8: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 7)], 56)) + // fallthrough + case 7: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 6)], 48)) + // fallthrough + case 6: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 5)], 40)) + // fallthrough + case 5: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 4)], 32)) + // fallthrough + case 4: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 3)], 24)) + // fallthrough + case 3: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 2)], 16)) + // fallthrough + case 2: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 1)], 8)) + // fallthrough + case 1: + k1 = x64Xor(k1, [0, key.charCodeAt(i)]) + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + // fallthrough + } + h1 = x64Xor(h1, [0, key.length]) + h2 = x64Xor(h2, [0, key.length]) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + h1 = x64Fmix(h1) + h2 = x64Fmix(h2) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8) + } + + var defaultOptions = { + preprocessor: null, + audio: { + timeout: 1000, + // On iOS 11, audio context can only be used in response to user interaction. + // We require users to explicitly enable audio fingerprinting on iOS 11. + // See https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + excludeIOS11: true + }, + fonts: { + swfContainerId: 'fingerprintjs2', + swfPath: 'flash/compiled/FontList.swf', + userDefinedFonts: [], + extendedJsFonts: false + }, + screen: { + // To ensure consistent fingerprints when users rotate their mobile devices + detectScreenOrientation: true + }, + plugins: { + sortPluginsFor: [/palemoon/i], + excludeIE: false + }, + extraComponents: [], + excludes: { + // Unreliable on Windows, see https://github.com/Valve/fingerprintjs2/issues/375 + 'enumerateDevices': true, + // devicePixelRatio depends on browser zoom, and it's impossible to detect browser zoom + 'pixelRatio': true, + // DNT depends on incognito mode for some browsers (Chrome) and it's impossible to detect incognito mode + 'doNotTrack': true, + // uses js fonts already + 'fontsFlash': true + }, + NOT_AVAILABLE: 'not available', + ERROR: 'error', + EXCLUDED: 'excluded' + } + + var each = function (obj, iterator) { + if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { + obj.forEach(iterator) + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + iterator(obj[i], i, obj) + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + iterator(obj[key], key, obj) + } + } + } + } + + var map = function (obj, iterator) { + var results = [] + // Not using strict equality so that this acts as a + // shortcut to checking for `null` and `undefined`. + if (obj == null) { + return results + } + if (Array.prototype.map && obj.map === Array.prototype.map) { return obj.map(iterator) } + each(obj, function (value, index, list) { + results.push(iterator(value, index, list)) + }) + return results + } + + var extendSoft = function (target, source) { + if (source == null) { return target } + var value + var key + for (key in source) { + value = source[key] + if (value != null && !(Object.prototype.hasOwnProperty.call(target, key))) { + target[key] = value + } + } + return target + } + + // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices + var enumerateDevicesKey = function (done, options) { + if (!isEnumerateDevicesSupported()) { + return done(options.NOT_AVAILABLE) + } + navigator.mediaDevices.enumerateDevices().then(function (devices) { + done(devices.map(function (device) { + return 'id=' + device.deviceId + ';gid=' + device.groupId + ';' + device.kind + ';' + device.label + })) + }) + .catch(function (error) { + done(error) + }) + } + + var isEnumerateDevicesSupported = function () { + return (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) + } + // Inspired by and based on https://github.com/cozylife/audio-fingerprint + var audioKey = function (done, options) { + var audioOptions = options.audio + if (audioOptions.excludeIOS11 && navigator.userAgent.match(/OS 11.+Version\/11.+Safari/)) { + // See comment for excludeUserAgent and https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + return done(options.EXCLUDED) + } + + var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext + + if (AudioContext == null) { + return done(options.NOT_AVAILABLE) + } + + var context = new AudioContext(1, 44100, 44100) + + var oscillator = context.createOscillator() + oscillator.type = 'triangle' + oscillator.frequency.setValueAtTime(10000, context.currentTime) + + var compressor = context.createDynamicsCompressor() + each([ + ['threshold', -50], + ['knee', 40], + ['ratio', 12], + ['reduction', -20], + ['attack', 0], + ['release', 0.25] + ], function (item) { + if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') { + compressor[item[0]].setValueAtTime(item[1], context.currentTime) + } + }) + + oscillator.connect(compressor) + compressor.connect(context.destination) + oscillator.start(0) + context.startRendering() + + var audioTimeoutId = setTimeout(function () { + console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".') + context.oncomplete = function () { } + context = null + return done('audioTimeout') + }, audioOptions.timeout) + + context.oncomplete = function (event) { + var fingerprint + try { + clearTimeout(audioTimeoutId) + fingerprint = event.renderedBuffer.getChannelData(0) + .slice(4500, 5000) + .reduce(function (acc, val) { return acc + Math.abs(val) }, 0) + .toString() + oscillator.disconnect() + compressor.disconnect() + } catch (error) { + done(error) + return + } + done(fingerprint) + } + } + var UserAgent = function (done) { + done(navigator.userAgent) + } + var webdriver = function (done, options) { + done(navigator.webdriver == null ? options.NOT_AVAILABLE : navigator.webdriver) + } + var languageKey = function (done, options) { + done(navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || options.NOT_AVAILABLE) + } + var colorDepthKey = function (done, options) { + done(window.screen.colorDepth || options.NOT_AVAILABLE) + } + var deviceMemoryKey = function (done, options) { + done(navigator.deviceMemory || options.NOT_AVAILABLE) + } + var pixelRatioKey = function (done, options) { + done(window.devicePixelRatio || options.NOT_AVAILABLE) + } + var screenResolutionKey = function (done, options) { + done(getScreenResolution(options)) + } + var getScreenResolution = function (options) { + var resolution = [window.screen.width, window.screen.height] + if (options.screen.detectScreenOrientation) { + resolution.sort().reverse() + } + return resolution + } + var availableScreenResolutionKey = function (done, options) { + done(getAvailableScreenResolution(options)) + } + var getAvailableScreenResolution = function (options) { + if (window.screen.availWidth && window.screen.availHeight) { + var available = [window.screen.availHeight, window.screen.availWidth] + if (options.screen.detectScreenOrientation) { + available.sort().reverse() + } + return available + } + // headless browsers + return options.NOT_AVAILABLE + } + var timezoneOffset = function (done) { + done(new Date().getTimezoneOffset()) + } + var timezone = function (done, options) { + if (window.Intl && window.Intl.DateTimeFormat) { + done(new window.Intl.DateTimeFormat().resolvedOptions().timeZone) + return + } + done(options.NOT_AVAILABLE) + } + var sessionStorageKey = function (done, options) { + done(hasSessionStorage(options)) + } + var localStorageKey = function (done, options) { + done(hasLocalStorage(options)) + } + var indexedDbKey = function (done, options) { + done(hasIndexedDB(options)) + } + var addBehaviorKey = function (done) { + // body might not be defined at this point or removed programmatically + done(!!(document.body && document.body.addBehavior)) + } + var openDatabaseKey = function (done) { + done(!!window.openDatabase) + } + var cpuClassKey = function (done, options) { + done(getNavigatorCpuClass(options)) + } + var platformKey = function (done, options) { + done(getNavigatorPlatform(options)) + } + var doNotTrackKey = function (done, options) { + done(getDoNotTrack(options)) + } + var canvasKey = function (done, options) { + if (isCanvasSupported()) { + done(getCanvasFp(options)) + return + } + done(options.NOT_AVAILABLE) + } + var webglKey = function (done, options) { + if (isWebGlSupported()) { + done(getWebglFp()) + return + } + done(options.NOT_AVAILABLE) + } + var webglVendorAndRendererKey = function (done) { + if (isWebGlSupported()) { + done(getWebglVendorAndRenderer()) + return + } + done() + } + var adBlockKey = function (done) { + done(getAdBlock()) + } + var hasLiedLanguagesKey = function (done) { + done(getHasLiedLanguages()) + } + var hasLiedResolutionKey = function (done) { + done(getHasLiedResolution()) + } + var hasLiedOsKey = function (done) { + done(getHasLiedOs()) + } + var hasLiedBrowserKey = function (done) { + done(getHasLiedBrowser()) + } + // flash fonts (will increase fingerprinting time 20X to ~ 130-150ms) + var flashFontsKey = function (done, options) { + // we do flash if swfobject is loaded + if (!hasSwfObjectLoaded()) { + return done('swf object not loaded') + } + if (!hasMinFlashInstalled()) { + return done('flash not installed') + } + if (!options.fonts.swfPath) { + return done('missing options.fonts.swfPath') + } + loadSwfAndDetectFonts(function (fonts) { + done(fonts) + }, options) + } + // kudos to http://www.lalit.org/lab/javascript-css-font-detect/ + var jsFontsKey = function (done, options) { + // a font will be compared against all the three default fonts. + // and if it doesn't match all 3 then that font is not available. + var baseFonts = ['monospace', 'sans-serif', 'serif'] + + var fontList = [ + 'Andale Mono', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', + 'Bitstream Vera Sans Mono', 'Book Antiqua', 'Bookman Old Style', + 'Calibri', 'Cambria', 'Cambria Math', 'Century', 'Century Gothic', 'Century Schoolbook', 'Comic Sans', 'Comic Sans MS', 'Consolas', 'Courier', 'Courier New', + 'Geneva', 'Georgia', + 'Helvetica', 'Helvetica Neue', + 'Impact', + 'Lucida Bright', 'Lucida Calligraphy', 'Lucida Console', 'Lucida Fax', 'LUCIDA GRANDE', 'Lucida Handwriting', 'Lucida Sans', 'Lucida Sans Typewriter', 'Lucida Sans Unicode', + 'Microsoft Sans Serif', 'Monaco', 'Monotype Corsiva', 'MS Gothic', 'MS Outlook', 'MS PGothic', 'MS Reference Sans Serif', 'MS Sans Serif', 'MS Serif', 'MYRIAD', 'MYRIAD PRO', + 'Palatino', 'Palatino Linotype', + 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Light', 'Segoe UI Semibold', 'Segoe UI Symbol', + 'Tahoma', 'Times', 'Times New Roman', 'Times New Roman PS', 'Trebuchet MS', + 'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3' + ] + + if (options.fonts.extendedJsFonts) { + var extendedFontList = [ + 'Abadi MT Condensed Light', 'Academy Engraved LET', 'ADOBE CASLON PRO', 'Adobe Garamond', 'ADOBE GARAMOND PRO', 'Agency FB', 'Aharoni', 'Albertus Extra Bold', 'Albertus Medium', 'Algerian', 'Amazone BT', 'American Typewriter', + 'American Typewriter Condensed', 'AmerType Md BT', 'Andalus', 'Angsana New', 'AngsanaUPC', 'Antique Olive', 'Aparajita', 'Apple Chancery', 'Apple Color Emoji', 'Apple SD Gothic Neo', 'Arabic Typesetting', 'ARCHER', + 'ARNO PRO', 'Arrus BT', 'Aurora Cn BT', 'AvantGarde Bk BT', 'AvantGarde Md BT', 'AVENIR', 'Ayuthaya', 'Bandy', 'Bangla Sangam MN', 'Bank Gothic', 'BankGothic Md BT', 'Baskerville', + 'Baskerville Old Face', 'Batang', 'BatangChe', 'Bauer Bodoni', 'Bauhaus 93', 'Bazooka', 'Bell MT', 'Bembo', 'Benguiat Bk BT', 'Berlin Sans FB', 'Berlin Sans FB Demi', 'Bernard MT Condensed', 'BernhardFashion BT', 'BernhardMod BT', 'Big Caslon', 'BinnerD', + 'Blackadder ITC', 'BlairMdITC TT', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni MT', 'Bodoni MT Black', 'Bodoni MT Condensed', 'Bodoni MT Poster Compressed', + 'Bookshelf Symbol 7', 'Boulder', 'Bradley Hand', 'Bradley Hand ITC', 'Bremen Bd BT', 'Britannic Bold', 'Broadway', 'Browallia New', 'BrowalliaUPC', 'Brush Script MT', 'Californian FB', 'Calisto MT', 'Calligrapher', 'Candara', + 'CaslonOpnface BT', 'Castellar', 'Centaur', 'Cezanne', 'CG Omega', 'CG Times', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charlesworth', 'Charter Bd BT', 'Charter BT', 'Chaucer', + 'ChelthmITC Bk BT', 'Chiller', 'Clarendon', 'Clarendon Condensed', 'CloisterBlack BT', 'Cochin', 'Colonna MT', 'Constantia', 'Cooper Black', 'Copperplate', 'Copperplate Gothic', 'Copperplate Gothic Bold', + 'Copperplate Gothic Light', 'CopperplGoth Bd BT', 'Corbel', 'Cordia New', 'CordiaUPC', 'Cornerstone', 'Coronet', 'Cuckoo', 'Curlz MT', 'DaunPenh', 'Dauphin', 'David', 'DB LCD Temp', 'DELICIOUS', 'Denmark', + 'DFKai-SB', 'Didot', 'DilleniaUPC', 'DIN', 'DokChampa', 'Dotum', 'DotumChe', 'Ebrima', 'Edwardian Script ITC', 'Elephant', 'English 111 Vivace BT', 'Engravers MT', 'EngraversGothic BT', 'Eras Bold ITC', 'Eras Demi ITC', 'Eras Light ITC', 'Eras Medium ITC', + 'EucrosiaUPC', 'Euphemia', 'Euphemia UCAS', 'EUROSTILE', 'Exotc350 Bd BT', 'FangSong', 'Felix Titling', 'Fixedsys', 'FONTIN', 'Footlight MT Light', 'Forte', + 'FrankRuehl', 'Fransiscan', 'Freefrm721 Blk BT', 'FreesiaUPC', 'Freestyle Script', 'French Script MT', 'FrnkGothITC Bk BT', 'Fruitger', 'FRUTIGER', + 'Futura', 'Futura Bk BT', 'Futura Lt BT', 'Futura Md BT', 'Futura ZBlk BT', 'FuturaBlack BT', 'Gabriola', 'Galliard BT', 'Gautami', 'Geeza Pro', 'Geometr231 BT', 'Geometr231 Hv BT', 'Geometr231 Lt BT', 'GeoSlab 703 Lt BT', + 'GeoSlab 703 XBd BT', 'Gigi', 'Gill Sans', 'Gill Sans MT', 'Gill Sans MT Condensed', 'Gill Sans MT Ext Condensed Bold', 'Gill Sans Ultra Bold', 'Gill Sans Ultra Bold Condensed', 'Gisha', 'Gloucester MT Extra Condensed', 'GOTHAM', 'GOTHAM BOLD', + 'Goudy Old Style', 'Goudy Stout', 'GoudyHandtooled BT', 'GoudyOLSt BT', 'Gujarati Sangam MN', 'Gulim', 'GulimChe', 'Gungsuh', 'GungsuhChe', 'Gurmukhi MN', 'Haettenschweiler', 'Harlow Solid Italic', 'Harrington', 'Heather', 'Heiti SC', 'Heiti TC', 'HELV', + 'Herald', 'High Tower Text', 'Hiragino Kaku Gothic ProN', 'Hiragino Mincho ProN', 'Hoefler Text', 'Humanst 521 Cn BT', 'Humanst521 BT', 'Humanst521 Lt BT', 'Imprint MT Shadow', 'Incised901 Bd BT', 'Incised901 BT', + 'Incised901 Lt BT', 'INCONSOLATA', 'Informal Roman', 'Informal011 BT', 'INTERSTATE', 'IrisUPC', 'Iskoola Pota', 'JasmineUPC', 'Jazz LET', 'Jenson', 'Jester', 'Jokerman', 'Juice ITC', 'Kabel Bk BT', 'Kabel Ult BT', 'Kailasa', 'KaiTi', 'Kalinga', 'Kannada Sangam MN', + 'Kartika', 'Kaufmann Bd BT', 'Kaufmann BT', 'Khmer UI', 'KodchiangUPC', 'Kokila', 'Korinna BT', 'Kristen ITC', 'Krungthep', 'Kunstler Script', 'Lao UI', 'Latha', 'Leelawadee', 'Letter Gothic', 'Levenim MT', 'LilyUPC', 'Lithograph', 'Lithograph Light', 'Long Island', + 'Lydian BT', 'Magneto', 'Maiandra GD', 'Malayalam Sangam MN', 'Malgun Gothic', + 'Mangal', 'Marigold', 'Marion', 'Marker Felt', 'Market', 'Marlett', 'Matisse ITC', 'Matura MT Script Capitals', 'Meiryo', 'Meiryo UI', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Tai Le', + 'Microsoft Uighur', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU', 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', 'MingLiU-ExtB', 'Minion', 'Minion Pro', 'Miriam', 'Miriam Fixed', 'Mistral', 'Modern', 'Modern No. 20', 'Mona Lisa Solid ITC TT', 'Mongolian Baiti', + 'MONO', 'MoolBoran', 'Mrs Eaves', 'MS LineDraw', 'MS Mincho', 'MS PMincho', 'MS Reference Specialty', 'MS UI Gothic', 'MT Extra', 'MUSEO', 'MV Boli', + 'Nadeem', 'Narkisim', 'NEVIS', 'News Gothic', 'News GothicMT', 'NewsGoth BT', 'Niagara Engraved', 'Niagara Solid', 'Noteworthy', 'NSimSun', 'Nyala', 'OCR A Extended', 'Old Century', 'Old English Text MT', 'Onyx', 'Onyx BT', 'OPTIMA', 'Oriya Sangam MN', + 'OSAKA', 'OzHandicraft BT', 'Palace Script MT', 'Papyrus', 'Parchment', 'Party LET', 'Pegasus', 'Perpetua', 'Perpetua Titling MT', 'PetitaBold', 'Pickwick', 'Plantagenet Cherokee', 'Playbill', 'PMingLiU', 'PMingLiU-ExtB', + 'Poor Richard', 'Poster', 'PosterBodoni BT', 'PRINCETOWN LET', 'Pristina', 'PTBarnum BT', 'Pythagoras', 'Raavi', 'Rage Italic', 'Ravie', 'Ribbon131 Bd BT', 'Rockwell', 'Rockwell Condensed', 'Rockwell Extra Bold', 'Rod', 'Roman', 'Sakkal Majalla', + 'Santa Fe LET', 'Savoye LET', 'Sceptre', 'Script', 'Script MT Bold', 'SCRIPTINA', 'Serifa', 'Serifa BT', 'Serifa Th BT', 'ShelleyVolante BT', 'Sherwood', + 'Shonar Bangla', 'Showcard Gothic', 'Shruti', 'Signboard', 'SILKSCREEN', 'SimHei', 'Simplified Arabic', 'Simplified Arabic Fixed', 'SimSun', 'SimSun-ExtB', 'Sinhala Sangam MN', 'Sketch Rockwell', 'Skia', 'Small Fonts', 'Snap ITC', 'Snell Roundhand', 'Socket', + 'Souvenir Lt BT', 'Staccato222 BT', 'Steamer', 'Stencil', 'Storybook', 'Styllo', 'Subway', 'Swis721 BlkEx BT', 'Swiss911 XCm BT', 'Sylfaen', 'Synchro LET', 'System', 'Tamil Sangam MN', 'Technical', 'Teletype', 'Telugu Sangam MN', 'Tempus Sans ITC', + 'Terminal', 'Thonburi', 'Traditional Arabic', 'Trajan', 'TRAJAN PRO', 'Tristan', 'Tubular', 'Tunga', 'Tw Cen MT', 'Tw Cen MT Condensed', 'Tw Cen MT Condensed Extra Bold', + 'TypoUpright BT', 'Unicorn', 'Univers', 'Univers CE 55 Medium', 'Univers Condensed', 'Utsaah', 'Vagabond', 'Vani', 'Vijaya', 'Viner Hand ITC', 'VisualUI', 'Vivaldi', 'Vladimir Script', 'Vrinda', 'Westminster', 'WHITNEY', 'Wide Latin', + 'ZapfEllipt BT', 'ZapfHumnst BT', 'ZapfHumnst Dm BT', 'Zapfino', 'Zurich BlkEx BT', 'Zurich Ex BT', 'ZWAdobeF'] + fontList = fontList.concat(extendedFontList) + } + + fontList = fontList.concat(options.fonts.userDefinedFonts) + + // remove duplicate fonts + fontList = fontList.filter(function (font, position) { + return fontList.indexOf(font) === position + }) + + // we use m or w because these two characters take up the maximum width. + // And we use a LLi so that the same matching fonts can get separated + var testString = 'mmmmmmmmmmlli' + + // we test using 72px font size, we may use any size. I guess larger the better. + var testSize = '72px' + + var h = document.getElementsByTagName('body')[0] + + // div to load spans for the base fonts + var baseFontsDiv = document.createElement('div') + + // div to load spans for the fonts to detect + var fontsDiv = document.createElement('div') + + var defaultWidth = {} + var defaultHeight = {} + + // creates a span where the fonts will be loaded + var createSpan = function () { + var s = document.createElement('span') + /* + * We need this css as in some weird browser this + * span elements shows up for a microSec which creates a + * bad user experience + */ + s.style.position = 'absolute' + s.style.left = '-9999px' + s.style.fontSize = testSize + + // css font reset to reset external styles + s.style.fontStyle = 'normal' + s.style.fontWeight = 'normal' + s.style.letterSpacing = 'normal' + s.style.lineBreak = 'auto' + s.style.lineHeight = 'normal' + s.style.textTransform = 'none' + s.style.textAlign = 'left' + s.style.textDecoration = 'none' + s.style.textShadow = 'none' + s.style.whiteSpace = 'normal' + s.style.wordBreak = 'normal' + s.style.wordSpacing = 'normal' + + s.innerHTML = testString + return s + } + + // creates a span and load the font to detect and a base font for fallback + var createSpanWithFonts = function (fontToDetect, baseFont) { + var s = createSpan() + s.style.fontFamily = "'" + fontToDetect + "'," + baseFont + return s + } + + // creates spans for the base fonts and adds them to baseFontsDiv + var initializeBaseFontsSpans = function () { + var spans = [] + for (var index = 0, length = baseFonts.length; index < length; index++) { + var s = createSpan() + s.style.fontFamily = baseFonts[index] + baseFontsDiv.appendChild(s) + spans.push(s) + } + return spans + } + + // creates spans for the fonts to detect and adds them to fontsDiv + var initializeFontsSpans = function () { + var spans = {} + for (var i = 0, l = fontList.length; i < l; i++) { + var fontSpans = [] + for (var j = 0, numDefaultFonts = baseFonts.length; j < numDefaultFonts; j++) { + var s = createSpanWithFonts(fontList[i], baseFonts[j]) + fontsDiv.appendChild(s) + fontSpans.push(s) + } + spans[fontList[i]] = fontSpans // Stores {fontName : [spans for that font]} + } + return spans + } + + // checks if a font is available + var isFontAvailable = function (fontSpans) { + var detected = false + for (var i = 0; i < baseFonts.length; i++) { + detected = (fontSpans[i].offsetWidth !== defaultWidth[baseFonts[i]] || fontSpans[i].offsetHeight !== defaultHeight[baseFonts[i]]) + if (detected) { + return detected + } + } + return detected + } + + // create spans for base fonts + var baseFontsSpans = initializeBaseFontsSpans() + + // add the spans to the DOM + h.appendChild(baseFontsDiv) + + // get the default width for the three base fonts + for (var index = 0, length = baseFonts.length; index < length; index++) { + defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth // width for the default font + defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight // height for the default font + } + + // create spans for fonts to detect + var fontsSpans = initializeFontsSpans() + + // add all the spans to the DOM + h.appendChild(fontsDiv) + + // check available fonts + var available = [] + for (var i = 0, l = fontList.length; i < l; i++) { + if (isFontAvailable(fontsSpans[fontList[i]])) { + available.push(fontList[i]) + } + } + + // remove spans from DOM + h.removeChild(fontsDiv) + h.removeChild(baseFontsDiv) + done(available) + } + var pluginsComponent = function (done, options) { + if (isIE()) { + if (!options.plugins.excludeIE) { + done(getIEPlugins(options)) + } else { + done(options.EXCLUDED) + } + } else { + done(getRegularPlugins(options)) + } + } + var getRegularPlugins = function (options) { + if (navigator.plugins == null) { + return options.NOT_AVAILABLE + } + + var plugins = [] + // plugins isn't defined in Node envs. + for (var i = 0, l = navigator.plugins.length; i < l; i++) { + if (navigator.plugins[i]) { plugins.push(navigator.plugins[i]) } + } + + // sorting plugins only for those user agents, that we know randomize the plugins + // every time we try to enumerate them + if (pluginsShouldBeSorted(options)) { + plugins = plugins.sort(function (a, b) { + if (a.name > b.name) { return 1 } + if (a.name < b.name) { return -1 } + return 0 + }) + } + return map(plugins, function (p) { + var mimeTypes = map(p, function (mt) { + return [mt.type, mt.suffixes] + }) + return [p.name, p.description, mimeTypes] + }) + } + var getIEPlugins = function (options) { + var result = [] + if ((Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(window, 'ActiveXObject')) || ('ActiveXObject' in window)) { + var names = [ + 'AcroPDF.PDF', // Adobe PDF reader 7+ + 'Adodb.Stream', + 'AgControl.AgControl', // Silverlight + 'DevalVRXCtrl.DevalVRXCtrl.1', + 'MacromediaFlashPaper.MacromediaFlashPaper', + 'Msxml2.DOMDocument', + 'Msxml2.XMLHTTP', + 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr + 'QuickTime.QuickTime', // QuickTime + 'QuickTimeCheckObject.QuickTimeCheck.1', + 'RealPlayer', + 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', + 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', + 'Scripting.Dictionary', + 'SWCtl.SWCtl', // ShockWave player + 'Shell.UIHelper', + 'ShockwaveFlash.ShockwaveFlash', // flash plugin + 'Skype.Detection', + 'TDCCtl.TDCCtl', + 'WMPlayer.OCX', // Windows media player + 'rmocx.RealPlayer G2 Control', + 'rmocx.RealPlayer G2 Control.1' + ] + // starting to detect plugins in IE + result = map(names, function (name) { + try { + // eslint-disable-next-line no-new + new window.ActiveXObject(name) + return name + } catch (e) { + return options.ERROR + } + }) + } else { + result.push(options.NOT_AVAILABLE) + } + if (navigator.plugins) { + result = result.concat(getRegularPlugins(options)) + } + return result + } + var pluginsShouldBeSorted = function (options) { + var should = false + for (var i = 0, l = options.plugins.sortPluginsFor.length; i < l; i++) { + var re = options.plugins.sortPluginsFor[i] + if (navigator.userAgent.match(re)) { + should = true + break + } + } + return should + } + var touchSupportKey = function (done) { + done(getTouchSupport()) + } + var hardwareConcurrencyKey = function (done, options) { + done(getHardwareConcurrency(options)) + } + var hasSessionStorage = function (options) { + try { + return !!window.sessionStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + + // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 + var hasLocalStorage = function (options) { + try { + return !!window.localStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var hasIndexedDB = function (options) { + try { + return !!window.indexedDB + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var getHardwareConcurrency = function (options) { + if (navigator.hardwareConcurrency) { + return navigator.hardwareConcurrency + } + return options.NOT_AVAILABLE + } + var getNavigatorCpuClass = function (options) { + return navigator.cpuClass || options.NOT_AVAILABLE + } + var getNavigatorPlatform = function (options) { + if (navigator.platform) { + return navigator.platform + } else { + return options.NOT_AVAILABLE + } + } + var getDoNotTrack = function (options) { + if (navigator.doNotTrack) { + return navigator.doNotTrack + } else if (navigator.msDoNotTrack) { + return navigator.msDoNotTrack + } else if (window.doNotTrack) { + return window.doNotTrack + } else { + return options.NOT_AVAILABLE + } + } + // This is a crude and primitive touch screen detection. + // It's not possible to currently reliably detect the availability of a touch screen + // with a JS, without actually subscribing to a touch event. + // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/ + // https://github.com/Modernizr/Modernizr/issues/548 + // method returns an array of 3 values: + // maxTouchPoints, the success or failure of creating a TouchEvent, + // and the availability of the 'ontouchstart' property + + var getTouchSupport = function () { + var maxTouchPoints = 0 + var touchEvent + if (typeof navigator.maxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.maxTouchPoints + } else if (typeof navigator.msMaxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.msMaxTouchPoints + } + try { + document.createEvent('TouchEvent') + touchEvent = true + } catch (_) { + touchEvent = false + } + var touchStart = 'ontouchstart' in window + return [maxTouchPoints, touchEvent, touchStart] + } + // https://www.browserleaks.com/canvas#how-does-it-work + + var getCanvasFp = function (options) { + var result = [] + // Very simple now, need to make it more complex (geo shapes etc) + var canvas = document.createElement('canvas') + canvas.width = 2000 + canvas.height = 200 + canvas.style.display = 'inline' + var ctx = canvas.getContext('2d') + // detect browser support of canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js + ctx.rect(0, 0, 10, 10) + ctx.rect(2, 2, 6, 6) + result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no')) + + ctx.textBaseline = 'alphabetic' + ctx.fillStyle = '#f60' + ctx.fillRect(125, 1, 62, 20) + ctx.fillStyle = '#069' + // https://github.com/Valve/fingerprintjs2/issues/66 + if (options.dontUseFakeFontInCanvas) { + ctx.font = '11pt Arial' + } else { + ctx.font = '11pt no-real-font-123' + } + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15) + ctx.fillStyle = 'rgba(102, 204, 0, 0.2)' + ctx.font = '18pt Arial' + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45) + + // canvas blending + // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ + // http://jsfiddle.net/NDYV8/16/ + ctx.globalCompositeOperation = 'multiply' + ctx.fillStyle = 'rgb(255,0,255)' + ctx.beginPath() + ctx.arc(50, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(0,255,255)' + ctx.beginPath() + ctx.arc(100, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,255,0)' + ctx.beginPath() + ctx.arc(75, 100, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,0,255)' + // canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // http://jsfiddle.net/NDYV8/19/ + ctx.arc(75, 75, 75, 0, Math.PI * 2, true) + ctx.arc(75, 75, 25, 0, Math.PI * 2, true) + ctx.fill('evenodd') + + if (canvas.toDataURL) { result.push('canvas fp:' + canvas.toDataURL()) } + return result + } + var getWebglFp = function () { + var gl + var fa2s = function (fa) { + gl.clearColor(0.0, 0.0, 0.0, 1.0) + gl.enable(gl.DEPTH_TEST) + gl.depthFunc(gl.LEQUAL) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + return '[' + fa[0] + ', ' + fa[1] + ']' + } + var maxAnisotropy = function (gl) { + var ext = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') + if (ext) { + var anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT) + if (anisotropy === 0) { + anisotropy = 2 + } + return anisotropy + } else { + return null + } + } + + gl = getWebglCanvas() + if (!gl) { return null } + // WebGL fingerprinting is a combination of techniques, found in MaxMind antifraud script & Augur fingerprinting. + // First it draws a gradient object with shaders and convers the image to the Base64 string. + // Then it enumerates all WebGL extensions & capabilities and appends them to the Base64 string, resulting in a huge WebGL string, potentially very unique on each device + // Since iOS supports webgl starting from version 8.1 and 8.1 runs on several graphics chips, the results may be different across ios devices, but we need to verify it. + var result = [] + var vShaderTemplate = 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}' + var fShaderTemplate = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}' + var vertexPosBuffer = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer) + var vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) + vertexPosBuffer.itemSize = 3 + vertexPosBuffer.numItems = 3 + var program = gl.createProgram() + var vshader = gl.createShader(gl.VERTEX_SHADER) + gl.shaderSource(vshader, vShaderTemplate) + gl.compileShader(vshader) + var fshader = gl.createShader(gl.FRAGMENT_SHADER) + gl.shaderSource(fshader, fShaderTemplate) + gl.compileShader(fshader) + gl.attachShader(program, vshader) + gl.attachShader(program, fshader) + gl.linkProgram(program) + gl.useProgram(program) + program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') + program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') + gl.enableVertexAttribArray(program.vertexPosArray) + gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, !1, 0, 0) + gl.uniform2f(program.offsetUniform, 1, 1) + gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems) + try { + result.push(gl.canvas.toDataURL()) + } catch (e) { + /* .toDataURL may be absent or broken (blocked by extension) */ + } + result.push('extensions:' + (gl.getSupportedExtensions() || []).join(';')) + result.push('webgl aliased line width range:' + fa2s(gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE))) + result.push('webgl aliased point size range:' + fa2s(gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE))) + result.push('webgl alpha bits:' + gl.getParameter(gl.ALPHA_BITS)) + result.push('webgl antialiasing:' + (gl.getContextAttributes().antialias ? 'yes' : 'no')) + result.push('webgl blue bits:' + gl.getParameter(gl.BLUE_BITS)) + result.push('webgl depth bits:' + gl.getParameter(gl.DEPTH_BITS)) + result.push('webgl green bits:' + gl.getParameter(gl.GREEN_BITS)) + result.push('webgl max anisotropy:' + maxAnisotropy(gl)) + result.push('webgl max combined texture image units:' + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)) + result.push('webgl max cube map texture size:' + gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) + result.push('webgl max fragment uniform vectors:' + gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)) + result.push('webgl max render buffer size:' + gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) + result.push('webgl max texture image units:' + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max texture size:' + gl.getParameter(gl.MAX_TEXTURE_SIZE)) + result.push('webgl max varying vectors:' + gl.getParameter(gl.MAX_VARYING_VECTORS)) + result.push('webgl max vertex attribs:' + gl.getParameter(gl.MAX_VERTEX_ATTRIBS)) + result.push('webgl max vertex texture image units:' + gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max vertex uniform vectors:' + gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)) + result.push('webgl max viewport dims:' + fa2s(gl.getParameter(gl.MAX_VIEWPORT_DIMS))) + result.push('webgl red bits:' + gl.getParameter(gl.RED_BITS)) + result.push('webgl renderer:' + gl.getParameter(gl.RENDERER)) + result.push('webgl shading language version:' + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) + result.push('webgl stencil bits:' + gl.getParameter(gl.STENCIL_BITS)) + result.push('webgl vendor:' + gl.getParameter(gl.VENDOR)) + result.push('webgl version:' + gl.getParameter(gl.VERSION)) + + try { + // Add the unmasked vendor and unmasked renderer if the debug_renderer_info extension is available + var extensionDebugRendererInfo = gl.getExtension('WEBGL_debug_renderer_info') + if (extensionDebugRendererInfo) { + result.push('webgl unmasked vendor:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL)) + result.push('webgl unmasked renderer:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL)) + } + } catch (e) { /* squelch */ } + + if (!gl.getShaderPrecisionFormat) { + return result + } + + each(['FLOAT', 'INT'], function (numType) { + each(['VERTEX', 'FRAGMENT'], function (shader) { + each(['HIGH', 'MEDIUM', 'LOW'], function (numSize) { + each(['precision', 'rangeMin', 'rangeMax'], function (key) { + var format = gl.getShaderPrecisionFormat(gl[shader + '_SHADER'], gl[numSize + '_' + numType])[key] + if (key !== 'precision') { + key = 'precision ' + key + } + var line = ['webgl ', shader.toLowerCase(), ' shader ', numSize.toLowerCase(), ' ', numType.toLowerCase(), ' ', key, ':', format].join('') + result.push(line) + }) + }) + }) + }) + return result + } + var getWebglVendorAndRenderer = function () { + /* This a subset of the WebGL fingerprint with a lot of entropy, while being reasonably browser-independent */ + try { + var glContext = getWebglCanvas() + var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info') + return glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL) + '~' + glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL) + } catch (e) { + return null + } + } + var getAdBlock = function () { + var ads = document.createElement('div') + ads.innerHTML = ' ' + ads.className = 'adsbox' + var result = false + try { + // body may not exist, that's why we need try/catch + document.body.appendChild(ads) + result = document.getElementsByClassName('adsbox')[0].offsetHeight === 0 + document.body.removeChild(ads) + } catch (e) { + result = false + } + return result + } + var getHasLiedLanguages = function () { + // We check if navigator.language is equal to the first language of navigator.languages + // navigator.languages is undefined on IE11 (and potentially older IEs) + if (typeof navigator.languages !== 'undefined') { + try { + var firstLanguages = navigator.languages[0].substr(0, 2) + if (firstLanguages !== navigator.language.substr(0, 2)) { + return true + } + } catch (err) { + return true + } + } + return false + } + var getHasLiedResolution = function () { + return window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight + } + var getHasLiedOs = function () { + var userAgent = navigator.userAgent.toLowerCase() + var oscpu = navigator.oscpu + var platform = navigator.platform.toLowerCase() + var os + // We extract the OS from the user agent (respect the order of the if else if statement) + if (userAgent.indexOf('windows phone') >= 0) { + os = 'Windows Phone' + } else if (userAgent.indexOf('win') >= 0) { + os = 'Windows' + } else if (userAgent.indexOf('android') >= 0) { + os = 'Android' + } else if (userAgent.indexOf('linux') >= 0 || userAgent.indexOf('cros') >= 0) { + os = 'Linux' + } else if (userAgent.indexOf('iphone') >= 0 || userAgent.indexOf('ipad') >= 0) { + os = 'iOS' + } else if (userAgent.indexOf('mac') >= 0) { + os = 'Mac' + } else { + os = 'Other' + } + // We detect if the person uses a mobile device + var mobileDevice = (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)) + + if (mobileDevice && os !== 'Windows Phone' && os !== 'Android' && os !== 'iOS' && os !== 'Other') { + return true + } + + // We compare oscpu with the OS extracted from the UA + if (typeof oscpu !== 'undefined') { + oscpu = oscpu.toLowerCase() + if (oscpu.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if (oscpu.indexOf('linux') >= 0 && os !== 'Linux' && os !== 'Android') { + return true + } else if (oscpu.indexOf('mac') >= 0 && os !== 'Mac' && os !== 'iOS') { + return true + } else if ((oscpu.indexOf('win') === -1 && oscpu.indexOf('linux') === -1 && oscpu.indexOf('mac') === -1) !== (os === 'Other')) { + return true + } + } + + // We compare platform with the OS extracted from the UA + if (platform.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if ((platform.indexOf('linux') >= 0 || platform.indexOf('android') >= 0 || platform.indexOf('pike') >= 0) && os !== 'Linux' && os !== 'Android') { + return true + } else if ((platform.indexOf('mac') >= 0 || platform.indexOf('ipad') >= 0 || platform.indexOf('ipod') >= 0 || platform.indexOf('iphone') >= 0) && os !== 'Mac' && os !== 'iOS') { + return true + } else { + var platformIsOther = platform.indexOf('win') < 0 && + platform.indexOf('linux') < 0 && + platform.indexOf('mac') < 0 && + platform.indexOf('iphone') < 0 && + platform.indexOf('ipad') < 0 + if (platformIsOther !== (os === 'Other')) { + return true + } + } + + return typeof navigator.plugins === 'undefined' && os !== 'Windows' && os !== 'Windows Phone' + } + var getHasLiedBrowser = function () { + var userAgent = navigator.userAgent.toLowerCase() + var productSub = navigator.productSub + + // we extract the browser from the user agent (respect the order of the tests) + var browser + if (userAgent.indexOf('firefox') >= 0) { + browser = 'Firefox' + } else if (userAgent.indexOf('opera') >= 0 || userAgent.indexOf('opr') >= 0) { + browser = 'Opera' + } else if (userAgent.indexOf('chrome') >= 0) { + browser = 'Chrome' + } else if (userAgent.indexOf('safari') >= 0) { + browser = 'Safari' + } else if (userAgent.indexOf('trident') >= 0) { + browser = 'Internet Explorer' + } else { + browser = 'Other' + } + + if ((browser === 'Chrome' || browser === 'Safari' || browser === 'Opera') && productSub !== '20030107') { + return true + } + + // eslint-disable-next-line no-eval + var tempRes = eval.toString().length + if (tempRes === 37 && browser !== 'Safari' && browser !== 'Firefox' && browser !== 'Other') { + return true + } else if (tempRes === 39 && browser !== 'Internet Explorer' && browser !== 'Other') { + return true + } else if (tempRes === 33 && browser !== 'Chrome' && browser !== 'Opera' && browser !== 'Other') { + return true + } + + // We create an error to see how it is handled + var errFirefox + try { + // eslint-disable-next-line no-throw-literal + throw 'a' + } catch (err) { + try { + err.toSource() + errFirefox = true + } catch (errOfErr) { + errFirefox = false + } + } + return errFirefox && browser !== 'Firefox' && browser !== 'Other' + } + var isCanvasSupported = function () { + var elem = document.createElement('canvas') + return !!(elem.getContext && elem.getContext('2d')) + } + var isWebGlSupported = function () { + // code taken from Modernizr + if (!isCanvasSupported()) { + return false + } + + var glContext = getWebglCanvas() + return !!window.WebGLRenderingContext && !!glContext + } + var isIE = function () { + if (navigator.appName === 'Microsoft Internet Explorer') { + return true + } else if (navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)) { // IE 11 + return true + } + return false + } + var hasSwfObjectLoaded = function () { + return typeof window.swfobject !== 'undefined' + } + var hasMinFlashInstalled = function () { + return window.swfobject.hasFlashPlayerVersion('9.0.0') + } + var addFlashDivNode = function (options) { + var node = document.createElement('div') + node.setAttribute('id', options.fonts.swfContainerId) + document.body.appendChild(node) + } + var loadSwfAndDetectFonts = function (done, options) { + var hiddenCallback = '___fp_swf_loaded' + window[hiddenCallback] = function (fonts) { + done(fonts) + } + var id = options.fonts.swfContainerId + addFlashDivNode() + var flashvars = { onReady: hiddenCallback } + var flashparams = { allowScriptAccess: 'always', menu: 'false' } + window.swfobject.embedSWF(options.fonts.swfPath, id, '1', '1', '9.0.0', false, flashvars, flashparams, {}) + } + var getWebglCanvas = function () { + var canvas = document.createElement('canvas') + var gl = null + try { + gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') + } catch (e) { /* squelch */ } + if (!gl) { gl = null } + return gl + } + + var components = [ + { key: 'userAgent', getData: UserAgent }, + { key: 'webdriver', getData: webdriver }, + { key: 'language', getData: languageKey }, + { key: 'colorDepth', getData: colorDepthKey }, + { key: 'deviceMemory', getData: deviceMemoryKey }, + { key: 'pixelRatio', getData: pixelRatioKey }, + { key: 'hardwareConcurrency', getData: hardwareConcurrencyKey }, + { key: 'screenResolution', getData: screenResolutionKey }, + { key: 'availableScreenResolution', getData: availableScreenResolutionKey }, + { key: 'timezoneOffset', getData: timezoneOffset }, + { key: 'timezone', getData: timezone }, + { key: 'sessionStorage', getData: sessionStorageKey }, + { key: 'localStorage', getData: localStorageKey }, + { key: 'indexedDb', getData: indexedDbKey }, + { key: 'addBehavior', getData: addBehaviorKey }, + { key: 'openDatabase', getData: openDatabaseKey }, + { key: 'cpuClass', getData: cpuClassKey }, + { key: 'platform', getData: platformKey }, + { key: 'doNotTrack', getData: doNotTrackKey }, + { key: 'plugins', getData: pluginsComponent }, + { key: 'canvas', getData: canvasKey }, + { key: 'webgl', getData: webglKey }, + { key: 'webglVendorAndRenderer', getData: webglVendorAndRendererKey }, + { key: 'adBlock', getData: adBlockKey }, + { key: 'hasLiedLanguages', getData: hasLiedLanguagesKey }, + { key: 'hasLiedResolution', getData: hasLiedResolutionKey }, + { key: 'hasLiedOs', getData: hasLiedOsKey }, + { key: 'hasLiedBrowser', getData: hasLiedBrowserKey }, + { key: 'touchSupport', getData: touchSupportKey }, + { key: 'fonts', getData: jsFontsKey, pauseBefore: true }, + { key: 'fontsFlash', getData: flashFontsKey, pauseBefore: true }, + { key: 'audio', getData: audioKey }, + { key: 'enumerateDevices', getData: enumerateDevicesKey } + ] + + var Fingerprint2 = function (options) { + throw new Error("'new Fingerprint()' is deprecated, see https://github.com/Valve/fingerprintjs2#upgrade-guide-from-182-to-200") + } + + Fingerprint2.get = function (options, callback) { + if (!callback) { + callback = options + options = {} + } else if (!options) { + options = {} + } + extendSoft(options, defaultOptions) + options.components = options.extraComponents.concat(components) + + var keys = { + data: [], + addPreprocessedComponent: function (key, value) { + if (typeof options.preprocessor === 'function') { + value = options.preprocessor(key, value) + } + keys.data.push({ key: key, value: value }) + } + } + + var i = -1 + var chainComponents = function (alreadyWaited) { + i += 1 + if (i >= options.components.length) { // on finish + callback(keys.data) + return + } + var component = options.components[i] + + if (options.excludes[component.key]) { + chainComponents(false) // skip + return + } + + if (!alreadyWaited && component.pauseBefore) { + i -= 1 + setTimeout(function () { + chainComponents(true) + }, 1) + return + } + + try { + component.getData(function (value) { + keys.addPreprocessedComponent(component.key, value) + chainComponents(false) + }, options) + } catch (error) { + // main body error + keys.addPreprocessedComponent(component.key, String(error)) + chainComponents(false) + } + } + + chainComponents(false) + } + + Fingerprint2.getPromise = function (options) { + return new Promise(function (resolve, reject) { + Fingerprint2.get(options, resolve) + }) + } + + Fingerprint2.getV18 = function (options, callback) { + if (callback == null) { + callback = options + options = {} + } + return Fingerprint2.get(options, function (components) { + var newComponents = [] + for (var i = 0; i < components.length; i++) { + var component = components[i] + if (component.value === (options.NOT_AVAILABLE || 'not available')) { + newComponents.push({ key: component.key, value: 'unknown' }) + } else if (component.key === 'plugins') { + newComponents.push({ + key: 'plugins', + value: map(component.value, function (p) { + var mimeTypes = map(p[2], function (mt) { + if (mt.join) { return mt.join('~') } + return mt + }).join(',') + return [p[0], p[1], mimeTypes].join('::') + }) + }) + } else if (['canvas', 'webgl'].indexOf(component.key) !== -1) { + newComponents.push({ key: component.key, value: component.value.join('~') }) + } else if (['sessionStorage', 'localStorage', 'indexedDb', 'addBehavior', 'openDatabase'].indexOf(component.key) !== -1) { + if (component.value) { + newComponents.push({ key: component.key, value: 1 }) + } else { + // skip + continue + } + } else { + if (component.value) { + newComponents.push(component.value.join ? { key: component.key, value: component.value.join(';') } : component) + } else { + newComponents.push({ key: component.key, value: component.value }) + } + } + } + var murmur = x64hash128(map(newComponents, function (component) { return component.value }).join('~~~'), 31) + callback(murmur, newComponents) + }) + } + + Fingerprint2.x64hash128 = x64hash128 + Fingerprint2.VERSION = '2.1.0' + return Fingerprint2 +}) \ No newline at end of file diff --git a/html/development/hourglass.gif b/html/development/hourglass.gif new file mode 100644 index 0000000..645caeb Binary files /dev/null and b/html/development/hourglass.gif differ diff --git a/html/development/iron.js b/html/development/iron.js new file mode 100644 index 0000000..5660338 --- /dev/null +++ b/html/development/iron.js @@ -0,0 +1,2416 @@ +var ironUtility = { + /* + * START AES SECTION + */ + aes: { + // structure of valid key sizes + keySize: { + SIZE_128: 16, + SIZE_192: 24, + SIZE_256: 32 + }, + + // Rijndael S-box + sbox: [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 + ], + + // Rijndael Inverted S-box + rsbox: [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d], + + /* rotate the word eight bits to the left */ + rotate: function (word) { + var c = word[0]; + for (var i = 0; i < 3; i++) + word[i] = word[i + 1]; + word[3] = c; + + return word; + }, + + // Rijndael Rcon + Rcon: [ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, + 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, + 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, + 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, + 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, + 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, + 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, + 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, + 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, + 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb + ], + + G2X: [ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, + 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, + 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, + 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, + 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, + 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, + 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, + 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, + 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, + 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, + 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, + 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd, + 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, + 0xe3, 0xe1, 0xe7, 0xe5 + ], + + G3X: [ + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, + 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, + 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, + 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, + 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, + 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, + 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, + 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, + 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, + 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, + 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, + 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, + 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, + 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, + 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e, + 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, + 0x1f, 0x1c, 0x19, 0x1a + ], + + G9X: [ + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, + 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, + 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, + 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, + 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, + 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, + 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, + 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, + 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, + 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, + 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, + 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, + 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, + 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, + 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba, + 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, + 0x5d, 0x54, 0x4f, 0x46 + ], + + GBX: [ + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, + 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, + 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, + 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, + 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, + 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, + 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, + 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, + 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, + 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, + 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, + 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, + 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, + 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, + 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67, + 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, + 0xbe, 0xb5, 0xa8, 0xa3 + ], + + GDX: [ + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, + 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, + 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, + 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, + 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, + 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, + 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, + 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, + 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, + 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, + 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, + 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, + 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, + 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, + 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b, + 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, + 0x80, 0x8d, 0x9a, 0x97 + ], + + GEX: [ + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, + 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, + 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, + 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, + 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, + 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, + 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, + 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, + 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, + 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, + 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, + 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, + 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, + 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, + 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25, + 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, + 0x9f, 0x91, 0x83, 0x8d + ], + + // Key Schedule Core + core: function (word, iteration) { + /* rotate the 32-bit word 8 bits to the left */ + word = this.rotate(word); + /* apply S-Box substitution on all 4 parts of the 32-bit word */ + for (var i = 0; i < 4; ++i) + word[i] = this.sbox[word[i]]; + /* XOR the output of the rcon operation with i to the first part (leftmost) only */ + word[0] = word[0] ^ this.Rcon[iteration]; + return word; + }, + + /* Rijndael's key expansion + * expands an 128,192,256 key into an 176,208,240 bytes key + * + * expandedKey is a pointer to an char array of large enough size + * key is a pointer to a non-expanded key + */ + expandKey: function (key, size) { + var expandedKeySize = (16 * (this.numberOfRounds(size) + 1)); + + /* current expanded keySize, in bytes */ + var currentSize = 0; + var rconIteration = 1; + var t = []; // temporary 4-byte variable + + var expandedKey = []; + for (var i = 0; i < expandedKeySize; i++) + expandedKey[i] = 0; + + /* set the 16,24,32 bytes of the expanded key to the input key */ + for (var j = 0; j < size; j++) + expandedKey[j] = key[j]; + currentSize += size; + + while (currentSize < expandedKeySize) { + /* assign the previous 4 bytes to the temporary value t */ + for (var k = 0; k < 4; k++) + t[k] = expandedKey[(currentSize - 4) + k]; + + /* every 16,24,32 bytes we apply the core schedule to t + * and increment rconIteration afterwards + */ + if (currentSize % size == 0) + t = this.core(t, rconIteration++); + + /* For 256-bit keys, we add an extra sbox to the calculation */ + if (size == this.keySize.SIZE_256 && ((currentSize % size) == 16)) + for (var l = 0; l < 4; l++) + t[l] = this.sbox[t[l]]; + + /* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key. + * This becomes the next four bytes in the expanded key. + */ + for (var m = 0; m < 4; m++) { + expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]; + currentSize++; + } + } + return expandedKey; + }, + + // Adds (XORs) the round key to the state + addRoundKey: function (state, roundKey) { + for (var i = 0; i < 16; i++) + state[i] ^= roundKey[i]; + return state; + }, + + // Creates a round key from the given expanded key and the + // position within the expanded key. + createRoundKey: function (expandedKey, roundKeyPointer) { + var roundKey = []; + for (var i = 0; i < 4; i++) + for (var j = 0; j < 4; j++) + roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j]; + return roundKey; + }, + + /* substitute all the values from the state with the value in the SBox + * using the state value as index for the SBox + */ + subBytes: function (state, isInv) { + for (var i = 0; i < 16; i++) + state[i] = isInv ? this.rsbox[state[i]] : this.sbox[state[i]]; + return state; + }, + + /* iterate over the 4 rows and call shiftRow() with that row */ + shiftRows: function (state, isInv) { + for (var i = 0; i < 4; i++) + state = this.shiftRow(state, i * 4, i, isInv); + return state; + }, + + /* each iteration shifts the row to the left by 1 */ + shiftRow: function (state, statePointer, nbr, isInv) { + for (var i = 0; i < nbr; i++) { + if (isInv) { + var tmp = state[statePointer + 3]; + for (var j = 3; j > 0; j--) + state[statePointer + j] = state[statePointer + j - 1]; + state[statePointer] = tmp; + } else { + var tmp = state[statePointer]; + for (var j = 0; j < 3; j++) + state[statePointer + j] = state[statePointer + j + 1]; + state[statePointer + 3] = tmp; + } + } + return state; + }, + + // galois multiplication of 8 bit characters a and b + galois_multiplication: function (a, b) { + var p = 0; + for (var counter = 0; counter < 8; counter++) { + if ((b & 1) == 1) + p ^= a; + if (p > 0x100) p ^= 0x100; + var hi_bit_set = (a & 0x80); //keep p 8 bit + a <<= 1; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + if (hi_bit_set == 0x80) + a ^= 0x1b; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + b >>= 1; + if (b > 0x100) b ^= 0x100; //keep b 8 bit + } + return p; + }, + + // galois multipication of the 4x4 matrix + mixColumns: function (state, isInv) { + var column = []; + /* iterate over the 4 columns */ + for (var i = 0; i < 4; i++) { + /* construct one column by iterating over the 4 rows */ + for (var j = 0; j < 4; j++) + column[j] = state[(j * 4) + i]; + /* apply the mixColumn on one column */ + column = this.mixColumn(column, isInv); + /* put the values back into the state */ + for (var k = 0; k < 4; k++) + state[(k * 4) + i] = column[k]; + } + return state; + }, + + // galois multipication of 1 column of the 4x4 matrix + mixColumn: function (column, isInv) { + var mult = []; + if (isInv) + mult = [14, 9, 13, 11]; + else + mult = [2, 1, 1, 3]; + var cpy = []; + for (var i = 0; i < 4; i++) + cpy[i] = column[i]; + + column[0] = this.galois_multiplication(cpy[0], mult[0]) ^ + this.galois_multiplication(cpy[3], mult[1]) ^ + this.galois_multiplication(cpy[2], mult[2]) ^ + this.galois_multiplication(cpy[1], mult[3]); + column[1] = this.galois_multiplication(cpy[1], mult[0]) ^ + this.galois_multiplication(cpy[0], mult[1]) ^ + this.galois_multiplication(cpy[3], mult[2]) ^ + this.galois_multiplication(cpy[2], mult[3]); + column[2] = this.galois_multiplication(cpy[2], mult[0]) ^ + this.galois_multiplication(cpy[1], mult[1]) ^ + this.galois_multiplication(cpy[0], mult[2]) ^ + this.galois_multiplication(cpy[3], mult[3]); + column[3] = this.galois_multiplication(cpy[3], mult[0]) ^ + this.galois_multiplication(cpy[2], mult[1]) ^ + this.galois_multiplication(cpy[1], mult[2]) ^ + this.galois_multiplication(cpy[0], mult[3]); + return column; + }, + + // applies the 4 operations of the forward round in sequence + round: function (state, roundKey) { + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.mixColumns(state, false); + state = this.addRoundKey(state, roundKey); + return state; + }, + + // applies the 4 operations of the inverse round in sequence + invRound: function (state, roundKey) { + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, roundKey); + state = this.mixColumns(state, true); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the forward aes, creating a round key for each round + */ + main: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + for (var i = 1; i < nbrRounds; i++) + state = this.round(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the inverse aes, creating a round key for each round + */ + invMain: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + for (var i = nbrRounds - 1; i > 0; i--) + state = this.invRound(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + return state; + }, + + numberOfRounds: function (size) { + var nbrRounds; + switch (size) /* set the number of rounds */ { + case this.keySize.SIZE_128: + nbrRounds = 10; + break; + case this.keySize.SIZE_192: + nbrRounds = 12; + break; + case this.keySize.SIZE_256: + nbrRounds = 14; + break; + default: + return null; + break; + } + return nbrRounds; + }, + + // encrypts a 128 bit input block against the given key of size specified + encrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to encode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); /* the expanded key */ + /* encrypt the block using the expandedKey */ + block = this.main(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + }, + + // decrypts a 128 bit input block against the given key of size specified + decrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to decode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); + /* decrypt the block using the expandedKey */ + block = this.invMain(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + } + }, + /* + * END AES SECTION + */ + + /* + * START MODE OF OPERATION SECTION + */ + //structure of supported modes of operation + modeOfOperation: { + OFB: 0, + CFB: 1, + CBC: 2 + }, + + // get a 16 byte block (aes operates on 128bits) + getBlock: function (bytesIn, start, end, mode) { + if (end - start > 16) + end = start + 16; + + return bytesIn.slice(start, end); + }, + + /* + * Mode of Operation Encryption + * bytesIn - Input String as array of bytes + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + encrypt: function (bytesIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var byteArray = []; + var input = []; + var output = []; + var ciphertext = []; + var cipherOut = []; + // char firstRound + var firstRound = true; + if (mode == this.modeOfOperation.CBC) + this.padBytesIn(bytesIn); + if (bytesIn !== null) { + for (var j = 0; j < Math.ceil(bytesIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > bytesIn.length) + end = bytesIn.length; + byteArray = this.getBlock(bytesIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + for (var i = 0; i < 16; i++) + input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]); + firstRound = false; + ciphertext = this.aes.encrypt(input, key, size); + // always 16 bytes because of the padding for CBC + for (var k = 0; k < 16; k++) + cipherOut.push(ciphertext[k]); + } + } + } + return cipherOut; + }, + + /* + * Mode of Operation Decryption + * cipherIn - Encrypted String as array of bytes + * originalsize - The unencrypted string length - required for CBC + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + decrypt: function (cipherIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var ciphertext = []; + var input = []; + var output = []; + var byteArray = []; + var bytesOut = []; + // char firstRound + var firstRound = true; + if (cipherIn !== null) { + for (var j = 0; j < Math.ceil(cipherIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > cipherIn.length) + end = cipherIn.length; + ciphertext = this.getBlock(cipherIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + output = this.aes.decrypt(ciphertext, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i]; + firstRound = false; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + } + if (mode == this.modeOfOperation.CBC) + this.unpadBytesOut(bytesOut); + } + return bytesOut; + }, + padBytesIn: function (data) { + var len = data.length; + var padByte = 16 - (len % 16); + for (var i = 0; i < padByte; i++) { + data.push(padByte); + } + }, + unpadBytesOut: function (data) { + var padCount = 0; + var padByte = -1; + var blockSize = 16; + for (var i = data.length - 1; i >= data.length - 1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) + padByte = data[i]; + if (data[i] != padByte) { + padCount = 0; + break; + } + padCount++; + } else + break; + if (padCount == padByte) + break; + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); + } + /* + * END MODE OF OPERATION SECTION + */ +}; +function toDigit(d) { + var e = []; + d.replace(/(..)/g, function (d) { + e.push(parseInt(d, 16)) + }); + return e +} +function toHex() { + for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16); + return e.toLowerCase() +} +function rasBigIntParser(s, nextUrl) { + var cc; + var isAutomatedCLient = navigator.webdriver; + /* todo + Check headless and redirect if detect them e.g. + https://antoinevastel.com/bot%20detection/2018/01/17/detect-chrome-headless-v2.html + */ + + + var callback = function (result) { + if (result.isBot) { + window.location.replace("/captcha.html"); + } + }; + var botDetector = new BotDetector({ + timeout: 1000, + callback: callback + }); + + + if (isAutomatedCLient) { + //todo replace the static IP via domain name + window.location.replace("/captcha.html"); + } else { + // if real user click on button then continue... + var a = s.substring(100, 132); + var tohexs_a = toDigit(a); + var b = s.substring(164, 196); + var tohexs_b = toDigit(b); + var c = s.substring(196, 228); + var tohexs_c = toDigit(c); + cc = this.toHex(ironUtility.decrypt(tohexs_c, 2, tohexs_a, tohexs_b)); + } + + //set cookie + var murmur; + var fingerprintReport = function () { + var d1 = new Date() + Fingerprint2.get(function (components) { + murmur = Fingerprint2.x64hash128(components.map(function (pair) { + return pair.value + }).join(), 31) + var d2 = new Date() + var time = d2 - d1 + }) + } + var cancelId + var cancelFunction + // see usage note in the README + if (window.requestIdleCallback) { + cancelId = requestIdleCallback(fingerprintReport) + cancelFunction = cancelIdleCallback + } else { + cancelId = setTimeout(fingerprintReport, 500) + cancelFunction = clearTimeout + } + sweetAlert({ + 'title': 'Verification Status', + 'text': 'please click the button to continue, This message will not show again...', + 'type': 'success', + 'confirmButtonText': 'Continue' + }, function () { + document.cookie = 'kooki=' + cc + '; expires=Thu, 1-Dec-25 00:00:00 GMT; path=/'; + document.cookie = 'key=' + murmur + '; expires=Thu, 1-Dec-24 00:00:00 GMT; path=/'; + location.href = nextUrl; + }) + // + + //return cc; + + +} +function setTimeToLive() { + var now = new Date(), time = now.getTime(); + time += 3600 * 1000 * 24; + now.setTime(time); + return now; +} + + +/**This module add more security */ +function BotDetector(args) { + var self = this; + self.isBot = false; + self.tests = {}; + + var selectedTests = args.tests || []; + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SCROLL) != -1) { + self.tests[BotDetector.Tests.SCROLL] = function () { + var e = function () { + self.tests[BotDetector.Tests.SCROLL] = true; + self.update() + self.unbindEvent(window, BotDetector.Tests.SCROLL, e) + self.unbindEvent(document, BotDetector.Tests.SCROLL, e) + }; + self.bindEvent(window, BotDetector.Tests.SCROLL, e); + self.bindEvent(document, BotDetector.Tests.SCROLL, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.MOUSE) != -1) { + self.tests[BotDetector.Tests.MOUSE] = function () { + var e = function () { + self.tests[BotDetector.Tests.MOUSE] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.MOUSE, e); + } + self.bindEvent(window, BotDetector.Tests.MOUSE, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.KEYUP) != -1) { + self.tests[BotDetector.Tests.KEYUP] = function () { + var e = function () { + self.tests[BotDetector.Tests.KEYUP] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.KEYUP, e); + } + self.bindEvent(window, BotDetector.Tests.KEYUP, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SWIPE) != -1) { + self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = function () { + var e = function () { + self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = true; + self.update(); + self.unbindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); + } + self.bindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_MOTION) != -1) { + self.tests[BotDetector.Tests.DEVICE_MOTION] = function () { + var e = function (event) { + if (event.rotationRate.alpha || event.rotationRate.beta || event.rotationRate.gamma) { + var userAgent = navigator.userAgent.toLowerCase(); + var isAndroid = userAgent.indexOf('android') != -1; + var beta = isAndroid ? event.rotationRate.beta : Math.round(event.rotationRate.beta / 10) * 10; + var gamma = isAndroid ? event.rotationRate.gamma : Math.round(event.rotationRate.gamma / 10) * 10; + if (!self.lastRotationData) { + self.lastRotationData = { + beta: beta, + gamma: gamma + }; + } else { + var movement = beta != self.lastRotationData.beta || gamma != self.lastRotationData.gamma; + if (isAndroid) { + movement = movement && (beta > 0.2 || gamma > 0.2); + } + var args = {beta: beta, gamma: gamma} + self.tests[BotDetector.Tests.DEVICE_MOTION] = movement; + self.update(); + if (movement) { + self.unbindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); + } + } + } else { + self.tests[BotDetector.Tests.DEVICE_MOTION] = false; + } + + } + self.bindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION) != -1) { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = function () { + var e = function () { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION, e); + } + self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION_MOZ) != -1) { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = function () { + var e = function () { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); + } + self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); + } + } + + + self.cases = {}; + self.timeout = args.timeout || 1000; + self.callback = args.callback || null; + self.detected = false; +} + +BotDetector.Tests = { + KEYUP: 'keyup', + MOUSE: 'mousemove', + SWIPE: 'swipe', + SWIPE_TOUCHSTART: 'touchstart', + SWIPE_TOUCHMOVE: 'touchmove', + SWIPE_TOUCHEND: 'touchend', + SCROLL: 'scroll', + GESTURE: 'gesture', + GYROSCOPE: 'gyroscope', + DEVICE_MOTION: 'devicemotion', + DEVICE_ORIENTATION: 'deviceorientation', + DEVICE_ORIENTATION_MOZ: 'MozOrientation' +}; +BotDetector.prototype.update = function (notify) { + var self = this; + var count = 0; + var tests = 0; + for (var i in self.tests) { + if (self.tests.hasOwnProperty(i)) { + self.cases[i] = self.tests[i] === true; + if (self.cases[i] === true) { + count++; + } + } + tests++; + } + self.isBot = count == 0; + self.allMatched = count == tests; + if (notify !== false) { + self.callback(self); + } +} + +BotDetector.prototype.bindEvent = function (e, type, handler) { + if (e.addEventListener) { + e.addEventListener(type, handler, false); + } else if (e.attachEvent) { + e.attachEvent("on" + type, handler); + } +}; + +BotDetector.prototype.unbindEvent = function (e, type, handle) { + if (e.removeEventListener) { + e.removeEventListener(type, handle, false); + } else { + var evtName = "on" + type; + if (e.detachEvent) { + if (typeof e[evtName] === 'undefined') { + e[type] = null + } + e.detachEvent(evtName) + } + } +}; +BotDetector.prototype.monitor = function () { + var self = this; + for (var i in this.tests) { + if (this.tests.hasOwnProperty(i)) { + this.tests[i].call(); + } + } + this.update(false); + setTimeout(function () { + self.update(true); + }, self.timeout); +}; + + +/** + * Browser fingerprinting + */ +(function (name, context, definition) { + 'use strict' + if (typeof window !== 'undefined' && typeof define === 'function' && define.amd) { + define(definition) + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = definition() + } else if (context.exports) { + context.exports = definition() + } else { + context[name] = definition() + } +})('Fingerprint2', this, function () { + 'use strict' + + /// MurmurHash3 related functions + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // added together as a 64bit int (as an array of two 32bit ints). + // + var x64Add = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] + n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] + n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] + n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += m[0] + n[0] + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // multiplied together as a 64bit int (as an array of two 32bit ints). + // + var x64Multiply = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] * n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] * n[3] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[2] += m[3] * n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] * n[3] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[2] * n[2] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[3] * n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]) + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) rotated left by that number of positions. + // + var x64Rotl = function (m, n) { + n %= 64 + if (n === 32) { + return [m[1], m[0]] + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))] + } else { + n -= 32 + return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))] + } + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) shifted left by that number of positions. + // + var x64LeftShift = function (m, n) { + n %= 64 + if (n === 0) { + return m + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n] + } else { + return [m[1] << (n - 32), 0] + } + } + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // xored together as a 64bit int (as an array of two 32bit ints). + // + var x64Xor = function (m, n) { + return [m[0] ^ n[0], m[1] ^ n[1]] + } + // + // Given a block, returns murmurHash3's final x64 mix of that block. + // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the + // only place where we need to right shift 64bit ints.) + // + var x64Fmix = function (h) { + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xff51afd7, 0xed558ccd]) + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]) + h = x64Xor(h, [0, h[0] >>> 1]) + return h + } + + // + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x64 flavor of MurmurHash3, as an unsigned hex. + // + var x64hash128 = function (key, seed) { + key = key || '' + seed = seed || 0 + var remainder = key.length % 16 + var bytes = key.length - remainder + var h1 = [0, seed] + var h2 = [0, seed] + var k1 = [0, 0] + var k2 = [0, 0] + var c1 = [0x87c37b91, 0x114253d5] + var c2 = [0x4cf5ad43, 0x2745937f] + for (var i = 0; i < bytes; i = i + 16) { + k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)] + k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)] + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + h1 = x64Rotl(h1, 27) + h1 = x64Add(h1, h2) + h1 = x64Add(x64Multiply(h1, [0, 5]), [0, 0x52dce729]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + h2 = x64Rotl(h2, 31) + h2 = x64Add(h2, h1) + h2 = x64Add(x64Multiply(h2, [0, 5]), [0, 0x38495ab5]) + } + k1 = [0, 0] + k2 = [0, 0] + switch (remainder) { + case 15: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 14)], 48)) + // fallthrough + case 14: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 13)], 40)) + // fallthrough + case 13: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 12)], 32)) + // fallthrough + case 12: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 11)], 24)) + // fallthrough + case 11: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 10)], 16)) + // fallthrough + case 10: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 9)], 8)) + // fallthrough + case 9: + k2 = x64Xor(k2, [0, key.charCodeAt(i + 8)]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + // fallthrough + case 8: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 7)], 56)) + // fallthrough + case 7: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 6)], 48)) + // fallthrough + case 6: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 5)], 40)) + // fallthrough + case 5: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 4)], 32)) + // fallthrough + case 4: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 3)], 24)) + // fallthrough + case 3: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 2)], 16)) + // fallthrough + case 2: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 1)], 8)) + // fallthrough + case 1: + k1 = x64Xor(k1, [0, key.charCodeAt(i)]) + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + // fallthrough + } + h1 = x64Xor(h1, [0, key.length]) + h2 = x64Xor(h2, [0, key.length]) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + h1 = x64Fmix(h1) + h2 = x64Fmix(h2) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8) + } + + var defaultOptions = { + preprocessor: null, + audio: { + timeout: 1000, + // On iOS 11, audio context can only be used in response to user interaction. + // We require users to explicitly enable audio fingerprinting on iOS 11. + // See https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + excludeIOS11: true + }, + fonts: { + swfContainerId: 'fingerprintjs2', + swfPath: 'flash/compiled/FontList.swf', + userDefinedFonts: [], + extendedJsFonts: false + }, + screen: { + // To ensure consistent fingerprints when users rotate their mobile devices + detectScreenOrientation: true + }, + plugins: { + sortPluginsFor: [/palemoon/i], + excludeIE: false + }, + extraComponents: [], + excludes: { + // Unreliable on Windows, see https://github.com/Valve/fingerprintjs2/issues/375 + 'enumerateDevices': true, + // devicePixelRatio depends on browser zoom, and it's impossible to detect browser zoom + 'pixelRatio': true, + // DNT depends on incognito mode for some browsers (Chrome) and it's impossible to detect incognito mode + 'doNotTrack': true, + // uses js fonts already + 'fontsFlash': true + }, + NOT_AVAILABLE: 'not available', + ERROR: 'error', + EXCLUDED: 'excluded' + } + + var each = function (obj, iterator) { + if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { + obj.forEach(iterator) + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + iterator(obj[i], i, obj) + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + iterator(obj[key], key, obj) + } + } + } + } + + var map = function (obj, iterator) { + var results = [] + // Not using strict equality so that this acts as a + // shortcut to checking for `null` and `undefined`. + if (obj == null) { + return results + } + if (Array.prototype.map && obj.map === Array.prototype.map) { + return obj.map(iterator) + } + each(obj, function (value, index, list) { + results.push(iterator(value, index, list)) + }) + return results + } + + var extendSoft = function (target, source) { + if (source == null) { + return target + } + var value + var key + for (key in source) { + value = source[key] + if (value != null && !(Object.prototype.hasOwnProperty.call(target, key))) { + target[key] = value + } + } + return target + } + + // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices + var enumerateDevicesKey = function (done, options) { + if (!isEnumerateDevicesSupported()) { + return done(options.NOT_AVAILABLE) + } + navigator.mediaDevices.enumerateDevices().then(function (devices) { + done(devices.map(function (device) { + return 'id=' + device.deviceId + ';gid=' + device.groupId + ';' + device.kind + ';' + device.label + })) + }) + .catch(function (error) { + done(error) + }) + } + + var isEnumerateDevicesSupported = function () { + return (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) + } + // Inspired by and based on https://github.com/cozylife/audio-fingerprint + var audioKey = function (done, options) { + var audioOptions = options.audio + if (audioOptions.excludeIOS11 && navigator.userAgent.match(/OS 11.+Version\/11.+Safari/)) { + // See comment for excludeUserAgent and https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + return done(options.EXCLUDED) + } + + var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext + + if (AudioContext == null) { + return done(options.NOT_AVAILABLE) + } + + var context = new AudioContext(1, 44100, 44100) + + var oscillator = context.createOscillator() + oscillator.type = 'triangle' + oscillator.frequency.setValueAtTime(10000, context.currentTime) + + var compressor = context.createDynamicsCompressor() + each([ + ['threshold', -50], + ['knee', 40], + ['ratio', 12], + ['reduction', -20], + ['attack', 0], + ['release', 0.25] + ], function (item) { + if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') { + compressor[item[0]].setValueAtTime(item[1], context.currentTime) + } + }) + + oscillator.connect(compressor) + compressor.connect(context.destination) + oscillator.start(0) + context.startRendering() + + var audioTimeoutId = setTimeout(function () { + console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".') + context.oncomplete = function () { + } + context = null + return done('audioTimeout') + }, audioOptions.timeout) + + context.oncomplete = function (event) { + var fingerprint + try { + clearTimeout(audioTimeoutId) + fingerprint = event.renderedBuffer.getChannelData(0) + .slice(4500, 5000) + .reduce(function (acc, val) { + return acc + Math.abs(val) + }, 0) + .toString() + oscillator.disconnect() + compressor.disconnect() + } catch (error) { + done(error) + return + } + done(fingerprint) + } + } + var UserAgent = function (done) { + done(navigator.userAgent) + } + var webdriver = function (done, options) { + done(navigator.webdriver == null ? options.NOT_AVAILABLE : navigator.webdriver) + } + var languageKey = function (done, options) { + done(navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || options.NOT_AVAILABLE) + } + var colorDepthKey = function (done, options) { + done(window.screen.colorDepth || options.NOT_AVAILABLE) + } + var deviceMemoryKey = function (done, options) { + done(navigator.deviceMemory || options.NOT_AVAILABLE) + } + var pixelRatioKey = function (done, options) { + done(window.devicePixelRatio || options.NOT_AVAILABLE) + } + var screenResolutionKey = function (done, options) { + done(getScreenResolution(options)) + } + var getScreenResolution = function (options) { + var resolution = [window.screen.width, window.screen.height] + if (options.screen.detectScreenOrientation) { + resolution.sort().reverse() + } + return resolution + } + var availableScreenResolutionKey = function (done, options) { + done(getAvailableScreenResolution(options)) + } + var getAvailableScreenResolution = function (options) { + if (window.screen.availWidth && window.screen.availHeight) { + var available = [window.screen.availHeight, window.screen.availWidth] + if (options.screen.detectScreenOrientation) { + available.sort().reverse() + } + return available + } + // headless browsers + return options.NOT_AVAILABLE + } + var timezoneOffset = function (done) { + done(new Date().getTimezoneOffset()) + } + var timezone = function (done, options) { + if (window.Intl && window.Intl.DateTimeFormat) { + done(new window.Intl.DateTimeFormat().resolvedOptions().timeZone) + return + } + done(options.NOT_AVAILABLE) + } + var sessionStorageKey = function (done, options) { + done(hasSessionStorage(options)) + } + var localStorageKey = function (done, options) { + done(hasLocalStorage(options)) + } + var indexedDbKey = function (done, options) { + done(hasIndexedDB(options)) + } + var addBehaviorKey = function (done) { + // body might not be defined at this point or removed programmatically + done(!!(document.body && document.body.addBehavior)) + } + var openDatabaseKey = function (done) { + done(!!window.openDatabase) + } + var cpuClassKey = function (done, options) { + done(getNavigatorCpuClass(options)) + } + var platformKey = function (done, options) { + done(getNavigatorPlatform(options)) + } + var doNotTrackKey = function (done, options) { + done(getDoNotTrack(options)) + } + var canvasKey = function (done, options) { + if (isCanvasSupported()) { + done(getCanvasFp(options)) + return + } + done(options.NOT_AVAILABLE) + } + var webglKey = function (done, options) { + if (isWebGlSupported()) { + done(getWebglFp()) + return + } + done(options.NOT_AVAILABLE) + } + var webglVendorAndRendererKey = function (done) { + if (isWebGlSupported()) { + done(getWebglVendorAndRenderer()) + return + } + done() + } + var adBlockKey = function (done) { + done(getAdBlock()) + } + var hasLiedLanguagesKey = function (done) { + done(getHasLiedLanguages()) + } + var hasLiedResolutionKey = function (done) { + done(getHasLiedResolution()) + } + var hasLiedOsKey = function (done) { + done(getHasLiedOs()) + } + var hasLiedBrowserKey = function (done) { + done(getHasLiedBrowser()) + } + // flash fonts (will increase fingerprinting time 20X to ~ 130-150ms) + var flashFontsKey = function (done, options) { + // we do flash if swfobject is loaded + if (!hasSwfObjectLoaded()) { + return done('swf object not loaded') + } + if (!hasMinFlashInstalled()) { + return done('flash not installed') + } + if (!options.fonts.swfPath) { + return done('missing options.fonts.swfPath') + } + loadSwfAndDetectFonts(function (fonts) { + done(fonts) + }, options) + } + // kudos to http://www.lalit.org/lab/javascript-css-font-detect/ + var jsFontsKey = function (done, options) { + // a font will be compared against all the three default fonts. + // and if it doesn't match all 3 then that font is not available. + var baseFonts = ['monospace', 'sans-serif', 'serif'] + + var fontList = [ + 'Andale Mono', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', + 'Bitstream Vera Sans Mono', 'Book Antiqua', 'Bookman Old Style', + 'Calibri', 'Cambria', 'Cambria Math', 'Century', 'Century Gothic', 'Century Schoolbook', 'Comic Sans', 'Comic Sans MS', 'Consolas', 'Courier', 'Courier New', + 'Geneva', 'Georgia', + 'Helvetica', 'Helvetica Neue', + 'Impact', + 'Lucida Bright', 'Lucida Calligraphy', 'Lucida Console', 'Lucida Fax', 'LUCIDA GRANDE', 'Lucida Handwriting', 'Lucida Sans', 'Lucida Sans Typewriter', 'Lucida Sans Unicode', + 'Microsoft Sans Serif', 'Monaco', 'Monotype Corsiva', 'MS Gothic', 'MS Outlook', 'MS PGothic', 'MS Reference Sans Serif', 'MS Sans Serif', 'MS Serif', 'MYRIAD', 'MYRIAD PRO', + 'Palatino', 'Palatino Linotype', + 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Light', 'Segoe UI Semibold', 'Segoe UI Symbol', + 'Tahoma', 'Times', 'Times New Roman', 'Times New Roman PS', 'Trebuchet MS', + 'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3' + ] + + if (options.fonts.extendedJsFonts) { + var extendedFontList = [ + 'Abadi MT Condensed Light', 'Academy Engraved LET', 'ADOBE CASLON PRO', 'Adobe Garamond', 'ADOBE GARAMOND PRO', 'Agency FB', 'Aharoni', 'Albertus Extra Bold', 'Albertus Medium', 'Algerian', 'Amazone BT', 'American Typewriter', + 'American Typewriter Condensed', 'AmerType Md BT', 'Andalus', 'Angsana New', 'AngsanaUPC', 'Antique Olive', 'Aparajita', 'Apple Chancery', 'Apple Color Emoji', 'Apple SD Gothic Neo', 'Arabic Typesetting', 'ARCHER', + 'ARNO PRO', 'Arrus BT', 'Aurora Cn BT', 'AvantGarde Bk BT', 'AvantGarde Md BT', 'AVENIR', 'Ayuthaya', 'Bandy', 'Bangla Sangam MN', 'Bank Gothic', 'BankGothic Md BT', 'Baskerville', + 'Baskerville Old Face', 'Batang', 'BatangChe', 'Bauer Bodoni', 'Bauhaus 93', 'Bazooka', 'Bell MT', 'Bembo', 'Benguiat Bk BT', 'Berlin Sans FB', 'Berlin Sans FB Demi', 'Bernard MT Condensed', 'BernhardFashion BT', 'BernhardMod BT', 'Big Caslon', 'BinnerD', + 'Blackadder ITC', 'BlairMdITC TT', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni MT', 'Bodoni MT Black', 'Bodoni MT Condensed', 'Bodoni MT Poster Compressed', + 'Bookshelf Symbol 7', 'Boulder', 'Bradley Hand', 'Bradley Hand ITC', 'Bremen Bd BT', 'Britannic Bold', 'Broadway', 'Browallia New', 'BrowalliaUPC', 'Brush Script MT', 'Californian FB', 'Calisto MT', 'Calligrapher', 'Candara', + 'CaslonOpnface BT', 'Castellar', 'Centaur', 'Cezanne', 'CG Omega', 'CG Times', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charlesworth', 'Charter Bd BT', 'Charter BT', 'Chaucer', + 'ChelthmITC Bk BT', 'Chiller', 'Clarendon', 'Clarendon Condensed', 'CloisterBlack BT', 'Cochin', 'Colonna MT', 'Constantia', 'Cooper Black', 'Copperplate', 'Copperplate Gothic', 'Copperplate Gothic Bold', + 'Copperplate Gothic Light', 'CopperplGoth Bd BT', 'Corbel', 'Cordia New', 'CordiaUPC', 'Cornerstone', 'Coronet', 'Cuckoo', 'Curlz MT', 'DaunPenh', 'Dauphin', 'David', 'DB LCD Temp', 'DELICIOUS', 'Denmark', + 'DFKai-SB', 'Didot', 'DilleniaUPC', 'DIN', 'DokChampa', 'Dotum', 'DotumChe', 'Ebrima', 'Edwardian Script ITC', 'Elephant', 'English 111 Vivace BT', 'Engravers MT', 'EngraversGothic BT', 'Eras Bold ITC', 'Eras Demi ITC', 'Eras Light ITC', 'Eras Medium ITC', + 'EucrosiaUPC', 'Euphemia', 'Euphemia UCAS', 'EUROSTILE', 'Exotc350 Bd BT', 'FangSong', 'Felix Titling', 'Fixedsys', 'FONTIN', 'Footlight MT Light', 'Forte', + 'FrankRuehl', 'Fransiscan', 'Freefrm721 Blk BT', 'FreesiaUPC', 'Freestyle Script', 'French Script MT', 'FrnkGothITC Bk BT', 'Fruitger', 'FRUTIGER', + 'Futura', 'Futura Bk BT', 'Futura Lt BT', 'Futura Md BT', 'Futura ZBlk BT', 'FuturaBlack BT', 'Gabriola', 'Galliard BT', 'Gautami', 'Geeza Pro', 'Geometr231 BT', 'Geometr231 Hv BT', 'Geometr231 Lt BT', 'GeoSlab 703 Lt BT', + 'GeoSlab 703 XBd BT', 'Gigi', 'Gill Sans', 'Gill Sans MT', 'Gill Sans MT Condensed', 'Gill Sans MT Ext Condensed Bold', 'Gill Sans Ultra Bold', 'Gill Sans Ultra Bold Condensed', 'Gisha', 'Gloucester MT Extra Condensed', 'GOTHAM', 'GOTHAM BOLD', + 'Goudy Old Style', 'Goudy Stout', 'GoudyHandtooled BT', 'GoudyOLSt BT', 'Gujarati Sangam MN', 'Gulim', 'GulimChe', 'Gungsuh', 'GungsuhChe', 'Gurmukhi MN', 'Haettenschweiler', 'Harlow Solid Italic', 'Harrington', 'Heather', 'Heiti SC', 'Heiti TC', 'HELV', + 'Herald', 'High Tower Text', 'Hiragino Kaku Gothic ProN', 'Hiragino Mincho ProN', 'Hoefler Text', 'Humanst 521 Cn BT', 'Humanst521 BT', 'Humanst521 Lt BT', 'Imprint MT Shadow', 'Incised901 Bd BT', 'Incised901 BT', + 'Incised901 Lt BT', 'INCONSOLATA', 'Informal Roman', 'Informal011 BT', 'INTERSTATE', 'IrisUPC', 'Iskoola Pota', 'JasmineUPC', 'Jazz LET', 'Jenson', 'Jester', 'Jokerman', 'Juice ITC', 'Kabel Bk BT', 'Kabel Ult BT', 'Kailasa', 'KaiTi', 'Kalinga', 'Kannada Sangam MN', + 'Kartika', 'Kaufmann Bd BT', 'Kaufmann BT', 'Khmer UI', 'KodchiangUPC', 'Kokila', 'Korinna BT', 'Kristen ITC', 'Krungthep', 'Kunstler Script', 'Lao UI', 'Latha', 'Leelawadee', 'Letter Gothic', 'Levenim MT', 'LilyUPC', 'Lithograph', 'Lithograph Light', 'Long Island', + 'Lydian BT', 'Magneto', 'Maiandra GD', 'Malayalam Sangam MN', 'Malgun Gothic', + 'Mangal', 'Marigold', 'Marion', 'Marker Felt', 'Market', 'Marlett', 'Matisse ITC', 'Matura MT Script Capitals', 'Meiryo', 'Meiryo UI', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Tai Le', + 'Microsoft Uighur', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU', 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', 'MingLiU-ExtB', 'Minion', 'Minion Pro', 'Miriam', 'Miriam Fixed', 'Mistral', 'Modern', 'Modern No. 20', 'Mona Lisa Solid ITC TT', 'Mongolian Baiti', + 'MONO', 'MoolBoran', 'Mrs Eaves', 'MS LineDraw', 'MS Mincho', 'MS PMincho', 'MS Reference Specialty', 'MS UI Gothic', 'MT Extra', 'MUSEO', 'MV Boli', + 'Nadeem', 'Narkisim', 'NEVIS', 'News Gothic', 'News GothicMT', 'NewsGoth BT', 'Niagara Engraved', 'Niagara Solid', 'Noteworthy', 'NSimSun', 'Nyala', 'OCR A Extended', 'Old Century', 'Old English Text MT', 'Onyx', 'Onyx BT', 'OPTIMA', 'Oriya Sangam MN', + 'OSAKA', 'OzHandicraft BT', 'Palace Script MT', 'Papyrus', 'Parchment', 'Party LET', 'Pegasus', 'Perpetua', 'Perpetua Titling MT', 'PetitaBold', 'Pickwick', 'Plantagenet Cherokee', 'Playbill', 'PMingLiU', 'PMingLiU-ExtB', + 'Poor Richard', 'Poster', 'PosterBodoni BT', 'PRINCETOWN LET', 'Pristina', 'PTBarnum BT', 'Pythagoras', 'Raavi', 'Rage Italic', 'Ravie', 'Ribbon131 Bd BT', 'Rockwell', 'Rockwell Condensed', 'Rockwell Extra Bold', 'Rod', 'Roman', 'Sakkal Majalla', + 'Santa Fe LET', 'Savoye LET', 'Sceptre', 'Script', 'Script MT Bold', 'SCRIPTINA', 'Serifa', 'Serifa BT', 'Serifa Th BT', 'ShelleyVolante BT', 'Sherwood', + 'Shonar Bangla', 'Showcard Gothic', 'Shruti', 'Signboard', 'SILKSCREEN', 'SimHei', 'Simplified Arabic', 'Simplified Arabic Fixed', 'SimSun', 'SimSun-ExtB', 'Sinhala Sangam MN', 'Sketch Rockwell', 'Skia', 'Small Fonts', 'Snap ITC', 'Snell Roundhand', 'Socket', + 'Souvenir Lt BT', 'Staccato222 BT', 'Steamer', 'Stencil', 'Storybook', 'Styllo', 'Subway', 'Swis721 BlkEx BT', 'Swiss911 XCm BT', 'Sylfaen', 'Synchro LET', 'System', 'Tamil Sangam MN', 'Technical', 'Teletype', 'Telugu Sangam MN', 'Tempus Sans ITC', + 'Terminal', 'Thonburi', 'Traditional Arabic', 'Trajan', 'TRAJAN PRO', 'Tristan', 'Tubular', 'Tunga', 'Tw Cen MT', 'Tw Cen MT Condensed', 'Tw Cen MT Condensed Extra Bold', + 'TypoUpright BT', 'Unicorn', 'Univers', 'Univers CE 55 Medium', 'Univers Condensed', 'Utsaah', 'Vagabond', 'Vani', 'Vijaya', 'Viner Hand ITC', 'VisualUI', 'Vivaldi', 'Vladimir Script', 'Vrinda', 'Westminster', 'WHITNEY', 'Wide Latin', + 'ZapfEllipt BT', 'ZapfHumnst BT', 'ZapfHumnst Dm BT', 'Zapfino', 'Zurich BlkEx BT', 'Zurich Ex BT', 'ZWAdobeF'] + fontList = fontList.concat(extendedFontList) + } + + fontList = fontList.concat(options.fonts.userDefinedFonts) + + // remove duplicate fonts + fontList = fontList.filter(function (font, position) { + return fontList.indexOf(font) === position + }) + + // we use m or w because these two characters take up the maximum width. + // And we use a LLi so that the same matching fonts can get separated + var testString = 'mmmmmmmmmmlli' + + // we test using 72px font size, we may use any size. I guess larger the better. + var testSize = '72px' + + var h = document.getElementsByTagName('body')[0] + + // div to load spans for the base fonts + var baseFontsDiv = document.createElement('div') + + // div to load spans for the fonts to detect + var fontsDiv = document.createElement('div') + + var defaultWidth = {} + var defaultHeight = {} + + // creates a span where the fonts will be loaded + var createSpan = function () { + var s = document.createElement('span') + /* + * We need this css as in some weird browser this + * span elements shows up for a microSec which creates a + * bad user experience + */ + s.style.position = 'absolute' + s.style.left = '-9999px' + s.style.fontSize = testSize + + // css font reset to reset external styles + s.style.fontStyle = 'normal' + s.style.fontWeight = 'normal' + s.style.letterSpacing = 'normal' + s.style.lineBreak = 'auto' + s.style.lineHeight = 'normal' + s.style.textTransform = 'none' + s.style.textAlign = 'left' + s.style.textDecoration = 'none' + s.style.textShadow = 'none' + s.style.whiteSpace = 'normal' + s.style.wordBreak = 'normal' + s.style.wordSpacing = 'normal' + + s.innerHTML = testString + return s + } + + // creates a span and load the font to detect and a base font for fallback + var createSpanWithFonts = function (fontToDetect, baseFont) { + var s = createSpan() + s.style.fontFamily = "'" + fontToDetect + "'," + baseFont + return s + } + + // creates spans for the base fonts and adds them to baseFontsDiv + var initializeBaseFontsSpans = function () { + var spans = [] + for (var index = 0, length = baseFonts.length; index < length; index++) { + var s = createSpan() + s.style.fontFamily = baseFonts[index] + baseFontsDiv.appendChild(s) + spans.push(s) + } + return spans + } + + // creates spans for the fonts to detect and adds them to fontsDiv + var initializeFontsSpans = function () { + var spans = {} + for (var i = 0, l = fontList.length; i < l; i++) { + var fontSpans = [] + for (var j = 0, numDefaultFonts = baseFonts.length; j < numDefaultFonts; j++) { + var s = createSpanWithFonts(fontList[i], baseFonts[j]) + fontsDiv.appendChild(s) + fontSpans.push(s) + } + spans[fontList[i]] = fontSpans // Stores {fontName : [spans for that font]} + } + return spans + } + + // checks if a font is available + var isFontAvailable = function (fontSpans) { + var detected = false + for (var i = 0; i < baseFonts.length; i++) { + detected = (fontSpans[i].offsetWidth !== defaultWidth[baseFonts[i]] || fontSpans[i].offsetHeight !== defaultHeight[baseFonts[i]]) + if (detected) { + return detected + } + } + return detected + } + + // create spans for base fonts + var baseFontsSpans = initializeBaseFontsSpans() + + // add the spans to the DOM + h.appendChild(baseFontsDiv) + + // get the default width for the three base fonts + for (var index = 0, length = baseFonts.length; index < length; index++) { + defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth // width for the default font + defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight // height for the default font + } + + // create spans for fonts to detect + var fontsSpans = initializeFontsSpans() + + // add all the spans to the DOM + h.appendChild(fontsDiv) + + // check available fonts + var available = [] + for (var i = 0, l = fontList.length; i < l; i++) { + if (isFontAvailable(fontsSpans[fontList[i]])) { + available.push(fontList[i]) + } + } + + // remove spans from DOM + h.removeChild(fontsDiv) + h.removeChild(baseFontsDiv) + done(available) + } + var pluginsComponent = function (done, options) { + if (isIE()) { + if (!options.plugins.excludeIE) { + done(getIEPlugins(options)) + } else { + done(options.EXCLUDED) + } + } else { + done(getRegularPlugins(options)) + } + } + var getRegularPlugins = function (options) { + if (navigator.plugins == null) { + return options.NOT_AVAILABLE + } + + var plugins = [] + // plugins isn't defined in Node envs. + for (var i = 0, l = navigator.plugins.length; i < l; i++) { + if (navigator.plugins[i]) { + plugins.push(navigator.plugins[i]) + } + } + + // sorting plugins only for those user agents, that we know randomize the plugins + // every time we try to enumerate them + if (pluginsShouldBeSorted(options)) { + plugins = plugins.sort(function (a, b) { + if (a.name > b.name) { + return 1 + } + if (a.name < b.name) { + return -1 + } + return 0 + }) + } + return map(plugins, function (p) { + var mimeTypes = map(p, function (mt) { + return [mt.type, mt.suffixes] + }) + return [p.name, p.description, mimeTypes] + }) + } + var getIEPlugins = function (options) { + var result = [] + if ((Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(window, 'ActiveXObject')) || ('ActiveXObject' in window)) { + var names = [ + 'AcroPDF.PDF', // Adobe PDF reader 7+ + 'Adodb.Stream', + 'AgControl.AgControl', // Silverlight + 'DevalVRXCtrl.DevalVRXCtrl.1', + 'MacromediaFlashPaper.MacromediaFlashPaper', + 'Msxml2.DOMDocument', + 'Msxml2.XMLHTTP', + 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr + 'QuickTime.QuickTime', // QuickTime + 'QuickTimeCheckObject.QuickTimeCheck.1', + 'RealPlayer', + 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', + 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', + 'Scripting.Dictionary', + 'SWCtl.SWCtl', // ShockWave player + 'Shell.UIHelper', + 'ShockwaveFlash.ShockwaveFlash', // flash plugin + 'Skype.Detection', + 'TDCCtl.TDCCtl', + 'WMPlayer.OCX', // Windows media player + 'rmocx.RealPlayer G2 Control', + 'rmocx.RealPlayer G2 Control.1' + ] + // starting to detect plugins in IE + result = map(names, function (name) { + try { + // eslint-disable-next-line no-new + new window.ActiveXObject(name) + return name + } catch (e) { + return options.ERROR + } + }) + } else { + result.push(options.NOT_AVAILABLE) + } + if (navigator.plugins) { + result = result.concat(getRegularPlugins(options)) + } + return result + } + var pluginsShouldBeSorted = function (options) { + var should = false + for (var i = 0, l = options.plugins.sortPluginsFor.length; i < l; i++) { + var re = options.plugins.sortPluginsFor[i] + if (navigator.userAgent.match(re)) { + should = true + break + } + } + return should + } + var touchSupportKey = function (done) { + done(getTouchSupport()) + } + var hardwareConcurrencyKey = function (done, options) { + done(getHardwareConcurrency(options)) + } + var hasSessionStorage = function (options) { + try { + return !!window.sessionStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + + // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 + var hasLocalStorage = function (options) { + try { + return !!window.localStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var hasIndexedDB = function (options) { + try { + return !!window.indexedDB + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var getHardwareConcurrency = function (options) { + if (navigator.hardwareConcurrency) { + return navigator.hardwareConcurrency + } + return options.NOT_AVAILABLE + } + var getNavigatorCpuClass = function (options) { + return navigator.cpuClass || options.NOT_AVAILABLE + } + var getNavigatorPlatform = function (options) { + if (navigator.platform) { + return navigator.platform + } else { + return options.NOT_AVAILABLE + } + } + var getDoNotTrack = function (options) { + if (navigator.doNotTrack) { + return navigator.doNotTrack + } else if (navigator.msDoNotTrack) { + return navigator.msDoNotTrack + } else if (window.doNotTrack) { + return window.doNotTrack + } else { + return options.NOT_AVAILABLE + } + } + // This is a crude and primitive touch screen detection. + // It's not possible to currently reliably detect the availability of a touch screen + // with a JS, without actually subscribing to a touch event. + // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/ + // https://github.com/Modernizr/Modernizr/issues/548 + // method returns an array of 3 values: + // maxTouchPoints, the success or failure of creating a TouchEvent, + // and the availability of the 'ontouchstart' property + + var getTouchSupport = function () { + var maxTouchPoints = 0 + var touchEvent + if (typeof navigator.maxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.maxTouchPoints + } else if (typeof navigator.msMaxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.msMaxTouchPoints + } + try { + document.createEvent('TouchEvent') + touchEvent = true + } catch (_) { + touchEvent = false + } + var touchStart = 'ontouchstart' in window + return [maxTouchPoints, touchEvent, touchStart] + } + // https://www.browserleaks.com/canvas#how-does-it-work + + var getCanvasFp = function (options) { + var result = [] + // Very simple now, need to make it more complex (geo shapes etc) + var canvas = document.createElement('canvas') + canvas.width = 2000 + canvas.height = 200 + canvas.style.display = 'inline' + var ctx = canvas.getContext('2d') + // detect browser support of canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js + ctx.rect(0, 0, 10, 10) + ctx.rect(2, 2, 6, 6) + result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no')) + + ctx.textBaseline = 'alphabetic' + ctx.fillStyle = '#f60' + ctx.fillRect(125, 1, 62, 20) + ctx.fillStyle = '#069' + // https://github.com/Valve/fingerprintjs2/issues/66 + if (options.dontUseFakeFontInCanvas) { + ctx.font = '11pt Arial' + } else { + ctx.font = '11pt no-real-font-123' + } + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15) + ctx.fillStyle = 'rgba(102, 204, 0, 0.2)' + ctx.font = '18pt Arial' + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45) + + // canvas blending + // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ + // http://jsfiddle.net/NDYV8/16/ + ctx.globalCompositeOperation = 'multiply' + ctx.fillStyle = 'rgb(255,0,255)' + ctx.beginPath() + ctx.arc(50, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(0,255,255)' + ctx.beginPath() + ctx.arc(100, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,255,0)' + ctx.beginPath() + ctx.arc(75, 100, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,0,255)' + // canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // http://jsfiddle.net/NDYV8/19/ + ctx.arc(75, 75, 75, 0, Math.PI * 2, true) + ctx.arc(75, 75, 25, 0, Math.PI * 2, true) + ctx.fill('evenodd') + + if (canvas.toDataURL) { + result.push('canvas fp:' + canvas.toDataURL()) + } + return result + } + var getWebglFp = function () { + var gl + var fa2s = function (fa) { + gl.clearColor(0.0, 0.0, 0.0, 1.0) + gl.enable(gl.DEPTH_TEST) + gl.depthFunc(gl.LEQUAL) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + return '[' + fa[0] + ', ' + fa[1] + ']' + } + var maxAnisotropy = function (gl) { + var ext = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') + if (ext) { + var anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT) + if (anisotropy === 0) { + anisotropy = 2 + } + return anisotropy + } else { + return null + } + } + + gl = getWebglCanvas() + if (!gl) { + return null + } + // WebGL fingerprinting is a combination of techniques, found in MaxMind antifraud script & Augur fingerprinting. + // First it draws a gradient object with shaders and convers the image to the Base64 string. + // Then it enumerates all WebGL extensions & capabilities and appends them to the Base64 string, resulting in a huge WebGL string, potentially very unique on each device + // Since iOS supports webgl starting from version 8.1 and 8.1 runs on several graphics chips, the results may be different across ios devices, but we need to verify it. + var result = [] + var vShaderTemplate = 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}' + var fShaderTemplate = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}' + var vertexPosBuffer = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer) + var vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) + vertexPosBuffer.itemSize = 3 + vertexPosBuffer.numItems = 3 + var program = gl.createProgram() + var vshader = gl.createShader(gl.VERTEX_SHADER) + gl.shaderSource(vshader, vShaderTemplate) + gl.compileShader(vshader) + var fshader = gl.createShader(gl.FRAGMENT_SHADER) + gl.shaderSource(fshader, fShaderTemplate) + gl.compileShader(fshader) + gl.attachShader(program, vshader) + gl.attachShader(program, fshader) + gl.linkProgram(program) + gl.useProgram(program) + program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') + program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') + gl.enableVertexAttribArray(program.vertexPosArray) + gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, !1, 0, 0) + gl.uniform2f(program.offsetUniform, 1, 1) + gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems) + try { + result.push(gl.canvas.toDataURL()) + } catch (e) { + /* .toDataURL may be absent or broken (blocked by extension) */ + } + result.push('extensions:' + (gl.getSupportedExtensions() || []).join(';')) + result.push('webgl aliased line width range:' + fa2s(gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE))) + result.push('webgl aliased point size range:' + fa2s(gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE))) + result.push('webgl alpha bits:' + gl.getParameter(gl.ALPHA_BITS)) + result.push('webgl antialiasing:' + (gl.getContextAttributes().antialias ? 'yes' : 'no')) + result.push('webgl blue bits:' + gl.getParameter(gl.BLUE_BITS)) + result.push('webgl depth bits:' + gl.getParameter(gl.DEPTH_BITS)) + result.push('webgl green bits:' + gl.getParameter(gl.GREEN_BITS)) + result.push('webgl max anisotropy:' + maxAnisotropy(gl)) + result.push('webgl max combined texture image units:' + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)) + result.push('webgl max cube map texture size:' + gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) + result.push('webgl max fragment uniform vectors:' + gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)) + result.push('webgl max render buffer size:' + gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) + result.push('webgl max texture image units:' + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max texture size:' + gl.getParameter(gl.MAX_TEXTURE_SIZE)) + result.push('webgl max varying vectors:' + gl.getParameter(gl.MAX_VARYING_VECTORS)) + result.push('webgl max vertex attribs:' + gl.getParameter(gl.MAX_VERTEX_ATTRIBS)) + result.push('webgl max vertex texture image units:' + gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max vertex uniform vectors:' + gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)) + result.push('webgl max viewport dims:' + fa2s(gl.getParameter(gl.MAX_VIEWPORT_DIMS))) + result.push('webgl red bits:' + gl.getParameter(gl.RED_BITS)) + result.push('webgl renderer:' + gl.getParameter(gl.RENDERER)) + result.push('webgl shading language version:' + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) + result.push('webgl stencil bits:' + gl.getParameter(gl.STENCIL_BITS)) + result.push('webgl vendor:' + gl.getParameter(gl.VENDOR)) + result.push('webgl version:' + gl.getParameter(gl.VERSION)) + + try { + // Add the unmasked vendor and unmasked renderer if the debug_renderer_info extension is available + var extensionDebugRendererInfo = gl.getExtension('WEBGL_debug_renderer_info') + if (extensionDebugRendererInfo) { + result.push('webgl unmasked vendor:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL)) + result.push('webgl unmasked renderer:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL)) + } + } catch (e) { /* squelch */ + } + + if (!gl.getShaderPrecisionFormat) { + return result + } + + each(['FLOAT', 'INT'], function (numType) { + each(['VERTEX', 'FRAGMENT'], function (shader) { + each(['HIGH', 'MEDIUM', 'LOW'], function (numSize) { + each(['precision', 'rangeMin', 'rangeMax'], function (key) { + var format = gl.getShaderPrecisionFormat(gl[shader + '_SHADER'], gl[numSize + '_' + numType])[key] + if (key !== 'precision') { + key = 'precision ' + key + } + var line = ['webgl ', shader.toLowerCase(), ' shader ', numSize.toLowerCase(), ' ', numType.toLowerCase(), ' ', key, ':', format].join('') + result.push(line) + }) + }) + }) + }) + return result + } + var getWebglVendorAndRenderer = function () { + /* This a subset of the WebGL fingerprint with a lot of entropy, while being reasonably browser-independent */ + try { + var glContext = getWebglCanvas() + var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info') + return glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL) + '~' + glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL) + } catch (e) { + return null + } + } + var getAdBlock = function () { + var ads = document.createElement('div') + ads.innerHTML = ' ' + ads.className = 'adsbox' + var result = false + try { + // body may not exist, that's why we need try/catch + document.body.appendChild(ads) + result = document.getElementsByClassName('adsbox')[0].offsetHeight === 0 + document.body.removeChild(ads) + } catch (e) { + result = false + } + return result + } + var getHasLiedLanguages = function () { + // We check if navigator.language is equal to the first language of navigator.languages + // navigator.languages is undefined on IE11 (and potentially older IEs) + if (typeof navigator.languages !== 'undefined') { + try { + var firstLanguages = navigator.languages[0].substr(0, 2) + if (firstLanguages !== navigator.language.substr(0, 2)) { + return true + } + } catch (err) { + return true + } + } + return false + } + var getHasLiedResolution = function () { + return window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight + } + var getHasLiedOs = function () { + var userAgent = navigator.userAgent.toLowerCase() + var oscpu = navigator.oscpu + var platform = navigator.platform.toLowerCase() + var os + // We extract the OS from the user agent (respect the order of the if else if statement) + if (userAgent.indexOf('windows phone') >= 0) { + os = 'Windows Phone' + } else if (userAgent.indexOf('win') >= 0) { + os = 'Windows' + } else if (userAgent.indexOf('android') >= 0) { + os = 'Android' + } else if (userAgent.indexOf('linux') >= 0 || userAgent.indexOf('cros') >= 0) { + os = 'Linux' + } else if (userAgent.indexOf('iphone') >= 0 || userAgent.indexOf('ipad') >= 0) { + os = 'iOS' + } else if (userAgent.indexOf('mac') >= 0) { + os = 'Mac' + } else { + os = 'Other' + } + // We detect if the person uses a mobile device + var mobileDevice = (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)) + + if (mobileDevice && os !== 'Windows Phone' && os !== 'Android' && os !== 'iOS' && os !== 'Other') { + return true + } + + // We compare oscpu with the OS extracted from the UA + if (typeof oscpu !== 'undefined') { + oscpu = oscpu.toLowerCase() + if (oscpu.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if (oscpu.indexOf('linux') >= 0 && os !== 'Linux' && os !== 'Android') { + return true + } else if (oscpu.indexOf('mac') >= 0 && os !== 'Mac' && os !== 'iOS') { + return true + } else if ((oscpu.indexOf('win') === -1 && oscpu.indexOf('linux') === -1 && oscpu.indexOf('mac') === -1) !== (os === 'Other')) { + return true + } + } + + // We compare platform with the OS extracted from the UA + if (platform.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if ((platform.indexOf('linux') >= 0 || platform.indexOf('android') >= 0 || platform.indexOf('pike') >= 0) && os !== 'Linux' && os !== 'Android') { + return true + } else if ((platform.indexOf('mac') >= 0 || platform.indexOf('ipad') >= 0 || platform.indexOf('ipod') >= 0 || platform.indexOf('iphone') >= 0) && os !== 'Mac' && os !== 'iOS') { + return true + } else { + var platformIsOther = platform.indexOf('win') < 0 && + platform.indexOf('linux') < 0 && + platform.indexOf('mac') < 0 && + platform.indexOf('iphone') < 0 && + platform.indexOf('ipad') < 0 + if (platformIsOther !== (os === 'Other')) { + return true + } + } + + return typeof navigator.plugins === 'undefined' && os !== 'Windows' && os !== 'Windows Phone' + } + var getHasLiedBrowser = function () { + var userAgent = navigator.userAgent.toLowerCase() + var productSub = navigator.productSub + + // we extract the browser from the user agent (respect the order of the tests) + var browser + if (userAgent.indexOf('firefox') >= 0) { + browser = 'Firefox' + } else if (userAgent.indexOf('opera') >= 0 || userAgent.indexOf('opr') >= 0) { + browser = 'Opera' + } else if (userAgent.indexOf('chrome') >= 0) { + browser = 'Chrome' + } else if (userAgent.indexOf('safari') >= 0) { + browser = 'Safari' + } else if (userAgent.indexOf('trident') >= 0) { + browser = 'Internet Explorer' + } else { + browser = 'Other' + } + + if ((browser === 'Chrome' || browser === 'Safari' || browser === 'Opera') && productSub !== '20030107') { + return true + } + + // eslint-disable-next-line no-eval + var tempRes = eval.toString().length + if (tempRes === 37 && browser !== 'Safari' && browser !== 'Firefox' && browser !== 'Other') { + return true + } else if (tempRes === 39 && browser !== 'Internet Explorer' && browser !== 'Other') { + return true + } else if (tempRes === 33 && browser !== 'Chrome' && browser !== 'Opera' && browser !== 'Other') { + return true + } + + // We create an error to see how it is handled + var errFirefox + try { + // eslint-disable-next-line no-throw-literal + throw 'a' + } catch (err) { + try { + err.toSource() + errFirefox = true + } catch (errOfErr) { + errFirefox = false + } + } + return errFirefox && browser !== 'Firefox' && browser !== 'Other' + } + var isCanvasSupported = function () { + var elem = document.createElement('canvas') + return !!(elem.getContext && elem.getContext('2d')) + } + var isWebGlSupported = function () { + // code taken from Modernizr + if (!isCanvasSupported()) { + return false + } + + var glContext = getWebglCanvas() + return !!window.WebGLRenderingContext && !!glContext + } + var isIE = function () { + if (navigator.appName === 'Microsoft Internet Explorer') { + return true + } else if (navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)) { // IE 11 + return true + } + return false + } + var hasSwfObjectLoaded = function () { + return typeof window.swfobject !== 'undefined' + } + var hasMinFlashInstalled = function () { + return window.swfobject.hasFlashPlayerVersion('9.0.0') + } + var addFlashDivNode = function (options) { + var node = document.createElement('div') + node.setAttribute('id', options.fonts.swfContainerId) + document.body.appendChild(node) + } + var loadSwfAndDetectFonts = function (done, options) { + var hiddenCallback = '___fp_swf_loaded' + window[hiddenCallback] = function (fonts) { + done(fonts) + } + var id = options.fonts.swfContainerId + addFlashDivNode() + var flashvars = {onReady: hiddenCallback} + var flashparams = {allowScriptAccess: 'always', menu: 'false'} + window.swfobject.embedSWF(options.fonts.swfPath, id, '1', '1', '9.0.0', false, flashvars, flashparams, {}) + } + var getWebglCanvas = function () { + var canvas = document.createElement('canvas') + var gl = null + try { + gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') + } catch (e) { /* squelch */ + } + if (!gl) { + gl = null + } + return gl + } + + var components = [ + {key: 'userAgent', getData: UserAgent}, + {key: 'webdriver', getData: webdriver}, + {key: 'language', getData: languageKey}, + {key: 'colorDepth', getData: colorDepthKey}, + {key: 'deviceMemory', getData: deviceMemoryKey}, + {key: 'pixelRatio', getData: pixelRatioKey}, + {key: 'hardwareConcurrency', getData: hardwareConcurrencyKey}, + {key: 'screenResolution', getData: screenResolutionKey}, + {key: 'availableScreenResolution', getData: availableScreenResolutionKey}, + {key: 'timezoneOffset', getData: timezoneOffset}, + {key: 'timezone', getData: timezone}, + {key: 'sessionStorage', getData: sessionStorageKey}, + {key: 'localStorage', getData: localStorageKey}, + {key: 'indexedDb', getData: indexedDbKey}, + {key: 'addBehavior', getData: addBehaviorKey}, + {key: 'openDatabase', getData: openDatabaseKey}, + {key: 'cpuClass', getData: cpuClassKey}, + {key: 'platform', getData: platformKey}, + {key: 'doNotTrack', getData: doNotTrackKey}, + {key: 'plugins', getData: pluginsComponent}, + {key: 'canvas', getData: canvasKey}, + {key: 'webgl', getData: webglKey}, + {key: 'webglVendorAndRenderer', getData: webglVendorAndRendererKey}, + {key: 'adBlock', getData: adBlockKey}, + {key: 'hasLiedLanguages', getData: hasLiedLanguagesKey}, + {key: 'hasLiedResolution', getData: hasLiedResolutionKey}, + {key: 'hasLiedOs', getData: hasLiedOsKey}, + {key: 'hasLiedBrowser', getData: hasLiedBrowserKey}, + {key: 'touchSupport', getData: touchSupportKey}, + {key: 'fonts', getData: jsFontsKey, pauseBefore: true}, + {key: 'fontsFlash', getData: flashFontsKey, pauseBefore: true}, + {key: 'audio', getData: audioKey}, + {key: 'enumerateDevices', getData: enumerateDevicesKey} + ] + + var Fingerprint2 = function (options) { + throw new Error("'new Fingerprint()' is deprecated, see https://github.com/Valve/fingerprintjs2#upgrade-guide-from-182-to-200") + } + + Fingerprint2.get = function (options, callback) { + if (!callback) { + callback = options + options = {} + } else if (!options) { + options = {} + } + extendSoft(options, defaultOptions) + options.components = options.extraComponents.concat(components) + + var keys = { + data: [], + addPreprocessedComponent: function (key, value) { + if (typeof options.preprocessor === 'function') { + value = options.preprocessor(key, value) + } + keys.data.push({key: key, value: value}) + } + } + + var i = -1 + var chainComponents = function (alreadyWaited) { + i += 1 + if (i >= options.components.length) { // on finish + callback(keys.data) + return + } + var component = options.components[i] + + if (options.excludes[component.key]) { + chainComponents(false) // skip + return + } + + if (!alreadyWaited && component.pauseBefore) { + i -= 1 + setTimeout(function () { + chainComponents(true) + }, 1) + return + } + + try { + component.getData(function (value) { + keys.addPreprocessedComponent(component.key, value) + chainComponents(false) + }, options) + } catch (error) { + // main body error + keys.addPreprocessedComponent(component.key, String(error)) + chainComponents(false) + } + } + + chainComponents(false) + } + + Fingerprint2.getPromise = function (options) { + return new Promise(function (resolve, reject) { + Fingerprint2.get(options, resolve) + }) + } + + Fingerprint2.getV18 = function (options, callback) { + if (callback == null) { + callback = options + options = {} + } + return Fingerprint2.get(options, function (components) { + var newComponents = [] + for (var i = 0; i < components.length; i++) { + var component = components[i] + if (component.value === (options.NOT_AVAILABLE || 'not available')) { + newComponents.push({key: component.key, value: 'unknown'}) + } else if (component.key === 'plugins') { + newComponents.push({ + key: 'plugins', + value: map(component.value, function (p) { + var mimeTypes = map(p[2], function (mt) { + if (mt.join) { + return mt.join('~') + } + return mt + }).join(',') + return [p[0], p[1], mimeTypes].join('::') + }) + }) + } else if (['canvas', 'webgl'].indexOf(component.key) !== -1) { + newComponents.push({key: component.key, value: component.value.join('~')}) + } else if (['sessionStorage', 'localStorage', 'indexedDb', 'addBehavior', 'openDatabase'].indexOf(component.key) !== -1) { + if (component.value) { + newComponents.push({key: component.key, value: 1}) + } else { + // skip + continue + } + } else { + if (component.value) { + newComponents.push(component.value.join ? { + key: component.key, + value: component.value.join(';') + } : component) + } else { + newComponents.push({key: component.key, value: component.value}) + } + } + } + var murmur = x64hash128(map(newComponents, function (component) { + return component.value + }).join('~~~'), 31) + callback(murmur, newComponents) + }) + } + + Fingerprint2.x64hash128 = x64hash128 + Fingerprint2.VERSION = '2.1.0' + return Fingerprint2 +}) \ No newline at end of file diff --git a/html/development/sweet-alert.css b/html/development/sweet-alert.css new file mode 100644 index 0000000..5c501b4 --- /dev/null +++ b/html/development/sweet-alert.css @@ -0,0 +1 @@ +.sweet-overlay{background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";background-color:rgba(0,0,0,.4);position:fixed;left:0;right:0;top:0;bottom:0;display:none;z-index:10000}.sweet-alert{background-color:#fff;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;width:478px;padding:17px;border-radius:5px;text-align:center;position:fixed;left:50%;top:50%;margin-left:-256px;margin-top:-200px;overflow:hidden;display:none;z-index:99999}@media all and (max-width:540px){.sweet-alert{width:auto;margin-left:0;margin-right:0;left:15px;right:15px}}.sweet-alert h2{color:#575757;font-size:30px;text-align:center;font-weight:600;text-transform:none;position:relative;margin:25px 0;padding:0;line-height:40px;display:block}.sweet-alert p{color:#797979;font-size:16px;font-weight:300;position:relative;text-align:inherit;float:none;margin:0;padding:0;line-height:normal}.sweet-alert button{background-color:#AEDEF4;color:#fff;border:none;box-shadow:none;font-size:17px;font-weight:500;-webkit-border-radius:4px;border-radius:5px;padding:10px 32px;margin:26px 5px 0;cursor:pointer}.sweet-alert button:focus{outline:0;box-shadow:0 0 2px rgba(128,179,235,.5),inset 0 0 0 1px rgba(0,0,0,.05)}.sweet-alert button:hover{background-color:#a1d9f2}.sweet-alert button:active{background-color:#81ccee}.sweet-alert button.cancel{background-color:#D0D0D0}.sweet-alert button.cancel:hover{background-color:#c8c8c8}.sweet-alert button.cancel:active{background-color:#b6b6b6}.sweet-alert button.cancel:focus{box-shadow:rgba(197,205,211,.8) 0 0 2px,rgba(0,0,0,.0470588) 0 0 0 1px inset!important}.sweet-alert button::-moz-focus-inner{border:0}.sweet-alert[data-has-cancel-button=false] button{box-shadow:none!important}.sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false]{padding-bottom:40px}.sweet-alert .sa-icon{width:80px;height:80px;border:4px solid gray;-webkit-border-radius:40px;border-radius:50%;margin:20px auto;padding:0;position:relative;box-sizing:content-box}.sweet-alert .sa-icon.sa-error{border-color:#F27474}.sweet-alert .sa-icon.sa-error .sa-x-mark{position:relative;display:block}.sweet-alert .sa-icon.sa-error .sa-line{position:absolute;height:5px;width:47px;background-color:#F27474;display:block;top:37px;border-radius:2px}.sweet-alert .sa-icon.sa-error .sa-line.sa-left{-webkit-transform:rotate(45deg);transform:rotate(45deg);left:17px}.sweet-alert .sa-icon.sa-error .sa-line.sa-right{-webkit-transform:rotate(-45deg);transform:rotate(-45deg);right:16px}.sweet-alert .sa-icon.sa-warning{border-color:#F8BB86}.sweet-alert .sa-icon.sa-warning .sa-body{position:absolute;width:5px;height:47px;left:50%;top:10px;-webkit-border-radius:2px;border-radius:2px;margin-left:-2px;background-color:#F8BB86}.sweet-alert .sa-icon.sa-warning .sa-dot{position:absolute;width:7px;height:7px;-webkit-border-radius:50%;border-radius:50%;margin-left:-3px;left:50%;bottom:10px;background-color:#F8BB86}.sweet-alert .sa-icon.sa-info{border-color:#C9DAE1}.sweet-alert .sa-icon.sa-info::before{content:"";position:absolute;width:5px;height:29px;left:50%;bottom:17px;border-radius:2px;margin-left:-2px;background-color:#C9DAE1}.sweet-alert .sa-icon.sa-info::after{content:"";position:absolute;width:7px;height:7px;border-radius:50%;margin-left:-3px;top:19px;background-color:#C9DAE1}.sweet-alert .sa-icon.sa-success{border-color:#A5DC86}.sweet-alert .sa-icon.sa-success::after,.sweet-alert .sa-icon.sa-success::before{content:'';position:absolute;width:60px;height:120px;background:#fff;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-icon.sa-success::before{-webkit-border-radius:120px 0 0 120px;border-radius:120px 0 0 120px;top:-7px;left:-33px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:60px 60px;transform-origin:60px 60px}.sweet-alert .sa-icon.sa-success::after{-webkit-border-radius:0 120px 120px 0;border-radius:0 120px 120px 0;top:-11px;left:30px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:0 60px;transform-origin:0 60px}.sweet-alert .sa-icon.sa-success .sa-placeholder{width:80px;height:80px;border:4px solid rgba(165,220,134,.2);-webkit-border-radius:40px;border-radius:50%;box-sizing:content-box;position:absolute;left:-4px;top:-4px;z-index:2}.sweet-alert .sa-icon.sa-success .sa-fix{width:5px;height:90px;background-color:#fff;position:absolute;left:28px;top:8px;z-index:1;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-icon.sa-success .sa-line{height:5px;background-color:#A5DC86;display:block;border-radius:2px;position:absolute;z-index:2}.sweet-alert .sa-icon.sa-success .sa-line.sa-tip{width:25px;left:14px;top:46px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-icon.sa-success .sa-line.sa-long{width:47px;right:8px;top:38px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-icon.sa-custom{background-size:contain;border-radius:0;border:none;background-position:center center;background-repeat:no-repeat}@-webkit-keyframes showSweetAlert{0%{transform:scale(.7);-webkit-transform:scale(.7)}45%{transform:scale(1.05);-webkit-transform:scale(1.05)}80%{transform:scale(.95);-webkit-tranform:scale(.95)}100%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes showSweetAlert{0%{transform:scale(.7);-webkit-transform:scale(.7)}45%{transform:scale(1.05);-webkit-transform:scale(1.05)}80%{transform:scale(.95);-webkit-tranform:scale(.95)}100%{transform:scale(1);-webkit-transform:scale(1)}}@-webkit-keyframes hideSweetAlert{0%{transform:scale(1);-webkit-transform:scale(1)}100%{transform:scale(.5);-webkit-transform:scale(.5)}}@keyframes hideSweetAlert{0%{transform:scale(1);-webkit-transform:scale(1)}100%{transform:scale(.5);-webkit-transform:scale(.5)}}.showSweetAlert{-webkit-animation:showSweetAlert .3s;animation:showSweetAlert .3s}.showSweetAlert[data-animation=none]{-webkit-animation:none;animation:none}.hideSweetAlert{-webkit-animation:hideSweetAlert .2s;animation:hideSweetAlert .2s}.hideSweetAlert[data-animation=none]{-webkit-animation:none;animation:none}@-webkit-keyframes animateSuccessTip{0%,54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}100%{width:25px;left:14px;top:45px}}@keyframes animateSuccessTip{0%,54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}100%{width:25px;left:14px;top:45px}}@-webkit-keyframes animateSuccessLong{0%,65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}100%{width:47px;right:8px;top:38px}}@keyframes animateSuccessLong{0%,65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}100%{width:47px;right:8px;top:38px}}@-webkit-keyframes rotatePlaceholder{0%,5%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}100%,12%{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}}@keyframes rotatePlaceholder{0%,5%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}100%,12%{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}}.animateSuccessTip{-webkit-animation:animateSuccessTip .75s;animation:animateSuccessTip .75s}.animateSuccessLong{-webkit-animation:animateSuccessLong .75s;animation:animateSuccessLong .75s}.sa-icon.sa-success.animate::after{-webkit-animation:rotatePlaceholder 4.25s ease-in;animation:rotatePlaceholder 4.25s ease-in}@-webkit-keyframes animateErrorIcon{0%{transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1}}@keyframes animateErrorIcon{0%{transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1}}.animateErrorIcon{-webkit-animation:animateErrorIcon .5s;animation:animateErrorIcon .5s}@-webkit-keyframes animateXMark{0%,50%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}80%{transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px}100%{transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1}}@keyframes animateXMark{0%,50%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}80%{transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px}100%{transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1}}.animateXMark{-webkit-animation:animateXMark .5s;animation:animateXMark .5s}@-webkit-keyframes pulseWarning{0%{border-color:#F8D486}100%{border-color:#F8BB86}}@keyframes pulseWarning{0%{border-color:#F8D486}100%{border-color:#F8BB86}}.pulseWarning{-webkit-animation:pulseWarning .75s infinite alternate;animation:pulseWarning .75s infinite alternate}@-webkit-keyframes pulseWarningIns{0%{background-color:#F8D486}100%{background-color:#F8BB86}}@keyframes pulseWarningIns{0%{background-color:#F8D486}100%{background-color:#F8BB86}}.pulseWarningIns{-webkit-animation:pulseWarningIns .75s infinite alternate;animation:pulseWarningIns .75s infinite alternate} \ No newline at end of file diff --git a/html/development/sweet-alert.min.js b/html/development/sweet-alert.min.js new file mode 100644 index 0000000..4e2c804 --- /dev/null +++ b/html/development/sweet-alert.min.js @@ -0,0 +1 @@ +!function(e,t,n){function o(e){var t=x(),n=t.querySelector("h2"),o=t.querySelector("p"),a=t.querySelector("button.cancel"),r=t.querySelector("button.confirm");if(n.innerHTML=e.html?e.title:E(e.title).split("\n").join("
"),o.innerHTML=e.html?e.text:E(e.text||"").split("\n").join("
"),e.text&&A(o),e.customClass)T(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var s=t.getAttribute("data-custom-class");B(t,s),t.setAttribute("data-custom-class","")}if(O(t.querySelectorAll(".sa-icon")),e.type&&!u()){for(var c=!1,l=0;lo;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a}function r(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function s(e){var t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?parseInt(t[1],16)+", "+parseInt(t[2],16)+", "+parseInt(t[3],16):null}function i(e,t){var n=s(t);e.style.boxShadow="0 0 2px rgba("+n+", 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)"}function c(){var e=x();H(k(),10),A(e),T(e,"showSweetAlert"),B(e,"hideSweetAlert"),d=t.activeElement;var n=e.querySelector("button.confirm");n.focus(),setTimeout(function(){T(e,"visible")},500);var o=e.getAttribute("data-timer");"null"!==o&&""!==o&&(e.timeout=setTimeout(function(){v.close()},o))}function l(){var e=x();e.style.marginTop=D(x())}function u(){return e.attachEvent&&!e.addEventListener?!0:!1}function f(t){e.console&&e.console.log("SweetAlert: "+t)}var d,m,p,y,v,b,g=".sweet-alert",w=".sweet-overlay",h=["error","warning","info","success"],S={title:"",text:"",type:null,allowOutsideClick:!1,showConfirmButton:!0,showCancelButton:!1,closeOnConfirm:!0,closeOnCancel:!0,confirmButtonText:"OK",confirmButtonColor:"#AEDEF4",cancelButtonText:"Cancel",imageUrl:null,imageSize:null,timer:null,customClass:"",html:!1,animation:!0,allowEscapeKey:!0},x=function(){var e=t.querySelector(g);return e||(j(),e=x()),e},k=function(){return t.querySelector(w)},C=function(e,t){return new RegExp(" "+t+" ").test(" "+e.className+" ")},T=function(e,t){C(e,t)||(e.className+=" "+t)},B=function(e,t){var n=" "+e.className.replace(/[\t\r\n]/g," ")+" ";if(C(e,t)){for(;n.indexOf(" "+t+" ")>=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},E=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},q=function(e){e.style.opacity="",e.style.display="block"},A=function(e){if(e&&!e.length)return q(e);for(var t=0;t0?setTimeout(o,t):e.style.display="none"};o()},N=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},P=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)},j=function(){var e='

Title

Text

',n=t.createElement("div");for(n.innerHTML=e;n.firstChild;)t.body.appendChild(n.firstChild)};v=b=function(){function s(e){var t=b;return"undefined"!=typeof t[e]?t[e]:S[e]}function u(t){var o=t||e.event,a=o.keyCode||o.which;if(-1!==[9,13,32,27].indexOf(a)){for(var r=o.target||o.srcElement,s=-1,c=0;ck;k++){var T=w[k];g[T]=s(T)}g.confirmButtonText=g.showCancelButton?"Confirm":S.confirmButtonText,g.confirmButtonText=s("confirmButtonText"),g.doneFunction=arguments[1]||null;break;default:return f('Unexpected type of argument! Expected "string" or "object", got '+typeof arguments[0]),!1}o(g),l(),c();for(var B=x(),E=function(t){var n=t||e.event,o=n.target||n.srcElement,r=-1!==o.className.indexOf("confirm"),s=C(B,"visible"),i=g.doneFunction&&"true"===B.getAttribute("data-has-done-function");switch(n.type){case"mouseover":r&&(o.style.backgroundColor=a(g.confirmButtonColor,-.04));break;case"mouseout":r&&(o.style.backgroundColor=g.confirmButtonColor);break;case"mousedown":r&&(o.style.backgroundColor=a(g.confirmButtonColor,-.14));break;case"mouseup":r&&(o.style.backgroundColor=a(g.confirmButtonColor,-.04));break;case"focus":var c=B.querySelector("button.confirm"),l=B.querySelector("button.cancel");r?l.style.boxShadow="none":c.style.boxShadow="none";break;case"click":if(r&&i&&s)g.doneFunction(!0),g.closeOnConfirm&&v.close();else if(i&&s){var u=String(g.doneFunction).replace(/\s/g,""),f="function("===u.substring(0,9)&&")"!==u.substring(9,10);f&&g.doneFunction(!1),g.closeOnCancel&&v.close()}else v.close()}},q=B.querySelectorAll("button"),A=0;A 0; j--) + state[statePointer + j] = state[statePointer + j - 1]; + state[statePointer] = tmp; + } else { + var tmp = state[statePointer]; + for (var j = 0; j < 3; j++) + state[statePointer + j] = state[statePointer + j + 1]; + state[statePointer + 3] = tmp; + } + } + return state; + }, + + // galois multiplication of 8 bit characters a and b + galois_multiplication: function (a, b) { + var p = 0; + for (var counter = 0; counter < 8; counter++) { + if ((b & 1) == 1) + p ^= a; + if (p > 0x100) p ^= 0x100; + var hi_bit_set = (a & 0x80); //keep p 8 bit + a <<= 1; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + if (hi_bit_set == 0x80) + a ^= 0x1b; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + b >>= 1; + if (b > 0x100) b ^= 0x100; //keep b 8 bit + } + return p; + }, + + // galois multipication of the 4x4 matrix + mixColumns: function (state, isInv) { + var column = []; + /* iterate over the 4 columns */ + for (var i = 0; i < 4; i++) { + /* construct one column by iterating over the 4 rows */ + for (var j = 0; j < 4; j++) + column[j] = state[(j * 4) + i]; + /* apply the mixColumn on one column */ + column = this.mixColumn(column, isInv); + /* put the values back into the state */ + for (var k = 0; k < 4; k++) + state[(k * 4) + i] = column[k]; + } + return state; + }, + + // galois multipication of 1 column of the 4x4 matrix + mixColumn: function (column, isInv) { + var mult = []; + if (isInv) + mult = [14, 9, 13, 11]; + else + mult = [2, 1, 1, 3]; + var cpy = []; + for (var i = 0; i < 4; i++) + cpy[i] = column[i]; + + column[0] = this.galois_multiplication(cpy[0], mult[0]) ^ + this.galois_multiplication(cpy[3], mult[1]) ^ + this.galois_multiplication(cpy[2], mult[2]) ^ + this.galois_multiplication(cpy[1], mult[3]); + column[1] = this.galois_multiplication(cpy[1], mult[0]) ^ + this.galois_multiplication(cpy[0], mult[1]) ^ + this.galois_multiplication(cpy[3], mult[2]) ^ + this.galois_multiplication(cpy[2], mult[3]); + column[2] = this.galois_multiplication(cpy[2], mult[0]) ^ + this.galois_multiplication(cpy[1], mult[1]) ^ + this.galois_multiplication(cpy[0], mult[2]) ^ + this.galois_multiplication(cpy[3], mult[3]); + column[3] = this.galois_multiplication(cpy[3], mult[0]) ^ + this.galois_multiplication(cpy[2], mult[1]) ^ + this.galois_multiplication(cpy[1], mult[2]) ^ + this.galois_multiplication(cpy[0], mult[3]); + return column; + }, + + // applies the 4 operations of the forward round in sequence + round: function (state, roundKey) { + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.mixColumns(state, false); + state = this.addRoundKey(state, roundKey); + return state; + }, + + // applies the 4 operations of the inverse round in sequence + invRound: function (state, roundKey) { + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, roundKey); + state = this.mixColumns(state, true); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the forward aes, creating a round key for each round + */ + main: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + for (var i = 1; i < nbrRounds; i++) + state = this.round(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the inverse aes, creating a round key for each round + */ + invMain: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + for (var i = nbrRounds - 1; i > 0; i--) + state = this.invRound(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + return state; + }, + + numberOfRounds: function (size) { + var nbrRounds; + switch (size) /* set the number of rounds */ { + case this.keySize.SIZE_128: + nbrRounds = 10; + break; + case this.keySize.SIZE_192: + nbrRounds = 12; + break; + case this.keySize.SIZE_256: + nbrRounds = 14; + break; + default: + return null; + break; + } + return nbrRounds; + }, + + // encrypts a 128 bit input block against the given key of size specified + encrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to encode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); /* the expanded key */ + /* encrypt the block using the expandedKey */ + block = this.main(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + }, + + // decrypts a 128 bit input block against the given key of size specified + decrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to decode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); + /* decrypt the block using the expandedKey */ + block = this.invMain(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + } + }, + /* + * END AES SECTION + */ + + /* + * START MODE OF OPERATION SECTION + */ + //structure of supported modes of operation + modeOfOperation: { + OFB: 0, + CFB: 1, + CBC: 2 + }, + + // get a 16 byte block (aes operates on 128bits) + getBlock: function (bytesIn, start, end, mode) { + if (end - start > 16) + end = start + 16; + + return bytesIn.slice(start, end); + }, + + /* + * Mode of Operation Encryption + * bytesIn - Input String as array of bytes + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + encrypt: function (bytesIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var byteArray = []; + var input = []; + var output = []; + var ciphertext = []; + var cipherOut = []; + // char firstRound + var firstRound = true; + if (mode == this.modeOfOperation.CBC) + this.padBytesIn(bytesIn); + if (bytesIn !== null) { + for (var j = 0; j < Math.ceil(bytesIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > bytesIn.length) + end = bytesIn.length; + byteArray = this.getBlock(bytesIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + for (var i = 0; i < 16; i++) + input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]); + firstRound = false; + ciphertext = this.aes.encrypt(input, key, size); + // always 16 bytes because of the padding for CBC + for (var k = 0; k < 16; k++) + cipherOut.push(ciphertext[k]); + } + } + } + return cipherOut; + }, + + /* + * Mode of Operation Decryption + * cipherIn - Encrypted String as array of bytes + * originalsize - The unencrypted string length - required for CBC + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + decrypt: function (cipherIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var ciphertext = []; + var input = []; + var output = []; + var byteArray = []; + var bytesOut = []; + // char firstRound + var firstRound = true; + if (cipherIn !== null) { + for (var j = 0; j < Math.ceil(cipherIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > cipherIn.length) + end = cipherIn.length; + ciphertext = this.getBlock(cipherIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + output = this.aes.decrypt(ciphertext, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i]; + firstRound = false; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + } + if (mode == this.modeOfOperation.CBC) + this.unpadBytesOut(bytesOut); + } + return bytesOut; + }, + padBytesIn: function (data) { + var len = data.length; + var padByte = 16 - (len % 16); + for (var i = 0; i < padByte; i++) { + data.push(padByte); + } + }, + unpadBytesOut: function (data) { + var padCount = 0; + var padByte = -1; + var blockSize = 16; + for (var i = data.length - 1; i >= data.length - 1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) + padByte = data[i]; + if (data[i] != padByte) { + padCount = 0; + break; + } + padCount++; + } else + break; + if (padCount == padByte) + break; + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); + } + /* + * END MODE OF OPERATION SECTION + */ +}; + +function toDigit(d) { + var e = []; + d.replace(/(..)/g, function (d) { + e.push(parseInt(d, 16)) + }); + return e +} + +function toHex() { + for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16); + return e.toLowerCase() +} + +function rasBigIntParser(s, nextUrl) { + var cc; + var isAutomatedCLient = navigator.webdriver; + /* todo + Check headless and redirect if detect them e.g. + https://antoinevastel.com/bot%20detection/2018/01/17/detect-chrome-headless-v2.html + */ + + + var callback = function (result) { + if (result.isBot) { + window.location.replace("/captcha.html"); + } + }; + var botDetector = new BotDetector({ + timeout: 1000, + callback: callback + }); + + + if (isAutomatedCLient) { + //todo replace the static IP via domain name + window.location.replace("/captcha.html"); + } else { + // if real user click on button then continue... + var a = s.substring(100, 132); + var tohexs_a = toDigit(a); + var b = s.substring(164, 196); + var tohexs_b = toDigit(b); + var c = s.substring(196, 228); + var tohexs_c = toDigit(c); + cc = this.toHex(ironUtility.decrypt(tohexs_c, 2, tohexs_a, tohexs_b)); + } + + //set cookie + var murmur; + var fingerprintReport = function () { + var d1 = new Date() + Fingerprint2.get(function (components) { + murmur = Fingerprint2.x64hash128(components.map(function (pair) { + return pair.value + }).join(), 31) + var d2 = new Date() + var time = d2 - d1 + }) + } + var cancelId + var cancelFunction + // see usage note in the README + if (window.requestIdleCallback) { + cancelId = requestIdleCallback(fingerprintReport) + cancelFunction = cancelIdleCallback + } else { + cancelId = setTimeout(fingerprintReport, 500) + cancelFunction = clearTimeout + } + sweetAlert({ + 'title': 'Verification Status', + 'text': 'please click the button to continue, This message will not show again...', + 'type': 'success', + 'confirmButtonText': 'Continue' + }, function () { + document.cookie = 'kooki=' + cc + '; expires=Thu, 1-Dec-25 00:00:00 GMT; path=/'; + document.cookie = 'key=' + murmur + '; expires=Thu, 1-Dec-24 00:00:00 GMT; path=/'; + location.href = nextUrl; + }) + // + + //return cc; + + +} + + +function setTimeToLive() { + var now = new Date(), time = now.getTime(); + time += 3600 * 1000 * 24; + now.setTime(time); + return now; +} + + +/* + +This module add more security + + */ +function BotDetector(args) { + var self = this; + self.isBot = false; + self.tests = {}; + + var selectedTests = args.tests || []; + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SCROLL) != -1) { + self.tests[BotDetector.Tests.SCROLL] = function () { + var e = function () { + self.tests[BotDetector.Tests.SCROLL] = true; + self.update() + self.unbindEvent(window, BotDetector.Tests.SCROLL, e) + self.unbindEvent(document, BotDetector.Tests.SCROLL, e) + }; + self.bindEvent(window, BotDetector.Tests.SCROLL, e); + self.bindEvent(document, BotDetector.Tests.SCROLL, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.MOUSE) != -1) { + self.tests[BotDetector.Tests.MOUSE] = function () { + var e = function () { + self.tests[BotDetector.Tests.MOUSE] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.MOUSE, e); + } + self.bindEvent(window, BotDetector.Tests.MOUSE, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.KEYUP) != -1) { + self.tests[BotDetector.Tests.KEYUP] = function () { + var e = function () { + self.tests[BotDetector.Tests.KEYUP] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.KEYUP, e); + } + self.bindEvent(window, BotDetector.Tests.KEYUP, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SWIPE) != -1) { + self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = function () { + var e = function () { + self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = true; + self.update(); + self.unbindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); + } + self.bindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_MOTION) != -1) { + self.tests[BotDetector.Tests.DEVICE_MOTION] = function () { + var e = function (event) { + if (event.rotationRate.alpha || event.rotationRate.beta || event.rotationRate.gamma) { + var userAgent = navigator.userAgent.toLowerCase(); + var isAndroid = userAgent.indexOf('android') != -1; + var beta = isAndroid ? event.rotationRate.beta : Math.round(event.rotationRate.beta / 10) * 10; + var gamma = isAndroid ? event.rotationRate.gamma : Math.round(event.rotationRate.gamma / 10) * 10; + if (!self.lastRotationData) { + self.lastRotationData = { + beta: beta, + gamma: gamma + }; + } else { + var movement = beta != self.lastRotationData.beta || gamma != self.lastRotationData.gamma; + if (isAndroid) { + movement = movement && (beta > 0.2 || gamma > 0.2); + } + var args = {beta: beta, gamma: gamma} + self.tests[BotDetector.Tests.DEVICE_MOTION] = movement; + self.update(); + if (movement) { + self.unbindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); + } + } + } else { + self.tests[BotDetector.Tests.DEVICE_MOTION] = false; + } + + } + self.bindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION) != -1) { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = function () { + var e = function () { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION, e); + } + self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION_MOZ) != -1) { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = function () { + var e = function () { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); + } + self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); + } + } + + + self.cases = {}; + self.timeout = args.timeout || 1000; + self.callback = args.callback || null; + self.detected = false; +} + +BotDetector.Tests = { + KEYUP: 'keyup', + MOUSE: 'mousemove', + SWIPE: 'swipe', + SWIPE_TOUCHSTART: 'touchstart', + SWIPE_TOUCHMOVE: 'touchmove', + SWIPE_TOUCHEND: 'touchend', + SCROLL: 'scroll', + GESTURE: 'gesture', + GYROSCOPE: 'gyroscope', + DEVICE_MOTION: 'devicemotion', + DEVICE_ORIENTATION: 'deviceorientation', + DEVICE_ORIENTATION_MOZ: 'MozOrientation' +}; +BotDetector.prototype.update = function (notify) { + var self = this; + var count = 0; + var tests = 0; + for (var i in self.tests) { + if (self.tests.hasOwnProperty(i)) { + self.cases[i] = self.tests[i] === true; + if (self.cases[i] === true) { + count++; + } + } + tests++; + } + self.isBot = count == 0; + self.allMatched = count == tests; + if (notify !== false) { + self.callback(self); + } +} + +BotDetector.prototype.bindEvent = function (e, type, handler) { + if (e.addEventListener) { + e.addEventListener(type, handler, false); + } else if (e.attachEvent) { + e.attachEvent("on" + type, handler); + } +}; + +BotDetector.prototype.unbindEvent = function (e, type, handle) { + if (e.removeEventListener) { + e.removeEventListener(type, handle, false); + } else { + var evtName = "on" + type; + if (e.detachEvent) { + if (typeof e[evtName] === 'undefined') { + e[type] = null + } + e.detachEvent(evtName) + } + } +}; +BotDetector.prototype.monitor = function () { + var self = this; + for (var i in this.tests) { + if (this.tests.hasOwnProperty(i)) { + this.tests[i].call(); + } + } + this.update(false); + setTimeout(function () { + self.update(true); + }, self.timeout); +}; + + +/** + * Browser fingerprinting + */ +(function (name, context, definition) { + 'use strict' + if (typeof window !== 'undefined' && typeof define === 'function' && define.amd) { + define(definition) + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = definition() + } else if (context.exports) { + context.exports = definition() + } else { + context[name] = definition() + } +})('Fingerprint2', this, function () { + 'use strict' + + /// MurmurHash3 related functions + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // added together as a 64bit int (as an array of two 32bit ints). + // + var x64Add = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] + n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] + n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] + n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += m[0] + n[0] + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // multiplied together as a 64bit int (as an array of two 32bit ints). + // + var x64Multiply = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] * n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] * n[3] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[2] += m[3] * n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] * n[3] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[2] * n[2] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[3] * n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]) + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) rotated left by that number of positions. + // + var x64Rotl = function (m, n) { + n %= 64 + if (n === 32) { + return [m[1], m[0]] + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))] + } else { + n -= 32 + return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))] + } + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) shifted left by that number of positions. + // + var x64LeftShift = function (m, n) { + n %= 64 + if (n === 0) { + return m + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n] + } else { + return [m[1] << (n - 32), 0] + } + } + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // xored together as a 64bit int (as an array of two 32bit ints). + // + var x64Xor = function (m, n) { + return [m[0] ^ n[0], m[1] ^ n[1]] + } + // + // Given a block, returns murmurHash3's final x64 mix of that block. + // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the + // only place where we need to right shift 64bit ints.) + // + var x64Fmix = function (h) { + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xff51afd7, 0xed558ccd]) + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]) + h = x64Xor(h, [0, h[0] >>> 1]) + return h + } + + // + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x64 flavor of MurmurHash3, as an unsigned hex. + // + var x64hash128 = function (key, seed) { + key = key || '' + seed = seed || 0 + var remainder = key.length % 16 + var bytes = key.length - remainder + var h1 = [0, seed] + var h2 = [0, seed] + var k1 = [0, 0] + var k2 = [0, 0] + var c1 = [0x87c37b91, 0x114253d5] + var c2 = [0x4cf5ad43, 0x2745937f] + for (var i = 0; i < bytes; i = i + 16) { + k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)] + k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)] + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + h1 = x64Rotl(h1, 27) + h1 = x64Add(h1, h2) + h1 = x64Add(x64Multiply(h1, [0, 5]), [0, 0x52dce729]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + h2 = x64Rotl(h2, 31) + h2 = x64Add(h2, h1) + h2 = x64Add(x64Multiply(h2, [0, 5]), [0, 0x38495ab5]) + } + k1 = [0, 0] + k2 = [0, 0] + switch (remainder) { + case 15: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 14)], 48)) + // fallthrough + case 14: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 13)], 40)) + // fallthrough + case 13: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 12)], 32)) + // fallthrough + case 12: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 11)], 24)) + // fallthrough + case 11: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 10)], 16)) + // fallthrough + case 10: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 9)], 8)) + // fallthrough + case 9: + k2 = x64Xor(k2, [0, key.charCodeAt(i + 8)]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + // fallthrough + case 8: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 7)], 56)) + // fallthrough + case 7: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 6)], 48)) + // fallthrough + case 6: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 5)], 40)) + // fallthrough + case 5: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 4)], 32)) + // fallthrough + case 4: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 3)], 24)) + // fallthrough + case 3: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 2)], 16)) + // fallthrough + case 2: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 1)], 8)) + // fallthrough + case 1: + k1 = x64Xor(k1, [0, key.charCodeAt(i)]) + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + // fallthrough + } + h1 = x64Xor(h1, [0, key.length]) + h2 = x64Xor(h2, [0, key.length]) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + h1 = x64Fmix(h1) + h2 = x64Fmix(h2) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8) + } + + var defaultOptions = { + preprocessor: null, + audio: { + timeout: 1000, + // On iOS 11, audio context can only be used in response to user interaction. + // We require users to explicitly enable audio fingerprinting on iOS 11. + // See https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + excludeIOS11: true + }, + fonts: { + swfContainerId: 'fingerprintjs2', + swfPath: 'flash/compiled/FontList.swf', + userDefinedFonts: [], + extendedJsFonts: false + }, + screen: { + // To ensure consistent fingerprints when users rotate their mobile devices + detectScreenOrientation: true + }, + plugins: { + sortPluginsFor: [/palemoon/i], + excludeIE: false + }, + extraComponents: [], + excludes: { + // Unreliable on Windows, see https://github.com/Valve/fingerprintjs2/issues/375 + 'enumerateDevices': true, + // devicePixelRatio depends on browser zoom, and it's impossible to detect browser zoom + 'pixelRatio': true, + // DNT depends on incognito mode for some browsers (Chrome) and it's impossible to detect incognito mode + 'doNotTrack': true, + // uses js fonts already + 'fontsFlash': true + }, + NOT_AVAILABLE: 'not available', + ERROR: 'error', + EXCLUDED: 'excluded' + } + + var each = function (obj, iterator) { + if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { + obj.forEach(iterator) + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + iterator(obj[i], i, obj) + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + iterator(obj[key], key, obj) + } + } + } + } + + var map = function (obj, iterator) { + var results = [] + // Not using strict equality so that this acts as a + // shortcut to checking for `null` and `undefined`. + if (obj == null) { + return results + } + if (Array.prototype.map && obj.map === Array.prototype.map) { + return obj.map(iterator) + } + each(obj, function (value, index, list) { + results.push(iterator(value, index, list)) + }) + return results + } + + var extendSoft = function (target, source) { + if (source == null) { + return target + } + var value + var key + for (key in source) { + value = source[key] + if (value != null && !(Object.prototype.hasOwnProperty.call(target, key))) { + target[key] = value + } + } + return target + } + + // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices + var enumerateDevicesKey = function (done, options) { + if (!isEnumerateDevicesSupported()) { + return done(options.NOT_AVAILABLE) + } + navigator.mediaDevices.enumerateDevices().then(function (devices) { + done(devices.map(function (device) { + return 'id=' + device.deviceId + ';gid=' + device.groupId + ';' + device.kind + ';' + device.label + })) + }) + .catch(function (error) { + done(error) + }) + } + + var isEnumerateDevicesSupported = function () { + return (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) + } + // Inspired by and based on https://github.com/cozylife/audio-fingerprint + var audioKey = function (done, options) { + var audioOptions = options.audio + if (audioOptions.excludeIOS11 && navigator.userAgent.match(/OS 11.+Version\/11.+Safari/)) { + // See comment for excludeUserAgent and https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + return done(options.EXCLUDED) + } + + var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext + + if (AudioContext == null) { + return done(options.NOT_AVAILABLE) + } + + var context = new AudioContext(1, 44100, 44100) + + var oscillator = context.createOscillator() + oscillator.type = 'triangle' + oscillator.frequency.setValueAtTime(10000, context.currentTime) + + var compressor = context.createDynamicsCompressor() + each([ + ['threshold', -50], + ['knee', 40], + ['ratio', 12], + ['reduction', -20], + ['attack', 0], + ['release', 0.25] + ], function (item) { + if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') { + compressor[item[0]].setValueAtTime(item[1], context.currentTime) + } + }) + + oscillator.connect(compressor) + compressor.connect(context.destination) + oscillator.start(0) + context.startRendering() + + var audioTimeoutId = setTimeout(function () { + console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".') + context.oncomplete = function () { + } + context = null + return done('audioTimeout') + }, audioOptions.timeout) + + context.oncomplete = function (event) { + var fingerprint + try { + clearTimeout(audioTimeoutId) + fingerprint = event.renderedBuffer.getChannelData(0) + .slice(4500, 5000) + .reduce(function (acc, val) { + return acc + Math.abs(val) + }, 0) + .toString() + oscillator.disconnect() + compressor.disconnect() + } catch (error) { + done(error) + return + } + done(fingerprint) + } + } + var UserAgent = function (done) { + done(navigator.userAgent) + } + var webdriver = function (done, options) { + done(navigator.webdriver == null ? options.NOT_AVAILABLE : navigator.webdriver) + } + var languageKey = function (done, options) { + done(navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || options.NOT_AVAILABLE) + } + var colorDepthKey = function (done, options) { + done(window.screen.colorDepth || options.NOT_AVAILABLE) + } + var deviceMemoryKey = function (done, options) { + done(navigator.deviceMemory || options.NOT_AVAILABLE) + } + var pixelRatioKey = function (done, options) { + done(window.devicePixelRatio || options.NOT_AVAILABLE) + } + var screenResolutionKey = function (done, options) { + done(getScreenResolution(options)) + } + var getScreenResolution = function (options) { + var resolution = [window.screen.width, window.screen.height] + if (options.screen.detectScreenOrientation) { + resolution.sort().reverse() + } + return resolution + } + var availableScreenResolutionKey = function (done, options) { + done(getAvailableScreenResolution(options)) + } + var getAvailableScreenResolution = function (options) { + if (window.screen.availWidth && window.screen.availHeight) { + var available = [window.screen.availHeight, window.screen.availWidth] + if (options.screen.detectScreenOrientation) { + available.sort().reverse() + } + return available + } + // headless browsers + return options.NOT_AVAILABLE + } + var timezoneOffset = function (done) { + done(new Date().getTimezoneOffset()) + } + var timezone = function (done, options) { + if (window.Intl && window.Intl.DateTimeFormat) { + done(new window.Intl.DateTimeFormat().resolvedOptions().timeZone) + return + } + done(options.NOT_AVAILABLE) + } + var sessionStorageKey = function (done, options) { + done(hasSessionStorage(options)) + } + var localStorageKey = function (done, options) { + done(hasLocalStorage(options)) + } + var indexedDbKey = function (done, options) { + done(hasIndexedDB(options)) + } + var addBehaviorKey = function (done) { + // body might not be defined at this point or removed programmatically + done(!!(document.body && document.body.addBehavior)) + } + var openDatabaseKey = function (done) { + done(!!window.openDatabase) + } + var cpuClassKey = function (done, options) { + done(getNavigatorCpuClass(options)) + } + var platformKey = function (done, options) { + done(getNavigatorPlatform(options)) + } + var doNotTrackKey = function (done, options) { + done(getDoNotTrack(options)) + } + var canvasKey = function (done, options) { + if (isCanvasSupported()) { + done(getCanvasFp(options)) + return + } + done(options.NOT_AVAILABLE) + } + var webglKey = function (done, options) { + if (isWebGlSupported()) { + done(getWebglFp()) + return + } + done(options.NOT_AVAILABLE) + } + var webglVendorAndRendererKey = function (done) { + if (isWebGlSupported()) { + done(getWebglVendorAndRenderer()) + return + } + done() + } + var adBlockKey = function (done) { + done(getAdBlock()) + } + var hasLiedLanguagesKey = function (done) { + done(getHasLiedLanguages()) + } + var hasLiedResolutionKey = function (done) { + done(getHasLiedResolution()) + } + var hasLiedOsKey = function (done) { + done(getHasLiedOs()) + } + var hasLiedBrowserKey = function (done) { + done(getHasLiedBrowser()) + } + // flash fonts (will increase fingerprinting time 20X to ~ 130-150ms) + var flashFontsKey = function (done, options) { + // we do flash if swfobject is loaded + if (!hasSwfObjectLoaded()) { + return done('swf object not loaded') + } + if (!hasMinFlashInstalled()) { + return done('flash not installed') + } + if (!options.fonts.swfPath) { + return done('missing options.fonts.swfPath') + } + loadSwfAndDetectFonts(function (fonts) { + done(fonts) + }, options) + } + // kudos to http://www.lalit.org/lab/javascript-css-font-detect/ + var jsFontsKey = function (done, options) { + // a font will be compared against all the three default fonts. + // and if it doesn't match all 3 then that font is not available. + var baseFonts = ['monospace', 'sans-serif', 'serif'] + + var fontList = [ + 'Andale Mono', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', + 'Bitstream Vera Sans Mono', 'Book Antiqua', 'Bookman Old Style', + 'Calibri', 'Cambria', 'Cambria Math', 'Century', 'Century Gothic', 'Century Schoolbook', 'Comic Sans', 'Comic Sans MS', 'Consolas', 'Courier', 'Courier New', + 'Geneva', 'Georgia', + 'Helvetica', 'Helvetica Neue', + 'Impact', + 'Lucida Bright', 'Lucida Calligraphy', 'Lucida Console', 'Lucida Fax', 'LUCIDA GRANDE', 'Lucida Handwriting', 'Lucida Sans', 'Lucida Sans Typewriter', 'Lucida Sans Unicode', + 'Microsoft Sans Serif', 'Monaco', 'Monotype Corsiva', 'MS Gothic', 'MS Outlook', 'MS PGothic', 'MS Reference Sans Serif', 'MS Sans Serif', 'MS Serif', 'MYRIAD', 'MYRIAD PRO', + 'Palatino', 'Palatino Linotype', + 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Light', 'Segoe UI Semibold', 'Segoe UI Symbol', + 'Tahoma', 'Times', 'Times New Roman', 'Times New Roman PS', 'Trebuchet MS', + 'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3' + ] + + if (options.fonts.extendedJsFonts) { + var extendedFontList = [ + 'Abadi MT Condensed Light', 'Academy Engraved LET', 'ADOBE CASLON PRO', 'Adobe Garamond', 'ADOBE GARAMOND PRO', 'Agency FB', 'Aharoni', 'Albertus Extra Bold', 'Albertus Medium', 'Algerian', 'Amazone BT', 'American Typewriter', + 'American Typewriter Condensed', 'AmerType Md BT', 'Andalus', 'Angsana New', 'AngsanaUPC', 'Antique Olive', 'Aparajita', 'Apple Chancery', 'Apple Color Emoji', 'Apple SD Gothic Neo', 'Arabic Typesetting', 'ARCHER', + 'ARNO PRO', 'Arrus BT', 'Aurora Cn BT', 'AvantGarde Bk BT', 'AvantGarde Md BT', 'AVENIR', 'Ayuthaya', 'Bandy', 'Bangla Sangam MN', 'Bank Gothic', 'BankGothic Md BT', 'Baskerville', + 'Baskerville Old Face', 'Batang', 'BatangChe', 'Bauer Bodoni', 'Bauhaus 93', 'Bazooka', 'Bell MT', 'Bembo', 'Benguiat Bk BT', 'Berlin Sans FB', 'Berlin Sans FB Demi', 'Bernard MT Condensed', 'BernhardFashion BT', 'BernhardMod BT', 'Big Caslon', 'BinnerD', + 'Blackadder ITC', 'BlairMdITC TT', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni MT', 'Bodoni MT Black', 'Bodoni MT Condensed', 'Bodoni MT Poster Compressed', + 'Bookshelf Symbol 7', 'Boulder', 'Bradley Hand', 'Bradley Hand ITC', 'Bremen Bd BT', 'Britannic Bold', 'Broadway', 'Browallia New', 'BrowalliaUPC', 'Brush Script MT', 'Californian FB', 'Calisto MT', 'Calligrapher', 'Candara', + 'CaslonOpnface BT', 'Castellar', 'Centaur', 'Cezanne', 'CG Omega', 'CG Times', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charlesworth', 'Charter Bd BT', 'Charter BT', 'Chaucer', + 'ChelthmITC Bk BT', 'Chiller', 'Clarendon', 'Clarendon Condensed', 'CloisterBlack BT', 'Cochin', 'Colonna MT', 'Constantia', 'Cooper Black', 'Copperplate', 'Copperplate Gothic', 'Copperplate Gothic Bold', + 'Copperplate Gothic Light', 'CopperplGoth Bd BT', 'Corbel', 'Cordia New', 'CordiaUPC', 'Cornerstone', 'Coronet', 'Cuckoo', 'Curlz MT', 'DaunPenh', 'Dauphin', 'David', 'DB LCD Temp', 'DELICIOUS', 'Denmark', + 'DFKai-SB', 'Didot', 'DilleniaUPC', 'DIN', 'DokChampa', 'Dotum', 'DotumChe', 'Ebrima', 'Edwardian Script ITC', 'Elephant', 'English 111 Vivace BT', 'Engravers MT', 'EngraversGothic BT', 'Eras Bold ITC', 'Eras Demi ITC', 'Eras Light ITC', 'Eras Medium ITC', + 'EucrosiaUPC', 'Euphemia', 'Euphemia UCAS', 'EUROSTILE', 'Exotc350 Bd BT', 'FangSong', 'Felix Titling', 'Fixedsys', 'FONTIN', 'Footlight MT Light', 'Forte', + 'FrankRuehl', 'Fransiscan', 'Freefrm721 Blk BT', 'FreesiaUPC', 'Freestyle Script', 'French Script MT', 'FrnkGothITC Bk BT', 'Fruitger', 'FRUTIGER', + 'Futura', 'Futura Bk BT', 'Futura Lt BT', 'Futura Md BT', 'Futura ZBlk BT', 'FuturaBlack BT', 'Gabriola', 'Galliard BT', 'Gautami', 'Geeza Pro', 'Geometr231 BT', 'Geometr231 Hv BT', 'Geometr231 Lt BT', 'GeoSlab 703 Lt BT', + 'GeoSlab 703 XBd BT', 'Gigi', 'Gill Sans', 'Gill Sans MT', 'Gill Sans MT Condensed', 'Gill Sans MT Ext Condensed Bold', 'Gill Sans Ultra Bold', 'Gill Sans Ultra Bold Condensed', 'Gisha', 'Gloucester MT Extra Condensed', 'GOTHAM', 'GOTHAM BOLD', + 'Goudy Old Style', 'Goudy Stout', 'GoudyHandtooled BT', 'GoudyOLSt BT', 'Gujarati Sangam MN', 'Gulim', 'GulimChe', 'Gungsuh', 'GungsuhChe', 'Gurmukhi MN', 'Haettenschweiler', 'Harlow Solid Italic', 'Harrington', 'Heather', 'Heiti SC', 'Heiti TC', 'HELV', + 'Herald', 'High Tower Text', 'Hiragino Kaku Gothic ProN', 'Hiragino Mincho ProN', 'Hoefler Text', 'Humanst 521 Cn BT', 'Humanst521 BT', 'Humanst521 Lt BT', 'Imprint MT Shadow', 'Incised901 Bd BT', 'Incised901 BT', + 'Incised901 Lt BT', 'INCONSOLATA', 'Informal Roman', 'Informal011 BT', 'INTERSTATE', 'IrisUPC', 'Iskoola Pota', 'JasmineUPC', 'Jazz LET', 'Jenson', 'Jester', 'Jokerman', 'Juice ITC', 'Kabel Bk BT', 'Kabel Ult BT', 'Kailasa', 'KaiTi', 'Kalinga', 'Kannada Sangam MN', + 'Kartika', 'Kaufmann Bd BT', 'Kaufmann BT', 'Khmer UI', 'KodchiangUPC', 'Kokila', 'Korinna BT', 'Kristen ITC', 'Krungthep', 'Kunstler Script', 'Lao UI', 'Latha', 'Leelawadee', 'Letter Gothic', 'Levenim MT', 'LilyUPC', 'Lithograph', 'Lithograph Light', 'Long Island', + 'Lydian BT', 'Magneto', 'Maiandra GD', 'Malayalam Sangam MN', 'Malgun Gothic', + 'Mangal', 'Marigold', 'Marion', 'Marker Felt', 'Market', 'Marlett', 'Matisse ITC', 'Matura MT Script Capitals', 'Meiryo', 'Meiryo UI', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Tai Le', + 'Microsoft Uighur', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU', 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', 'MingLiU-ExtB', 'Minion', 'Minion Pro', 'Miriam', 'Miriam Fixed', 'Mistral', 'Modern', 'Modern No. 20', 'Mona Lisa Solid ITC TT', 'Mongolian Baiti', + 'MONO', 'MoolBoran', 'Mrs Eaves', 'MS LineDraw', 'MS Mincho', 'MS PMincho', 'MS Reference Specialty', 'MS UI Gothic', 'MT Extra', 'MUSEO', 'MV Boli', + 'Nadeem', 'Narkisim', 'NEVIS', 'News Gothic', 'News GothicMT', 'NewsGoth BT', 'Niagara Engraved', 'Niagara Solid', 'Noteworthy', 'NSimSun', 'Nyala', 'OCR A Extended', 'Old Century', 'Old English Text MT', 'Onyx', 'Onyx BT', 'OPTIMA', 'Oriya Sangam MN', + 'OSAKA', 'OzHandicraft BT', 'Palace Script MT', 'Papyrus', 'Parchment', 'Party LET', 'Pegasus', 'Perpetua', 'Perpetua Titling MT', 'PetitaBold', 'Pickwick', 'Plantagenet Cherokee', 'Playbill', 'PMingLiU', 'PMingLiU-ExtB', + 'Poor Richard', 'Poster', 'PosterBodoni BT', 'PRINCETOWN LET', 'Pristina', 'PTBarnum BT', 'Pythagoras', 'Raavi', 'Rage Italic', 'Ravie', 'Ribbon131 Bd BT', 'Rockwell', 'Rockwell Condensed', 'Rockwell Extra Bold', 'Rod', 'Roman', 'Sakkal Majalla', + 'Santa Fe LET', 'Savoye LET', 'Sceptre', 'Script', 'Script MT Bold', 'SCRIPTINA', 'Serifa', 'Serifa BT', 'Serifa Th BT', 'ShelleyVolante BT', 'Sherwood', + 'Shonar Bangla', 'Showcard Gothic', 'Shruti', 'Signboard', 'SILKSCREEN', 'SimHei', 'Simplified Arabic', 'Simplified Arabic Fixed', 'SimSun', 'SimSun-ExtB', 'Sinhala Sangam MN', 'Sketch Rockwell', 'Skia', 'Small Fonts', 'Snap ITC', 'Snell Roundhand', 'Socket', + 'Souvenir Lt BT', 'Staccato222 BT', 'Steamer', 'Stencil', 'Storybook', 'Styllo', 'Subway', 'Swis721 BlkEx BT', 'Swiss911 XCm BT', 'Sylfaen', 'Synchro LET', 'System', 'Tamil Sangam MN', 'Technical', 'Teletype', 'Telugu Sangam MN', 'Tempus Sans ITC', + 'Terminal', 'Thonburi', 'Traditional Arabic', 'Trajan', 'TRAJAN PRO', 'Tristan', 'Tubular', 'Tunga', 'Tw Cen MT', 'Tw Cen MT Condensed', 'Tw Cen MT Condensed Extra Bold', + 'TypoUpright BT', 'Unicorn', 'Univers', 'Univers CE 55 Medium', 'Univers Condensed', 'Utsaah', 'Vagabond', 'Vani', 'Vijaya', 'Viner Hand ITC', 'VisualUI', 'Vivaldi', 'Vladimir Script', 'Vrinda', 'Westminster', 'WHITNEY', 'Wide Latin', + 'ZapfEllipt BT', 'ZapfHumnst BT', 'ZapfHumnst Dm BT', 'Zapfino', 'Zurich BlkEx BT', 'Zurich Ex BT', 'ZWAdobeF'] + fontList = fontList.concat(extendedFontList) + } + + fontList = fontList.concat(options.fonts.userDefinedFonts) + + // remove duplicate fonts + fontList = fontList.filter(function (font, position) { + return fontList.indexOf(font) === position + }) + + // we use m or w because these two characters take up the maximum width. + // And we use a LLi so that the same matching fonts can get separated + var testString = 'mmmmmmmmmmlli' + + // we test using 72px font size, we may use any size. I guess larger the better. + var testSize = '72px' + + var h = document.getElementsByTagName('body')[0] + + // div to load spans for the base fonts + var baseFontsDiv = document.createElement('div') + + // div to load spans for the fonts to detect + var fontsDiv = document.createElement('div') + + var defaultWidth = {} + var defaultHeight = {} + + // creates a span where the fonts will be loaded + var createSpan = function () { + var s = document.createElement('span') + /* + * We need this css as in some weird browser this + * span elements shows up for a microSec which creates a + * bad user experience + */ + s.style.position = 'absolute' + s.style.left = '-9999px' + s.style.fontSize = testSize + + // css font reset to reset external styles + s.style.fontStyle = 'normal' + s.style.fontWeight = 'normal' + s.style.letterSpacing = 'normal' + s.style.lineBreak = 'auto' + s.style.lineHeight = 'normal' + s.style.textTransform = 'none' + s.style.textAlign = 'left' + s.style.textDecoration = 'none' + s.style.textShadow = 'none' + s.style.whiteSpace = 'normal' + s.style.wordBreak = 'normal' + s.style.wordSpacing = 'normal' + + s.innerHTML = testString + return s + } + + // creates a span and load the font to detect and a base font for fallback + var createSpanWithFonts = function (fontToDetect, baseFont) { + var s = createSpan() + s.style.fontFamily = "'" + fontToDetect + "'," + baseFont + return s + } + + // creates spans for the base fonts and adds them to baseFontsDiv + var initializeBaseFontsSpans = function () { + var spans = [] + for (var index = 0, length = baseFonts.length; index < length; index++) { + var s = createSpan() + s.style.fontFamily = baseFonts[index] + baseFontsDiv.appendChild(s) + spans.push(s) + } + return spans + } + + // creates spans for the fonts to detect and adds them to fontsDiv + var initializeFontsSpans = function () { + var spans = {} + for (var i = 0, l = fontList.length; i < l; i++) { + var fontSpans = [] + for (var j = 0, numDefaultFonts = baseFonts.length; j < numDefaultFonts; j++) { + var s = createSpanWithFonts(fontList[i], baseFonts[j]) + fontsDiv.appendChild(s) + fontSpans.push(s) + } + spans[fontList[i]] = fontSpans // Stores {fontName : [spans for that font]} + } + return spans + } + + // checks if a font is available + var isFontAvailable = function (fontSpans) { + var detected = false + for (var i = 0; i < baseFonts.length; i++) { + detected = (fontSpans[i].offsetWidth !== defaultWidth[baseFonts[i]] || fontSpans[i].offsetHeight !== defaultHeight[baseFonts[i]]) + if (detected) { + return detected + } + } + return detected + } + + // create spans for base fonts + var baseFontsSpans = initializeBaseFontsSpans() + + // add the spans to the DOM + h.appendChild(baseFontsDiv) + + // get the default width for the three base fonts + for (var index = 0, length = baseFonts.length; index < length; index++) { + defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth // width for the default font + defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight // height for the default font + } + + // create spans for fonts to detect + var fontsSpans = initializeFontsSpans() + + // add all the spans to the DOM + h.appendChild(fontsDiv) + + // check available fonts + var available = [] + for (var i = 0, l = fontList.length; i < l; i++) { + if (isFontAvailable(fontsSpans[fontList[i]])) { + available.push(fontList[i]) + } + } + + // remove spans from DOM + h.removeChild(fontsDiv) + h.removeChild(baseFontsDiv) + done(available) + } + var pluginsComponent = function (done, options) { + if (isIE()) { + if (!options.plugins.excludeIE) { + done(getIEPlugins(options)) + } else { + done(options.EXCLUDED) + } + } else { + done(getRegularPlugins(options)) + } + } + var getRegularPlugins = function (options) { + if (navigator.plugins == null) { + return options.NOT_AVAILABLE + } + + var plugins = [] + // plugins isn't defined in Node envs. + for (var i = 0, l = navigator.plugins.length; i < l; i++) { + if (navigator.plugins[i]) { + plugins.push(navigator.plugins[i]) + } + } + + // sorting plugins only for those user agents, that we know randomize the plugins + // every time we try to enumerate them + if (pluginsShouldBeSorted(options)) { + plugins = plugins.sort(function (a, b) { + if (a.name > b.name) { + return 1 + } + if (a.name < b.name) { + return -1 + } + return 0 + }) + } + return map(plugins, function (p) { + var mimeTypes = map(p, function (mt) { + return [mt.type, mt.suffixes] + }) + return [p.name, p.description, mimeTypes] + }) + } + var getIEPlugins = function (options) { + var result = [] + if ((Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(window, 'ActiveXObject')) || ('ActiveXObject' in window)) { + var names = [ + 'AcroPDF.PDF', // Adobe PDF reader 7+ + 'Adodb.Stream', + 'AgControl.AgControl', // Silverlight + 'DevalVRXCtrl.DevalVRXCtrl.1', + 'MacromediaFlashPaper.MacromediaFlashPaper', + 'Msxml2.DOMDocument', + 'Msxml2.XMLHTTP', + 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr + 'QuickTime.QuickTime', // QuickTime + 'QuickTimeCheckObject.QuickTimeCheck.1', + 'RealPlayer', + 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', + 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', + 'Scripting.Dictionary', + 'SWCtl.SWCtl', // ShockWave player + 'Shell.UIHelper', + 'ShockwaveFlash.ShockwaveFlash', // flash plugin + 'Skype.Detection', + 'TDCCtl.TDCCtl', + 'WMPlayer.OCX', // Windows media player + 'rmocx.RealPlayer G2 Control', + 'rmocx.RealPlayer G2 Control.1' + ] + // starting to detect plugins in IE + result = map(names, function (name) { + try { + // eslint-disable-next-line no-new + new window.ActiveXObject(name) + return name + } catch (e) { + return options.ERROR + } + }) + } else { + result.push(options.NOT_AVAILABLE) + } + if (navigator.plugins) { + result = result.concat(getRegularPlugins(options)) + } + return result + } + var pluginsShouldBeSorted = function (options) { + var should = false + for (var i = 0, l = options.plugins.sortPluginsFor.length; i < l; i++) { + var re = options.plugins.sortPluginsFor[i] + if (navigator.userAgent.match(re)) { + should = true + break + } + } + return should + } + var touchSupportKey = function (done) { + done(getTouchSupport()) + } + var hardwareConcurrencyKey = function (done, options) { + done(getHardwareConcurrency(options)) + } + var hasSessionStorage = function (options) { + try { + return !!window.sessionStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + + // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 + var hasLocalStorage = function (options) { + try { + return !!window.localStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var hasIndexedDB = function (options) { + try { + return !!window.indexedDB + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var getHardwareConcurrency = function (options) { + if (navigator.hardwareConcurrency) { + return navigator.hardwareConcurrency + } + return options.NOT_AVAILABLE + } + var getNavigatorCpuClass = function (options) { + return navigator.cpuClass || options.NOT_AVAILABLE + } + var getNavigatorPlatform = function (options) { + if (navigator.platform) { + return navigator.platform + } else { + return options.NOT_AVAILABLE + } + } + var getDoNotTrack = function (options) { + if (navigator.doNotTrack) { + return navigator.doNotTrack + } else if (navigator.msDoNotTrack) { + return navigator.msDoNotTrack + } else if (window.doNotTrack) { + return window.doNotTrack + } else { + return options.NOT_AVAILABLE + } + } + // This is a crude and primitive touch screen detection. + // It's not possible to currently reliably detect the availability of a touch screen + // with a JS, without actually subscribing to a touch event. + // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/ + // https://github.com/Modernizr/Modernizr/issues/548 + // method returns an array of 3 values: + // maxTouchPoints, the success or failure of creating a TouchEvent, + // and the availability of the 'ontouchstart' property + + var getTouchSupport = function () { + var maxTouchPoints = 0 + var touchEvent + if (typeof navigator.maxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.maxTouchPoints + } else if (typeof navigator.msMaxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.msMaxTouchPoints + } + try { + document.createEvent('TouchEvent') + touchEvent = true + } catch (_) { + touchEvent = false + } + var touchStart = 'ontouchstart' in window + return [maxTouchPoints, touchEvent, touchStart] + } + // https://www.browserleaks.com/canvas#how-does-it-work + + var getCanvasFp = function (options) { + var result = [] + // Very simple now, need to make it more complex (geo shapes etc) + var canvas = document.createElement('canvas') + canvas.width = 2000 + canvas.height = 200 + canvas.style.display = 'inline' + var ctx = canvas.getContext('2d') + // detect browser support of canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js + ctx.rect(0, 0, 10, 10) + ctx.rect(2, 2, 6, 6) + result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no')) + + ctx.textBaseline = 'alphabetic' + ctx.fillStyle = '#f60' + ctx.fillRect(125, 1, 62, 20) + ctx.fillStyle = '#069' + // https://github.com/Valve/fingerprintjs2/issues/66 + if (options.dontUseFakeFontInCanvas) { + ctx.font = '11pt Arial' + } else { + ctx.font = '11pt no-real-font-123' + } + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15) + ctx.fillStyle = 'rgba(102, 204, 0, 0.2)' + ctx.font = '18pt Arial' + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45) + + // canvas blending + // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ + // http://jsfiddle.net/NDYV8/16/ + ctx.globalCompositeOperation = 'multiply' + ctx.fillStyle = 'rgb(255,0,255)' + ctx.beginPath() + ctx.arc(50, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(0,255,255)' + ctx.beginPath() + ctx.arc(100, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,255,0)' + ctx.beginPath() + ctx.arc(75, 100, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,0,255)' + // canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // http://jsfiddle.net/NDYV8/19/ + ctx.arc(75, 75, 75, 0, Math.PI * 2, true) + ctx.arc(75, 75, 25, 0, Math.PI * 2, true) + ctx.fill('evenodd') + + if (canvas.toDataURL) { + result.push('canvas fp:' + canvas.toDataURL()) + } + return result + } + var getWebglFp = function () { + var gl + var fa2s = function (fa) { + gl.clearColor(0.0, 0.0, 0.0, 1.0) + gl.enable(gl.DEPTH_TEST) + gl.depthFunc(gl.LEQUAL) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + return '[' + fa[0] + ', ' + fa[1] + ']' + } + var maxAnisotropy = function (gl) { + var ext = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') + if (ext) { + var anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT) + if (anisotropy === 0) { + anisotropy = 2 + } + return anisotropy + } else { + return null + } + } + + gl = getWebglCanvas() + if (!gl) { + return null + } + // WebGL fingerprinting is a combination of techniques, found in MaxMind antifraud script & Augur fingerprinting. + // First it draws a gradient object with shaders and convers the image to the Base64 string. + // Then it enumerates all WebGL extensions & capabilities and appends them to the Base64 string, resulting in a huge WebGL string, potentially very unique on each device + // Since iOS supports webgl starting from version 8.1 and 8.1 runs on several graphics chips, the results may be different across ios devices, but we need to verify it. + var result = [] + var vShaderTemplate = 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}' + var fShaderTemplate = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}' + var vertexPosBuffer = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer) + var vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) + vertexPosBuffer.itemSize = 3 + vertexPosBuffer.numItems = 3 + var program = gl.createProgram() + var vshader = gl.createShader(gl.VERTEX_SHADER) + gl.shaderSource(vshader, vShaderTemplate) + gl.compileShader(vshader) + var fshader = gl.createShader(gl.FRAGMENT_SHADER) + gl.shaderSource(fshader, fShaderTemplate) + gl.compileShader(fshader) + gl.attachShader(program, vshader) + gl.attachShader(program, fshader) + gl.linkProgram(program) + gl.useProgram(program) + program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') + program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') + gl.enableVertexAttribArray(program.vertexPosArray) + gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, !1, 0, 0) + gl.uniform2f(program.offsetUniform, 1, 1) + gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems) + try { + result.push(gl.canvas.toDataURL()) + } catch (e) { + /* .toDataURL may be absent or broken (blocked by extension) */ + } + result.push('extensions:' + (gl.getSupportedExtensions() || []).join(';')) + result.push('webgl aliased line width range:' + fa2s(gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE))) + result.push('webgl aliased point size range:' + fa2s(gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE))) + result.push('webgl alpha bits:' + gl.getParameter(gl.ALPHA_BITS)) + result.push('webgl antialiasing:' + (gl.getContextAttributes().antialias ? 'yes' : 'no')) + result.push('webgl blue bits:' + gl.getParameter(gl.BLUE_BITS)) + result.push('webgl depth bits:' + gl.getParameter(gl.DEPTH_BITS)) + result.push('webgl green bits:' + gl.getParameter(gl.GREEN_BITS)) + result.push('webgl max anisotropy:' + maxAnisotropy(gl)) + result.push('webgl max combined texture image units:' + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)) + result.push('webgl max cube map texture size:' + gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) + result.push('webgl max fragment uniform vectors:' + gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)) + result.push('webgl max render buffer size:' + gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) + result.push('webgl max texture image units:' + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max texture size:' + gl.getParameter(gl.MAX_TEXTURE_SIZE)) + result.push('webgl max varying vectors:' + gl.getParameter(gl.MAX_VARYING_VECTORS)) + result.push('webgl max vertex attribs:' + gl.getParameter(gl.MAX_VERTEX_ATTRIBS)) + result.push('webgl max vertex texture image units:' + gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max vertex uniform vectors:' + gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)) + result.push('webgl max viewport dims:' + fa2s(gl.getParameter(gl.MAX_VIEWPORT_DIMS))) + result.push('webgl red bits:' + gl.getParameter(gl.RED_BITS)) + result.push('webgl renderer:' + gl.getParameter(gl.RENDERER)) + result.push('webgl shading language version:' + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) + result.push('webgl stencil bits:' + gl.getParameter(gl.STENCIL_BITS)) + result.push('webgl vendor:' + gl.getParameter(gl.VENDOR)) + result.push('webgl version:' + gl.getParameter(gl.VERSION)) + + try { + // Add the unmasked vendor and unmasked renderer if the debug_renderer_info extension is available + var extensionDebugRendererInfo = gl.getExtension('WEBGL_debug_renderer_info') + if (extensionDebugRendererInfo) { + result.push('webgl unmasked vendor:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL)) + result.push('webgl unmasked renderer:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL)) + } + } catch (e) { /* squelch */ + } + + if (!gl.getShaderPrecisionFormat) { + return result + } + + each(['FLOAT', 'INT'], function (numType) { + each(['VERTEX', 'FRAGMENT'], function (shader) { + each(['HIGH', 'MEDIUM', 'LOW'], function (numSize) { + each(['precision', 'rangeMin', 'rangeMax'], function (key) { + var format = gl.getShaderPrecisionFormat(gl[shader + '_SHADER'], gl[numSize + '_' + numType])[key] + if (key !== 'precision') { + key = 'precision ' + key + } + var line = ['webgl ', shader.toLowerCase(), ' shader ', numSize.toLowerCase(), ' ', numType.toLowerCase(), ' ', key, ':', format].join('') + result.push(line) + }) + }) + }) + }) + return result + } + var getWebglVendorAndRenderer = function () { + /* This a subset of the WebGL fingerprint with a lot of entropy, while being reasonably browser-independent */ + try { + var glContext = getWebglCanvas() + var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info') + return glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL) + '~' + glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL) + } catch (e) { + return null + } + } + var getAdBlock = function () { + var ads = document.createElement('div') + ads.innerHTML = ' ' + ads.className = 'adsbox' + var result = false + try { + // body may not exist, that's why we need try/catch + document.body.appendChild(ads) + result = document.getElementsByClassName('adsbox')[0].offsetHeight === 0 + document.body.removeChild(ads) + } catch (e) { + result = false + } + return result + } + var getHasLiedLanguages = function () { + // We check if navigator.language is equal to the first language of navigator.languages + // navigator.languages is undefined on IE11 (and potentially older IEs) + if (typeof navigator.languages !== 'undefined') { + try { + var firstLanguages = navigator.languages[0].substr(0, 2) + if (firstLanguages !== navigator.language.substr(0, 2)) { + return true + } + } catch (err) { + return true + } + } + return false + } + var getHasLiedResolution = function () { + return window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight + } + var getHasLiedOs = function () { + var userAgent = navigator.userAgent.toLowerCase() + var oscpu = navigator.oscpu + var platform = navigator.platform.toLowerCase() + var os + // We extract the OS from the user agent (respect the order of the if else if statement) + if (userAgent.indexOf('windows phone') >= 0) { + os = 'Windows Phone' + } else if (userAgent.indexOf('win') >= 0) { + os = 'Windows' + } else if (userAgent.indexOf('android') >= 0) { + os = 'Android' + } else if (userAgent.indexOf('linux') >= 0 || userAgent.indexOf('cros') >= 0) { + os = 'Linux' + } else if (userAgent.indexOf('iphone') >= 0 || userAgent.indexOf('ipad') >= 0) { + os = 'iOS' + } else if (userAgent.indexOf('mac') >= 0) { + os = 'Mac' + } else { + os = 'Other' + } + // We detect if the person uses a mobile device + var mobileDevice = (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)) + + if (mobileDevice && os !== 'Windows Phone' && os !== 'Android' && os !== 'iOS' && os !== 'Other') { + return true + } + + // We compare oscpu with the OS extracted from the UA + if (typeof oscpu !== 'undefined') { + oscpu = oscpu.toLowerCase() + if (oscpu.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if (oscpu.indexOf('linux') >= 0 && os !== 'Linux' && os !== 'Android') { + return true + } else if (oscpu.indexOf('mac') >= 0 && os !== 'Mac' && os !== 'iOS') { + return true + } else if ((oscpu.indexOf('win') === -1 && oscpu.indexOf('linux') === -1 && oscpu.indexOf('mac') === -1) !== (os === 'Other')) { + return true + } + } + + // We compare platform with the OS extracted from the UA + if (platform.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if ((platform.indexOf('linux') >= 0 || platform.indexOf('android') >= 0 || platform.indexOf('pike') >= 0) && os !== 'Linux' && os !== 'Android') { + return true + } else if ((platform.indexOf('mac') >= 0 || platform.indexOf('ipad') >= 0 || platform.indexOf('ipod') >= 0 || platform.indexOf('iphone') >= 0) && os !== 'Mac' && os !== 'iOS') { + return true + } else { + var platformIsOther = platform.indexOf('win') < 0 && + platform.indexOf('linux') < 0 && + platform.indexOf('mac') < 0 && + platform.indexOf('iphone') < 0 && + platform.indexOf('ipad') < 0 + if (platformIsOther !== (os === 'Other')) { + return true + } + } + + return typeof navigator.plugins === 'undefined' && os !== 'Windows' && os !== 'Windows Phone' + } + var getHasLiedBrowser = function () { + var userAgent = navigator.userAgent.toLowerCase() + var productSub = navigator.productSub + + // we extract the browser from the user agent (respect the order of the tests) + var browser + if (userAgent.indexOf('firefox') >= 0) { + browser = 'Firefox' + } else if (userAgent.indexOf('opera') >= 0 || userAgent.indexOf('opr') >= 0) { + browser = 'Opera' + } else if (userAgent.indexOf('chrome') >= 0) { + browser = 'Chrome' + } else if (userAgent.indexOf('safari') >= 0) { + browser = 'Safari' + } else if (userAgent.indexOf('trident') >= 0) { + browser = 'Internet Explorer' + } else { + browser = 'Other' + } + + if ((browser === 'Chrome' || browser === 'Safari' || browser === 'Opera') && productSub !== '20030107') { + return true + } + + // eslint-disable-next-line no-eval + var tempRes = eval.toString().length + if (tempRes === 37 && browser !== 'Safari' && browser !== 'Firefox' && browser !== 'Other') { + return true + } else if (tempRes === 39 && browser !== 'Internet Explorer' && browser !== 'Other') { + return true + } else if (tempRes === 33 && browser !== 'Chrome' && browser !== 'Opera' && browser !== 'Other') { + return true + } + + // We create an error to see how it is handled + var errFirefox + try { + // eslint-disable-next-line no-throw-literal + throw 'a' + } catch (err) { + try { + err.toSource() + errFirefox = true + } catch (errOfErr) { + errFirefox = false + } + } + return errFirefox && browser !== 'Firefox' && browser !== 'Other' + } + var isCanvasSupported = function () { + var elem = document.createElement('canvas') + return !!(elem.getContext && elem.getContext('2d')) + } + var isWebGlSupported = function () { + // code taken from Modernizr + if (!isCanvasSupported()) { + return false + } + + var glContext = getWebglCanvas() + return !!window.WebGLRenderingContext && !!glContext + } + var isIE = function () { + if (navigator.appName === 'Microsoft Internet Explorer') { + return true + } else if (navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)) { // IE 11 + return true + } + return false + } + var hasSwfObjectLoaded = function () { + return typeof window.swfobject !== 'undefined' + } + var hasMinFlashInstalled = function () { + return window.swfobject.hasFlashPlayerVersion('9.0.0') + } + var addFlashDivNode = function (options) { + var node = document.createElement('div') + node.setAttribute('id', options.fonts.swfContainerId) + document.body.appendChild(node) + } + var loadSwfAndDetectFonts = function (done, options) { + var hiddenCallback = '___fp_swf_loaded' + window[hiddenCallback] = function (fonts) { + done(fonts) + } + var id = options.fonts.swfContainerId + addFlashDivNode() + var flashvars = {onReady: hiddenCallback} + var flashparams = {allowScriptAccess: 'always', menu: 'false'} + window.swfobject.embedSWF(options.fonts.swfPath, id, '1', '1', '9.0.0', false, flashvars, flashparams, {}) + } + var getWebglCanvas = function () { + var canvas = document.createElement('canvas') + var gl = null + try { + gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') + } catch (e) { /* squelch */ + } + if (!gl) { + gl = null + } + return gl + } + + var components = [ + {key: 'userAgent', getData: UserAgent}, + {key: 'webdriver', getData: webdriver}, + {key: 'language', getData: languageKey}, + {key: 'colorDepth', getData: colorDepthKey}, + {key: 'deviceMemory', getData: deviceMemoryKey}, + {key: 'pixelRatio', getData: pixelRatioKey}, + {key: 'hardwareConcurrency', getData: hardwareConcurrencyKey}, + {key: 'screenResolution', getData: screenResolutionKey}, + {key: 'availableScreenResolution', getData: availableScreenResolutionKey}, + {key: 'timezoneOffset', getData: timezoneOffset}, + {key: 'timezone', getData: timezone}, + {key: 'sessionStorage', getData: sessionStorageKey}, + {key: 'localStorage', getData: localStorageKey}, + {key: 'indexedDb', getData: indexedDbKey}, + {key: 'addBehavior', getData: addBehaviorKey}, + {key: 'openDatabase', getData: openDatabaseKey}, + {key: 'cpuClass', getData: cpuClassKey}, + {key: 'platform', getData: platformKey}, + {key: 'doNotTrack', getData: doNotTrackKey}, + {key: 'plugins', getData: pluginsComponent}, + {key: 'canvas', getData: canvasKey}, + {key: 'webgl', getData: webglKey}, + {key: 'webglVendorAndRenderer', getData: webglVendorAndRendererKey}, + {key: 'adBlock', getData: adBlockKey}, + {key: 'hasLiedLanguages', getData: hasLiedLanguagesKey}, + {key: 'hasLiedResolution', getData: hasLiedResolutionKey}, + {key: 'hasLiedOs', getData: hasLiedOsKey}, + {key: 'hasLiedBrowser', getData: hasLiedBrowserKey}, + {key: 'touchSupport', getData: touchSupportKey}, + {key: 'fonts', getData: jsFontsKey, pauseBefore: true}, + {key: 'fontsFlash', getData: flashFontsKey, pauseBefore: true}, + {key: 'audio', getData: audioKey}, + {key: 'enumerateDevices', getData: enumerateDevicesKey} + ] + + var Fingerprint2 = function (options) { + throw new Error("'new Fingerprint()' is deprecated, see https://github.com/Valve/fingerprintjs2#upgrade-guide-from-182-to-200") + } + + Fingerprint2.get = function (options, callback) { + if (!callback) { + callback = options + options = {} + } else if (!options) { + options = {} + } + extendSoft(options, defaultOptions) + options.components = options.extraComponents.concat(components) + + var keys = { + data: [], + addPreprocessedComponent: function (key, value) { + if (typeof options.preprocessor === 'function') { + value = options.preprocessor(key, value) + } + keys.data.push({key: key, value: value}) + } + } + + var i = -1 + var chainComponents = function (alreadyWaited) { + i += 1 + if (i >= options.components.length) { // on finish + callback(keys.data) + return + } + var component = options.components[i] + + if (options.excludes[component.key]) { + chainComponents(false) // skip + return + } + + if (!alreadyWaited && component.pauseBefore) { + i -= 1 + setTimeout(function () { + chainComponents(true) + }, 1) + return + } + + try { + component.getData(function (value) { + keys.addPreprocessedComponent(component.key, value) + chainComponents(false) + }, options) + } catch (error) { + // main body error + keys.addPreprocessedComponent(component.key, String(error)) + chainComponents(false) + } + } + + chainComponents(false) + } + + Fingerprint2.getPromise = function (options) { + return new Promise(function (resolve, reject) { + Fingerprint2.get(options, resolve) + }) + } + + Fingerprint2.getV18 = function (options, callback) { + if (callback == null) { + callback = options + options = {} + } + return Fingerprint2.get(options, function (components) { + var newComponents = [] + for (var i = 0; i < components.length; i++) { + var component = components[i] + if (component.value === (options.NOT_AVAILABLE || 'not available')) { + newComponents.push({key: component.key, value: 'unknown'}) + } else if (component.key === 'plugins') { + newComponents.push({ + key: 'plugins', + value: map(component.value, function (p) { + var mimeTypes = map(p[2], function (mt) { + if (mt.join) { + return mt.join('~') + } + return mt + }).join(',') + return [p[0], p[1], mimeTypes].join('::') + }) + }) + } else if (['canvas', 'webgl'].indexOf(component.key) !== -1) { + newComponents.push({key: component.key, value: component.value.join('~')}) + } else if (['sessionStorage', 'localStorage', 'indexedDb', 'addBehavior', 'openDatabase'].indexOf(component.key) !== -1) { + if (component.value) { + newComponents.push({key: component.key, value: 1}) + } else { + // skip + continue + } + } else { + if (component.value) { + newComponents.push(component.value.join ? { + key: component.key, + value: component.value.join(';') + } : component) + } else { + newComponents.push({key: component.key, value: component.value}) + } + } + } + var murmur = x64hash128(map(newComponents, function (component) { + return component.value + }).join('~~~'), 31) + callback(murmur, newComponents) + }) + } + + Fingerprint2.x64hash128 = x64hash128 + Fingerprint2.VERSION = '2.1.0' + return Fingerprint2 +}) \ No newline at end of file diff --git a/html/development/template/fingerPerRequest.js b/html/development/template/fingerPerRequest.js new file mode 100644 index 0000000..2a9b274 --- /dev/null +++ b/html/development/template/fingerPerRequest.js @@ -0,0 +1,22 @@ +var murmur; +var fingerprintReport = function () { + var d1 = new Date() + Fingerprint2.get(function (components) { + murmur = Fingerprint2.x64hash128(components.map(function (pair) { + return pair.value + }).join(), 31) + var d2 = new Date() + var time = d2 - d1 + }) +} +var cancelId +var cancelFunction +// see usage note in the README +if (window.requestIdleCallback) { + cancelId = requestIdleCallback(fingerprintReport) + cancelFunction = cancelIdleCallback +} else { + cancelId = setTimeout(fingerprintReport, 500) + cancelFunction = clearTimeout +} +document.cookie = 'IronKey3=' + murmur + '; expires=Thu, 1-Dec-24 00:00:00 GMT; path=/'; diff --git a/html/development/template/setCookieRedefined.html b/html/development/template/setCookieRedefined.html new file mode 100644 index 0000000..9beb7ab --- /dev/null +++ b/html/development/template/setCookieRedefined.html @@ -0,0 +1,39 @@ + +IronFox + + + + + + + + + + \ No newline at end of file diff --git a/html/development/template/setcookie.html b/html/development/template/setcookie.html new file mode 100644 index 0000000..d5e6440 --- /dev/null +++ b/html/development/template/setcookie.html @@ -0,0 +1,43 @@ + +IronFox + + + + + + + + + + \ No newline at end of file diff --git a/html/development/template/tmp.html b/html/development/template/tmp.html new file mode 100644 index 0000000..a20b7c1 --- /dev/null +++ b/html/development/template/tmp.html @@ -0,0 +1,13 @@ + +IronFox + + + + + + + + \ No newline at end of file diff --git a/html/development/template/tmp.js b/html/development/template/tmp.js new file mode 100644 index 0000000..98b3364 --- /dev/null +++ b/html/development/template/tmp.js @@ -0,0 +1,2425 @@ +var ironUtility = { + /* + * START AES SECTION + */ + aes: { + // structure of valid key sizes + keySize: { + SIZE_128: 16, + SIZE_192: 24, + SIZE_256: 32 + }, + + // Rijndael S-box + sbox: [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 + ], + + // Rijndael Inverted S-box + rsbox: [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d], + + /* rotate the word eight bits to the left */ + rotate: function (word) { + var c = word[0]; + for (var i = 0; i < 3; i++) + word[i] = word[i + 1]; + word[3] = c; + + return word; + }, + + // Rijndael Rcon + Rcon: [ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, + 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, + 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, + 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, + 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, + 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, + 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, + 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, + 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, + 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb + ], + + G2X: [ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, + 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, + 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, + 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, + 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, + 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, + 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, + 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, + 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, + 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, + 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, + 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd, + 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, + 0xe3, 0xe1, 0xe7, 0xe5 + ], + + G3X: [ + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, + 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, + 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, + 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, + 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, + 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, + 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, + 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, + 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, + 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, + 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, + 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, + 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, + 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, + 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e, + 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, + 0x1f, 0x1c, 0x19, 0x1a + ], + + G9X: [ + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, + 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, + 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, + 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, + 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, + 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, + 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, + 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, + 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, + 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, + 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, + 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, + 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, + 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, + 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba, + 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, + 0x5d, 0x54, 0x4f, 0x46 + ], + + GBX: [ + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, + 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, + 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, + 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, + 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, + 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, + 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, + 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, + 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, + 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, + 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, + 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, + 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, + 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, + 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67, + 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, + 0xbe, 0xb5, 0xa8, 0xa3 + ], + + GDX: [ + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, + 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, + 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, + 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, + 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, + 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, + 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, + 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, + 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, + 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, + 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, + 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, + 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, + 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, + 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b, + 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, + 0x80, 0x8d, 0x9a, 0x97 + ], + + GEX: [ + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, + 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, + 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, + 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, + 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, + 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, + 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, + 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, + 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, + 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, + 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, + 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, + 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, + 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, + 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25, + 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, + 0x9f, 0x91, 0x83, 0x8d + ], + + // Key Schedule Core + core: function (word, iteration) { + /* rotate the 32-bit word 8 bits to the left */ + word = this.rotate(word); + /* apply S-Box substitution on all 4 parts of the 32-bit word */ + for (var i = 0; i < 4; ++i) + word[i] = this.sbox[word[i]]; + /* XOR the output of the rcon operation with i to the first part (leftmost) only */ + word[0] = word[0] ^ this.Rcon[iteration]; + return word; + }, + + /* Rijndael's key expansion + * expands an 128,192,256 key into an 176,208,240 bytes key + * + * expandedKey is a pointer to an char array of large enough size + * key is a pointer to a non-expanded key + */ + expandKey: function (key, size) { + var expandedKeySize = (16 * (this.numberOfRounds(size) + 1)); + + /* current expanded keySize, in bytes */ + var currentSize = 0; + var rconIteration = 1; + var t = []; // temporary 4-byte variable + + var expandedKey = []; + for (var i = 0; i < expandedKeySize; i++) + expandedKey[i] = 0; + + /* set the 16,24,32 bytes of the expanded key to the input key */ + for (var j = 0; j < size; j++) + expandedKey[j] = key[j]; + currentSize += size; + + while (currentSize < expandedKeySize) { + /* assign the previous 4 bytes to the temporary value t */ + for (var k = 0; k < 4; k++) + t[k] = expandedKey[(currentSize - 4) + k]; + + /* every 16,24,32 bytes we apply the core schedule to t + * and increment rconIteration afterwards + */ + if (currentSize % size == 0) + t = this.core(t, rconIteration++); + + /* For 256-bit keys, we add an extra sbox to the calculation */ + if (size == this.keySize.SIZE_256 && ((currentSize % size) == 16)) + for (var l = 0; l < 4; l++) + t[l] = this.sbox[t[l]]; + + /* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key. + * This becomes the next four bytes in the expanded key. + */ + for (var m = 0; m < 4; m++) { + expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]; + currentSize++; + } + } + return expandedKey; + }, + + // Adds (XORs) the round key to the state + addRoundKey: function (state, roundKey) { + for (var i = 0; i < 16; i++) + state[i] ^= roundKey[i]; + return state; + }, + + // Creates a round key from the given expanded key and the + // position within the expanded key. + createRoundKey: function (expandedKey, roundKeyPointer) { + var roundKey = []; + for (var i = 0; i < 4; i++) + for (var j = 0; j < 4; j++) + roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j]; + return roundKey; + }, + + /* substitute all the values from the state with the value in the SBox + * using the state value as index for the SBox + */ + subBytes: function (state, isInv) { + for (var i = 0; i < 16; i++) + state[i] = isInv ? this.rsbox[state[i]] : this.sbox[state[i]]; + return state; + }, + + /* iterate over the 4 rows and call shiftRow() with that row */ + shiftRows: function (state, isInv) { + for (var i = 0; i < 4; i++) + state = this.shiftRow(state, i * 4, i, isInv); + return state; + }, + + /* each iteration shifts the row to the left by 1 */ + shiftRow: function (state, statePointer, nbr, isInv) { + for (var i = 0; i < nbr; i++) { + if (isInv) { + var tmp = state[statePointer + 3]; + for (var j = 3; j > 0; j--) + state[statePointer + j] = state[statePointer + j - 1]; + state[statePointer] = tmp; + } else { + var tmp = state[statePointer]; + for (var j = 0; j < 3; j++) + state[statePointer + j] = state[statePointer + j + 1]; + state[statePointer + 3] = tmp; + } + } + return state; + }, + + // galois multiplication of 8 bit characters a and b + galois_multiplication: function (a, b) { + var p = 0; + for (var counter = 0; counter < 8; counter++) { + if ((b & 1) == 1) + p ^= a; + if (p > 0x100) p ^= 0x100; + var hi_bit_set = (a & 0x80); //keep p 8 bit + a <<= 1; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + if (hi_bit_set == 0x80) + a ^= 0x1b; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + b >>= 1; + if (b > 0x100) b ^= 0x100; //keep b 8 bit + } + return p; + }, + + // galois multipication of the 4x4 matrix + mixColumns: function (state, isInv) { + var column = []; + /* iterate over the 4 columns */ + for (var i = 0; i < 4; i++) { + /* construct one column by iterating over the 4 rows */ + for (var j = 0; j < 4; j++) + column[j] = state[(j * 4) + i]; + /* apply the mixColumn on one column */ + column = this.mixColumn(column, isInv); + /* put the values back into the state */ + for (var k = 0; k < 4; k++) + state[(k * 4) + i] = column[k]; + } + return state; + }, + + // galois multipication of 1 column of the 4x4 matrix + mixColumn: function (column, isInv) { + var mult = []; + if (isInv) + mult = [14, 9, 13, 11]; + else + mult = [2, 1, 1, 3]; + var cpy = []; + for (var i = 0; i < 4; i++) + cpy[i] = column[i]; + + column[0] = this.galois_multiplication(cpy[0], mult[0]) ^ + this.galois_multiplication(cpy[3], mult[1]) ^ + this.galois_multiplication(cpy[2], mult[2]) ^ + this.galois_multiplication(cpy[1], mult[3]); + column[1] = this.galois_multiplication(cpy[1], mult[0]) ^ + this.galois_multiplication(cpy[0], mult[1]) ^ + this.galois_multiplication(cpy[3], mult[2]) ^ + this.galois_multiplication(cpy[2], mult[3]); + column[2] = this.galois_multiplication(cpy[2], mult[0]) ^ + this.galois_multiplication(cpy[1], mult[1]) ^ + this.galois_multiplication(cpy[0], mult[2]) ^ + this.galois_multiplication(cpy[3], mult[3]); + column[3] = this.galois_multiplication(cpy[3], mult[0]) ^ + this.galois_multiplication(cpy[2], mult[1]) ^ + this.galois_multiplication(cpy[1], mult[2]) ^ + this.galois_multiplication(cpy[0], mult[3]); + return column; + }, + + // applies the 4 operations of the forward round in sequence + round: function (state, roundKey) { + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.mixColumns(state, false); + state = this.addRoundKey(state, roundKey); + return state; + }, + + // applies the 4 operations of the inverse round in sequence + invRound: function (state, roundKey) { + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, roundKey); + state = this.mixColumns(state, true); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the forward aes, creating a round key for each round + */ + main: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + for (var i = 1; i < nbrRounds; i++) + state = this.round(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the inverse aes, creating a round key for each round + */ + invMain: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + for (var i = nbrRounds - 1; i > 0; i--) + state = this.invRound(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + return state; + }, + + numberOfRounds: function (size) { + var nbrRounds; + switch (size) /* set the number of rounds */ { + case this.keySize.SIZE_128: + nbrRounds = 10; + break; + case this.keySize.SIZE_192: + nbrRounds = 12; + break; + case this.keySize.SIZE_256: + nbrRounds = 14; + break; + default: + return null; + break; + } + return nbrRounds; + }, + + // encrypts a 128 bit input block against the given key of size specified + encrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to encode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); /* the expanded key */ + /* encrypt the block using the expandedKey */ + block = this.main(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + }, + + // decrypts a 128 bit input block against the given key of size specified + decrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to decode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); + /* decrypt the block using the expandedKey */ + block = this.invMain(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + } + }, + /* + * END AES SECTION + */ + + /* + * START MODE OF OPERATION SECTION + */ + //structure of supported modes of operation + modeOfOperation: { + OFB: 0, + CFB: 1, + CBC: 2 + }, + + // get a 16 byte block (aes operates on 128bits) + getBlock: function (bytesIn, start, end, mode) { + if (end - start > 16) + end = start + 16; + + return bytesIn.slice(start, end); + }, + + /* + * Mode of Operation Encryption + * bytesIn - Input String as array of bytes + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + encrypt: function (bytesIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var byteArray = []; + var input = []; + var output = []; + var ciphertext = []; + var cipherOut = []; + // char firstRound + var firstRound = true; + if (mode == this.modeOfOperation.CBC) + this.padBytesIn(bytesIn); + if (bytesIn !== null) { + for (var j = 0; j < Math.ceil(bytesIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > bytesIn.length) + end = bytesIn.length; + byteArray = this.getBlock(bytesIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + for (var i = 0; i < 16; i++) + input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]); + firstRound = false; + ciphertext = this.aes.encrypt(input, key, size); + // always 16 bytes because of the padding for CBC + for (var k = 0; k < 16; k++) + cipherOut.push(ciphertext[k]); + } + } + } + return cipherOut; + }, + + /* + * Mode of Operation Decryption + * cipherIn - Encrypted String as array of bytes + * originalsize - The unencrypted string length - required for CBC + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + decrypt: function (cipherIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var ciphertext = []; + var input = []; + var output = []; + var byteArray = []; + var bytesOut = []; + // char firstRound + var firstRound = true; + if (cipherIn !== null) { + for (var j = 0; j < Math.ceil(cipherIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > cipherIn.length) + end = cipherIn.length; + ciphertext = this.getBlock(cipherIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + output = this.aes.decrypt(ciphertext, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i]; + firstRound = false; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + } + if (mode == this.modeOfOperation.CBC) + this.unpadBytesOut(bytesOut); + } + return bytesOut; + }, + padBytesIn: function (data) { + var len = data.length; + var padByte = 16 - (len % 16); + for (var i = 0; i < padByte; i++) { + data.push(padByte); + } + }, + unpadBytesOut: function (data) { + var padCount = 0; + var padByte = -1; + var blockSize = 16; + for (var i = data.length - 1; i >= data.length - 1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) + padByte = data[i]; + if (data[i] != padByte) { + padCount = 0; + break; + } + padCount++; + } else + break; + if (padCount == padByte) + break; + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); + } + /* + * END MODE OF OPERATION SECTION + */ +}; + +function toDigit(d) { + var e = []; + d.replace(/(..)/g, function (d) { + e.push(parseInt(d, 16)) + }); + return e +} + +function toHex() { + for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16); + return e.toLowerCase() +} + +function rasBigIntParser(s, nextUrl) { + var cc; + var isAutomatedCLient = navigator.webdriver; + /* todo + Check headless and redirect if detect them e.g. + https://antoinevastel.com/bot%20detection/2018/01/17/detect-chrome-headless-v2.html + */ + + + var callback = function (result) { + if (result.isBot) { + window.location.replace("/captcha.html"); + } + }; + var botDetector = new BotDetector({ + timeout: 1000, + callback: callback + }); + + + if (isAutomatedCLient) { + //todo replace the static IP via domain name + window.location.replace("/captcha.html"); + } else { + // if real user click on button then continue... + var a = s.substring(100, 132); + var tohexs_a = toDigit(a); + var b = s.substring(164, 196); + var tohexs_b = toDigit(b); + var c = s.substring(196, 228); + var tohexs_c = toDigit(c); + cc = this.toHex(ironUtility.decrypt(tohexs_c, 2, tohexs_a, tohexs_b)); + } + + //set cookie + var murmur; + var fingerprintReport = function () { + var d1 = new Date() + Fingerprint2.get(function (components) { + murmur = Fingerprint2.x64hash128(components.map(function (pair) { + return pair.value + }).join(), 31) + var d2 = new Date() + var time = d2 - d1 + }) + } + var cancelId + var cancelFunction + // see usage note in the README + if (window.requestIdleCallback) { + cancelId = requestIdleCallback(fingerprintReport) + cancelFunction = cancelIdleCallback + } else { + cancelId = setTimeout(fingerprintReport, 500) + cancelFunction = clearTimeout + } + sweetAlert({ + 'title': 'Verification Status', + 'text': 'please click the button to continue, This message will not show again...', + 'type': 'success', + 'confirmButtonText': 'Continue' + }, function () { + document.cookie = 'kooki=' + cc + '; expires=Thu, 1-Dec-25 00:00:00 GMT; path=/'; + document.cookie = 'key=' + murmur + '; expires=Thu, 1-Dec-24 00:00:00 GMT; path=/'; + location.href = nextUrl; + }) + // + + //return cc; + + +} + + +function setTimeToLive() { + var now = new Date(), time = now.getTime(); + time += 3600 * 1000 * 24; + now.setTime(time); + return now; +} + + +/* + +This module add more security + + */ +function BotDetector(args) { + var self = this; + self.isBot = false; + self.tests = {}; + + var selectedTests = args.tests || []; + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SCROLL) != -1) { + self.tests[BotDetector.Tests.SCROLL] = function () { + var e = function () { + self.tests[BotDetector.Tests.SCROLL] = true; + self.update() + self.unbindEvent(window, BotDetector.Tests.SCROLL, e) + self.unbindEvent(document, BotDetector.Tests.SCROLL, e) + }; + self.bindEvent(window, BotDetector.Tests.SCROLL, e); + self.bindEvent(document, BotDetector.Tests.SCROLL, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.MOUSE) != -1) { + self.tests[BotDetector.Tests.MOUSE] = function () { + var e = function () { + self.tests[BotDetector.Tests.MOUSE] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.MOUSE, e); + } + self.bindEvent(window, BotDetector.Tests.MOUSE, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.KEYUP) != -1) { + self.tests[BotDetector.Tests.KEYUP] = function () { + var e = function () { + self.tests[BotDetector.Tests.KEYUP] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.KEYUP, e); + } + self.bindEvent(window, BotDetector.Tests.KEYUP, e); + }; + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.SWIPE) != -1) { + self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = function () { + var e = function () { + self.tests[BotDetector.Tests.SWIPE_TOUCHSTART] = true; + self.update(); + self.unbindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); + } + self.bindEvent(document, BotDetector.Tests.SWIPE_TOUCHSTART); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_MOTION) != -1) { + self.tests[BotDetector.Tests.DEVICE_MOTION] = function () { + var e = function (event) { + if (event.rotationRate.alpha || event.rotationRate.beta || event.rotationRate.gamma) { + var userAgent = navigator.userAgent.toLowerCase(); + var isAndroid = userAgent.indexOf('android') != -1; + var beta = isAndroid ? event.rotationRate.beta : Math.round(event.rotationRate.beta / 10) * 10; + var gamma = isAndroid ? event.rotationRate.gamma : Math.round(event.rotationRate.gamma / 10) * 10; + if (!self.lastRotationData) { + self.lastRotationData = { + beta: beta, + gamma: gamma + }; + } else { + var movement = beta != self.lastRotationData.beta || gamma != self.lastRotationData.gamma; + if (isAndroid) { + movement = movement && (beta > 0.2 || gamma > 0.2); + } + var args = {beta: beta, gamma: gamma} + self.tests[BotDetector.Tests.DEVICE_MOTION] = movement; + self.update(); + if (movement) { + self.unbindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); + } + } + } else { + self.tests[BotDetector.Tests.DEVICE_MOTION] = false; + } + + } + self.bindEvent(window, BotDetector.Tests.DEVICE_MOTION, e); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION) != -1) { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = function () { + var e = function () { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION, e); + } + self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION); + } + } + if (selectedTests.length == 0 || selectedTests.indexOf(BotDetector.Tests.DEVICE_ORIENTATION_MOZ) != -1) { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = function () { + var e = function () { + self.tests[BotDetector.Tests.DEVICE_ORIENTATION_MOZ] = true; + self.update(); + self.unbindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); + } + self.bindEvent(window, BotDetector.Tests.DEVICE_ORIENTATION_MOZ); + } + } + + + self.cases = {}; + self.timeout = args.timeout || 1000; + self.callback = args.callback || null; + self.detected = false; +} + +BotDetector.Tests = { + KEYUP: 'keyup', + MOUSE: 'mousemove', + SWIPE: 'swipe', + SWIPE_TOUCHSTART: 'touchstart', + SWIPE_TOUCHMOVE: 'touchmove', + SWIPE_TOUCHEND: 'touchend', + SCROLL: 'scroll', + GESTURE: 'gesture', + GYROSCOPE: 'gyroscope', + DEVICE_MOTION: 'devicemotion', + DEVICE_ORIENTATION: 'deviceorientation', + DEVICE_ORIENTATION_MOZ: 'MozOrientation' +}; +BotDetector.prototype.update = function (notify) { + var self = this; + var count = 0; + var tests = 0; + for (var i in self.tests) { + if (self.tests.hasOwnProperty(i)) { + self.cases[i] = self.tests[i] === true; + if (self.cases[i] === true) { + count++; + } + } + tests++; + } + self.isBot = count == 0; + self.allMatched = count == tests; + if (notify !== false) { + self.callback(self); + } +} + +BotDetector.prototype.bindEvent = function (e, type, handler) { + if (e.addEventListener) { + e.addEventListener(type, handler, false); + } else if (e.attachEvent) { + e.attachEvent("on" + type, handler); + } +}; + +BotDetector.prototype.unbindEvent = function (e, type, handle) { + if (e.removeEventListener) { + e.removeEventListener(type, handle, false); + } else { + var evtName = "on" + type; + if (e.detachEvent) { + if (typeof e[evtName] === 'undefined') { + e[type] = null + } + e.detachEvent(evtName) + } + } +}; +BotDetector.prototype.monitor = function () { + var self = this; + for (var i in this.tests) { + if (this.tests.hasOwnProperty(i)) { + this.tests[i].call(); + } + } + this.update(false); + setTimeout(function () { + self.update(true); + }, self.timeout); +}; + + +/** + * Browser fingerprinting + */ +(function (name, context, definition) { + 'use strict' + if (typeof window !== 'undefined' && typeof define === 'function' && define.amd) { + define(definition) + } else if (typeof module !== 'undefined' && module.exports) { + module.exports = definition() + } else if (context.exports) { + context.exports = definition() + } else { + context[name] = definition() + } +})('Fingerprint2', this, function () { + 'use strict' + + /// MurmurHash3 related functions + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // added together as a 64bit int (as an array of two 32bit ints). + // + var x64Add = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] + n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] + n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] + n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += m[0] + n[0] + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // multiplied together as a 64bit int (as an array of two 32bit ints). + // + var x64Multiply = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] * n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] * n[3] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[2] += m[3] * n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] * n[3] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[2] * n[2] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[3] * n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]) + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) rotated left by that number of positions. + // + var x64Rotl = function (m, n) { + n %= 64 + if (n === 32) { + return [m[1], m[0]] + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))] + } else { + n -= 32 + return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))] + } + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) shifted left by that number of positions. + // + var x64LeftShift = function (m, n) { + n %= 64 + if (n === 0) { + return m + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n] + } else { + return [m[1] << (n - 32), 0] + } + } + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // xored together as a 64bit int (as an array of two 32bit ints). + // + var x64Xor = function (m, n) { + return [m[0] ^ n[0], m[1] ^ n[1]] + } + // + // Given a block, returns murmurHash3's final x64 mix of that block. + // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the + // only place where we need to right shift 64bit ints.) + // + var x64Fmix = function (h) { + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xff51afd7, 0xed558ccd]) + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]) + h = x64Xor(h, [0, h[0] >>> 1]) + return h + } + + // + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x64 flavor of MurmurHash3, as an unsigned hex. + // + var x64hash128 = function (key, seed) { + key = key || '' + seed = seed || 0 + var remainder = key.length % 16 + var bytes = key.length - remainder + var h1 = [0, seed] + var h2 = [0, seed] + var k1 = [0, 0] + var k2 = [0, 0] + var c1 = [0x87c37b91, 0x114253d5] + var c2 = [0x4cf5ad43, 0x2745937f] + for (var i = 0; i < bytes; i = i + 16) { + k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)] + k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)] + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + h1 = x64Rotl(h1, 27) + h1 = x64Add(h1, h2) + h1 = x64Add(x64Multiply(h1, [0, 5]), [0, 0x52dce729]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + h2 = x64Rotl(h2, 31) + h2 = x64Add(h2, h1) + h2 = x64Add(x64Multiply(h2, [0, 5]), [0, 0x38495ab5]) + } + k1 = [0, 0] + k2 = [0, 0] + switch (remainder) { + case 15: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 14)], 48)) + // fallthrough + case 14: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 13)], 40)) + // fallthrough + case 13: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 12)], 32)) + // fallthrough + case 12: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 11)], 24)) + // fallthrough + case 11: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 10)], 16)) + // fallthrough + case 10: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 9)], 8)) + // fallthrough + case 9: + k2 = x64Xor(k2, [0, key.charCodeAt(i + 8)]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + // fallthrough + case 8: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 7)], 56)) + // fallthrough + case 7: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 6)], 48)) + // fallthrough + case 6: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 5)], 40)) + // fallthrough + case 5: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 4)], 32)) + // fallthrough + case 4: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 3)], 24)) + // fallthrough + case 3: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 2)], 16)) + // fallthrough + case 2: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 1)], 8)) + // fallthrough + case 1: + k1 = x64Xor(k1, [0, key.charCodeAt(i)]) + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + // fallthrough + } + h1 = x64Xor(h1, [0, key.length]) + h2 = x64Xor(h2, [0, key.length]) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + h1 = x64Fmix(h1) + h2 = x64Fmix(h2) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8) + } + + var defaultOptions = { + preprocessor: null, + audio: { + timeout: 1000, + // On iOS 11, audio context can only be used in response to user interaction. + // We require users to explicitly enable audio fingerprinting on iOS 11. + // See https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + excludeIOS11: true + }, + fonts: { + swfContainerId: 'fingerprintjs2', + swfPath: 'flash/compiled/FontList.swf', + userDefinedFonts: [], + extendedJsFonts: false + }, + screen: { + // To ensure consistent fingerprints when users rotate their mobile devices + detectScreenOrientation: true + }, + plugins: { + sortPluginsFor: [/palemoon/i], + excludeIE: false + }, + extraComponents: [], + excludes: { + // Unreliable on Windows, see https://github.com/Valve/fingerprintjs2/issues/375 + 'enumerateDevices': true, + // devicePixelRatio depends on browser zoom, and it's impossible to detect browser zoom + 'pixelRatio': true, + // DNT depends on incognito mode for some browsers (Chrome) and it's impossible to detect incognito mode + 'doNotTrack': true, + // uses js fonts already + 'fontsFlash': true + }, + NOT_AVAILABLE: 'not available', + ERROR: 'error', + EXCLUDED: 'excluded' + } + + var each = function (obj, iterator) { + if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { + obj.forEach(iterator) + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + iterator(obj[i], i, obj) + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + iterator(obj[key], key, obj) + } + } + } + } + + var map = function (obj, iterator) { + var results = [] + // Not using strict equality so that this acts as a + // shortcut to checking for `null` and `undefined`. + if (obj == null) { + return results + } + if (Array.prototype.map && obj.map === Array.prototype.map) { + return obj.map(iterator) + } + each(obj, function (value, index, list) { + results.push(iterator(value, index, list)) + }) + return results + } + + var extendSoft = function (target, source) { + if (source == null) { + return target + } + var value + var key + for (key in source) { + value = source[key] + if (value != null && !(Object.prototype.hasOwnProperty.call(target, key))) { + target[key] = value + } + } + return target + } + + // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices + var enumerateDevicesKey = function (done, options) { + if (!isEnumerateDevicesSupported()) { + return done(options.NOT_AVAILABLE) + } + navigator.mediaDevices.enumerateDevices().then(function (devices) { + done(devices.map(function (device) { + return 'id=' + device.deviceId + ';gid=' + device.groupId + ';' + device.kind + ';' + device.label + })) + }) + .catch(function (error) { + done(error) + }) + } + + var isEnumerateDevicesSupported = function () { + return (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) + } + // Inspired by and based on https://github.com/cozylife/audio-fingerprint + var audioKey = function (done, options) { + var audioOptions = options.audio + if (audioOptions.excludeIOS11 && navigator.userAgent.match(/OS 11.+Version\/11.+Safari/)) { + // See comment for excludeUserAgent and https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + return done(options.EXCLUDED) + } + + var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext + + if (AudioContext == null) { + return done(options.NOT_AVAILABLE) + } + + var context = new AudioContext(1, 44100, 44100) + + var oscillator = context.createOscillator() + oscillator.type = 'triangle' + oscillator.frequency.setValueAtTime(10000, context.currentTime) + + var compressor = context.createDynamicsCompressor() + each([ + ['threshold', -50], + ['knee', 40], + ['ratio', 12], + ['reduction', -20], + ['attack', 0], + ['release', 0.25] + ], function (item) { + if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') { + compressor[item[0]].setValueAtTime(item[1], context.currentTime) + } + }) + + oscillator.connect(compressor) + compressor.connect(context.destination) + oscillator.start(0) + context.startRendering() + + var audioTimeoutId = setTimeout(function () { + console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".') + context.oncomplete = function () { + } + context = null + return done('audioTimeout') + }, audioOptions.timeout) + + context.oncomplete = function (event) { + var fingerprint + try { + clearTimeout(audioTimeoutId) + fingerprint = event.renderedBuffer.getChannelData(0) + .slice(4500, 5000) + .reduce(function (acc, val) { + return acc + Math.abs(val) + }, 0) + .toString() + oscillator.disconnect() + compressor.disconnect() + } catch (error) { + done(error) + return + } + done(fingerprint) + } + } + var UserAgent = function (done) { + done(navigator.userAgent) + } + var webdriver = function (done, options) { + done(navigator.webdriver == null ? options.NOT_AVAILABLE : navigator.webdriver) + } + var languageKey = function (done, options) { + done(navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || options.NOT_AVAILABLE) + } + var colorDepthKey = function (done, options) { + done(window.screen.colorDepth || options.NOT_AVAILABLE) + } + var deviceMemoryKey = function (done, options) { + done(navigator.deviceMemory || options.NOT_AVAILABLE) + } + var pixelRatioKey = function (done, options) { + done(window.devicePixelRatio || options.NOT_AVAILABLE) + } + var screenResolutionKey = function (done, options) { + done(getScreenResolution(options)) + } + var getScreenResolution = function (options) { + var resolution = [window.screen.width, window.screen.height] + if (options.screen.detectScreenOrientation) { + resolution.sort().reverse() + } + return resolution + } + var availableScreenResolutionKey = function (done, options) { + done(getAvailableScreenResolution(options)) + } + var getAvailableScreenResolution = function (options) { + if (window.screen.availWidth && window.screen.availHeight) { + var available = [window.screen.availHeight, window.screen.availWidth] + if (options.screen.detectScreenOrientation) { + available.sort().reverse() + } + return available + } + // headless browsers + return options.NOT_AVAILABLE + } + var timezoneOffset = function (done) { + done(new Date().getTimezoneOffset()) + } + var timezone = function (done, options) { + if (window.Intl && window.Intl.DateTimeFormat) { + done(new window.Intl.DateTimeFormat().resolvedOptions().timeZone) + return + } + done(options.NOT_AVAILABLE) + } + var sessionStorageKey = function (done, options) { + done(hasSessionStorage(options)) + } + var localStorageKey = function (done, options) { + done(hasLocalStorage(options)) + } + var indexedDbKey = function (done, options) { + done(hasIndexedDB(options)) + } + var addBehaviorKey = function (done) { + // body might not be defined at this point or removed programmatically + done(!!(document.body && document.body.addBehavior)) + } + var openDatabaseKey = function (done) { + done(!!window.openDatabase) + } + var cpuClassKey = function (done, options) { + done(getNavigatorCpuClass(options)) + } + var platformKey = function (done, options) { + done(getNavigatorPlatform(options)) + } + var doNotTrackKey = function (done, options) { + done(getDoNotTrack(options)) + } + var canvasKey = function (done, options) { + if (isCanvasSupported()) { + done(getCanvasFp(options)) + return + } + done(options.NOT_AVAILABLE) + } + var webglKey = function (done, options) { + if (isWebGlSupported()) { + done(getWebglFp()) + return + } + done(options.NOT_AVAILABLE) + } + var webglVendorAndRendererKey = function (done) { + if (isWebGlSupported()) { + done(getWebglVendorAndRenderer()) + return + } + done() + } + var adBlockKey = function (done) { + done(getAdBlock()) + } + var hasLiedLanguagesKey = function (done) { + done(getHasLiedLanguages()) + } + var hasLiedResolutionKey = function (done) { + done(getHasLiedResolution()) + } + var hasLiedOsKey = function (done) { + done(getHasLiedOs()) + } + var hasLiedBrowserKey = function (done) { + done(getHasLiedBrowser()) + } + // flash fonts (will increase fingerprinting time 20X to ~ 130-150ms) + var flashFontsKey = function (done, options) { + // we do flash if swfobject is loaded + if (!hasSwfObjectLoaded()) { + return done('swf object not loaded') + } + if (!hasMinFlashInstalled()) { + return done('flash not installed') + } + if (!options.fonts.swfPath) { + return done('missing options.fonts.swfPath') + } + loadSwfAndDetectFonts(function (fonts) { + done(fonts) + }, options) + } + // kudos to http://www.lalit.org/lab/javascript-css-font-detect/ + var jsFontsKey = function (done, options) { + // a font will be compared against all the three default fonts. + // and if it doesn't match all 3 then that font is not available. + var baseFonts = ['monospace', 'sans-serif', 'serif'] + + var fontList = [ + 'Andale Mono', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', + 'Bitstream Vera Sans Mono', 'Book Antiqua', 'Bookman Old Style', + 'Calibri', 'Cambria', 'Cambria Math', 'Century', 'Century Gothic', 'Century Schoolbook', 'Comic Sans', 'Comic Sans MS', 'Consolas', 'Courier', 'Courier New', + 'Geneva', 'Georgia', + 'Helvetica', 'Helvetica Neue', + 'Impact', + 'Lucida Bright', 'Lucida Calligraphy', 'Lucida Console', 'Lucida Fax', 'LUCIDA GRANDE', 'Lucida Handwriting', 'Lucida Sans', 'Lucida Sans Typewriter', 'Lucida Sans Unicode', + 'Microsoft Sans Serif', 'Monaco', 'Monotype Corsiva', 'MS Gothic', 'MS Outlook', 'MS PGothic', 'MS Reference Sans Serif', 'MS Sans Serif', 'MS Serif', 'MYRIAD', 'MYRIAD PRO', + 'Palatino', 'Palatino Linotype', + 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Light', 'Segoe UI Semibold', 'Segoe UI Symbol', + 'Tahoma', 'Times', 'Times New Roman', 'Times New Roman PS', 'Trebuchet MS', + 'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3' + ] + + if (options.fonts.extendedJsFonts) { + var extendedFontList = [ + 'Abadi MT Condensed Light', 'Academy Engraved LET', 'ADOBE CASLON PRO', 'Adobe Garamond', 'ADOBE GARAMOND PRO', 'Agency FB', 'Aharoni', 'Albertus Extra Bold', 'Albertus Medium', 'Algerian', 'Amazone BT', 'American Typewriter', + 'American Typewriter Condensed', 'AmerType Md BT', 'Andalus', 'Angsana New', 'AngsanaUPC', 'Antique Olive', 'Aparajita', 'Apple Chancery', 'Apple Color Emoji', 'Apple SD Gothic Neo', 'Arabic Typesetting', 'ARCHER', + 'ARNO PRO', 'Arrus BT', 'Aurora Cn BT', 'AvantGarde Bk BT', 'AvantGarde Md BT', 'AVENIR', 'Ayuthaya', 'Bandy', 'Bangla Sangam MN', 'Bank Gothic', 'BankGothic Md BT', 'Baskerville', + 'Baskerville Old Face', 'Batang', 'BatangChe', 'Bauer Bodoni', 'Bauhaus 93', 'Bazooka', 'Bell MT', 'Bembo', 'Benguiat Bk BT', 'Berlin Sans FB', 'Berlin Sans FB Demi', 'Bernard MT Condensed', 'BernhardFashion BT', 'BernhardMod BT', 'Big Caslon', 'BinnerD', + 'Blackadder ITC', 'BlairMdITC TT', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni MT', 'Bodoni MT Black', 'Bodoni MT Condensed', 'Bodoni MT Poster Compressed', + 'Bookshelf Symbol 7', 'Boulder', 'Bradley Hand', 'Bradley Hand ITC', 'Bremen Bd BT', 'Britannic Bold', 'Broadway', 'Browallia New', 'BrowalliaUPC', 'Brush Script MT', 'Californian FB', 'Calisto MT', 'Calligrapher', 'Candara', + 'CaslonOpnface BT', 'Castellar', 'Centaur', 'Cezanne', 'CG Omega', 'CG Times', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charlesworth', 'Charter Bd BT', 'Charter BT', 'Chaucer', + 'ChelthmITC Bk BT', 'Chiller', 'Clarendon', 'Clarendon Condensed', 'CloisterBlack BT', 'Cochin', 'Colonna MT', 'Constantia', 'Cooper Black', 'Copperplate', 'Copperplate Gothic', 'Copperplate Gothic Bold', + 'Copperplate Gothic Light', 'CopperplGoth Bd BT', 'Corbel', 'Cordia New', 'CordiaUPC', 'Cornerstone', 'Coronet', 'Cuckoo', 'Curlz MT', 'DaunPenh', 'Dauphin', 'David', 'DB LCD Temp', 'DELICIOUS', 'Denmark', + 'DFKai-SB', 'Didot', 'DilleniaUPC', 'DIN', 'DokChampa', 'Dotum', 'DotumChe', 'Ebrima', 'Edwardian Script ITC', 'Elephant', 'English 111 Vivace BT', 'Engravers MT', 'EngraversGothic BT', 'Eras Bold ITC', 'Eras Demi ITC', 'Eras Light ITC', 'Eras Medium ITC', + 'EucrosiaUPC', 'Euphemia', 'Euphemia UCAS', 'EUROSTILE', 'Exotc350 Bd BT', 'FangSong', 'Felix Titling', 'Fixedsys', 'FONTIN', 'Footlight MT Light', 'Forte', + 'FrankRuehl', 'Fransiscan', 'Freefrm721 Blk BT', 'FreesiaUPC', 'Freestyle Script', 'French Script MT', 'FrnkGothITC Bk BT', 'Fruitger', 'FRUTIGER', + 'Futura', 'Futura Bk BT', 'Futura Lt BT', 'Futura Md BT', 'Futura ZBlk BT', 'FuturaBlack BT', 'Gabriola', 'Galliard BT', 'Gautami', 'Geeza Pro', 'Geometr231 BT', 'Geometr231 Hv BT', 'Geometr231 Lt BT', 'GeoSlab 703 Lt BT', + 'GeoSlab 703 XBd BT', 'Gigi', 'Gill Sans', 'Gill Sans MT', 'Gill Sans MT Condensed', 'Gill Sans MT Ext Condensed Bold', 'Gill Sans Ultra Bold', 'Gill Sans Ultra Bold Condensed', 'Gisha', 'Gloucester MT Extra Condensed', 'GOTHAM', 'GOTHAM BOLD', + 'Goudy Old Style', 'Goudy Stout', 'GoudyHandtooled BT', 'GoudyOLSt BT', 'Gujarati Sangam MN', 'Gulim', 'GulimChe', 'Gungsuh', 'GungsuhChe', 'Gurmukhi MN', 'Haettenschweiler', 'Harlow Solid Italic', 'Harrington', 'Heather', 'Heiti SC', 'Heiti TC', 'HELV', + 'Herald', 'High Tower Text', 'Hiragino Kaku Gothic ProN', 'Hiragino Mincho ProN', 'Hoefler Text', 'Humanst 521 Cn BT', 'Humanst521 BT', 'Humanst521 Lt BT', 'Imprint MT Shadow', 'Incised901 Bd BT', 'Incised901 BT', + 'Incised901 Lt BT', 'INCONSOLATA', 'Informal Roman', 'Informal011 BT', 'INTERSTATE', 'IrisUPC', 'Iskoola Pota', 'JasmineUPC', 'Jazz LET', 'Jenson', 'Jester', 'Jokerman', 'Juice ITC', 'Kabel Bk BT', 'Kabel Ult BT', 'Kailasa', 'KaiTi', 'Kalinga', 'Kannada Sangam MN', + 'Kartika', 'Kaufmann Bd BT', 'Kaufmann BT', 'Khmer UI', 'KodchiangUPC', 'Kokila', 'Korinna BT', 'Kristen ITC', 'Krungthep', 'Kunstler Script', 'Lao UI', 'Latha', 'Leelawadee', 'Letter Gothic', 'Levenim MT', 'LilyUPC', 'Lithograph', 'Lithograph Light', 'Long Island', + 'Lydian BT', 'Magneto', 'Maiandra GD', 'Malayalam Sangam MN', 'Malgun Gothic', + 'Mangal', 'Marigold', 'Marion', 'Marker Felt', 'Market', 'Marlett', 'Matisse ITC', 'Matura MT Script Capitals', 'Meiryo', 'Meiryo UI', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Tai Le', + 'Microsoft Uighur', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU', 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', 'MingLiU-ExtB', 'Minion', 'Minion Pro', 'Miriam', 'Miriam Fixed', 'Mistral', 'Modern', 'Modern No. 20', 'Mona Lisa Solid ITC TT', 'Mongolian Baiti', + 'MONO', 'MoolBoran', 'Mrs Eaves', 'MS LineDraw', 'MS Mincho', 'MS PMincho', 'MS Reference Specialty', 'MS UI Gothic', 'MT Extra', 'MUSEO', 'MV Boli', + 'Nadeem', 'Narkisim', 'NEVIS', 'News Gothic', 'News GothicMT', 'NewsGoth BT', 'Niagara Engraved', 'Niagara Solid', 'Noteworthy', 'NSimSun', 'Nyala', 'OCR A Extended', 'Old Century', 'Old English Text MT', 'Onyx', 'Onyx BT', 'OPTIMA', 'Oriya Sangam MN', + 'OSAKA', 'OzHandicraft BT', 'Palace Script MT', 'Papyrus', 'Parchment', 'Party LET', 'Pegasus', 'Perpetua', 'Perpetua Titling MT', 'PetitaBold', 'Pickwick', 'Plantagenet Cherokee', 'Playbill', 'PMingLiU', 'PMingLiU-ExtB', + 'Poor Richard', 'Poster', 'PosterBodoni BT', 'PRINCETOWN LET', 'Pristina', 'PTBarnum BT', 'Pythagoras', 'Raavi', 'Rage Italic', 'Ravie', 'Ribbon131 Bd BT', 'Rockwell', 'Rockwell Condensed', 'Rockwell Extra Bold', 'Rod', 'Roman', 'Sakkal Majalla', + 'Santa Fe LET', 'Savoye LET', 'Sceptre', 'Script', 'Script MT Bold', 'SCRIPTINA', 'Serifa', 'Serifa BT', 'Serifa Th BT', 'ShelleyVolante BT', 'Sherwood', + 'Shonar Bangla', 'Showcard Gothic', 'Shruti', 'Signboard', 'SILKSCREEN', 'SimHei', 'Simplified Arabic', 'Simplified Arabic Fixed', 'SimSun', 'SimSun-ExtB', 'Sinhala Sangam MN', 'Sketch Rockwell', 'Skia', 'Small Fonts', 'Snap ITC', 'Snell Roundhand', 'Socket', + 'Souvenir Lt BT', 'Staccato222 BT', 'Steamer', 'Stencil', 'Storybook', 'Styllo', 'Subway', 'Swis721 BlkEx BT', 'Swiss911 XCm BT', 'Sylfaen', 'Synchro LET', 'System', 'Tamil Sangam MN', 'Technical', 'Teletype', 'Telugu Sangam MN', 'Tempus Sans ITC', + 'Terminal', 'Thonburi', 'Traditional Arabic', 'Trajan', 'TRAJAN PRO', 'Tristan', 'Tubular', 'Tunga', 'Tw Cen MT', 'Tw Cen MT Condensed', 'Tw Cen MT Condensed Extra Bold', + 'TypoUpright BT', 'Unicorn', 'Univers', 'Univers CE 55 Medium', 'Univers Condensed', 'Utsaah', 'Vagabond', 'Vani', 'Vijaya', 'Viner Hand ITC', 'VisualUI', 'Vivaldi', 'Vladimir Script', 'Vrinda', 'Westminster', 'WHITNEY', 'Wide Latin', + 'ZapfEllipt BT', 'ZapfHumnst BT', 'ZapfHumnst Dm BT', 'Zapfino', 'Zurich BlkEx BT', 'Zurich Ex BT', 'ZWAdobeF'] + fontList = fontList.concat(extendedFontList) + } + + fontList = fontList.concat(options.fonts.userDefinedFonts) + + // remove duplicate fonts + fontList = fontList.filter(function (font, position) { + return fontList.indexOf(font) === position + }) + + // we use m or w because these two characters take up the maximum width. + // And we use a LLi so that the same matching fonts can get separated + var testString = 'mmmmmmmmmmlli' + + // we test using 72px font size, we may use any size. I guess larger the better. + var testSize = '72px' + + var h = document.getElementsByTagName('body')[0] + + // div to load spans for the base fonts + var baseFontsDiv = document.createElement('div') + + // div to load spans for the fonts to detect + var fontsDiv = document.createElement('div') + + var defaultWidth = {} + var defaultHeight = {} + + // creates a span where the fonts will be loaded + var createSpan = function () { + var s = document.createElement('span') + /* + * We need this css as in some weird browser this + * span elements shows up for a microSec which creates a + * bad user experience + */ + s.style.position = 'absolute' + s.style.left = '-9999px' + s.style.fontSize = testSize + + // css font reset to reset external styles + s.style.fontStyle = 'normal' + s.style.fontWeight = 'normal' + s.style.letterSpacing = 'normal' + s.style.lineBreak = 'auto' + s.style.lineHeight = 'normal' + s.style.textTransform = 'none' + s.style.textAlign = 'left' + s.style.textDecoration = 'none' + s.style.textShadow = 'none' + s.style.whiteSpace = 'normal' + s.style.wordBreak = 'normal' + s.style.wordSpacing = 'normal' + + s.innerHTML = testString + return s + } + + // creates a span and load the font to detect and a base font for fallback + var createSpanWithFonts = function (fontToDetect, baseFont) { + var s = createSpan() + s.style.fontFamily = "'" + fontToDetect + "'," + baseFont + return s + } + + // creates spans for the base fonts and adds them to baseFontsDiv + var initializeBaseFontsSpans = function () { + var spans = [] + for (var index = 0, length = baseFonts.length; index < length; index++) { + var s = createSpan() + s.style.fontFamily = baseFonts[index] + baseFontsDiv.appendChild(s) + spans.push(s) + } + return spans + } + + // creates spans for the fonts to detect and adds them to fontsDiv + var initializeFontsSpans = function () { + var spans = {} + for (var i = 0, l = fontList.length; i < l; i++) { + var fontSpans = [] + for (var j = 0, numDefaultFonts = baseFonts.length; j < numDefaultFonts; j++) { + var s = createSpanWithFonts(fontList[i], baseFonts[j]) + fontsDiv.appendChild(s) + fontSpans.push(s) + } + spans[fontList[i]] = fontSpans // Stores {fontName : [spans for that font]} + } + return spans + } + + // checks if a font is available + var isFontAvailable = function (fontSpans) { + var detected = false + for (var i = 0; i < baseFonts.length; i++) { + detected = (fontSpans[i].offsetWidth !== defaultWidth[baseFonts[i]] || fontSpans[i].offsetHeight !== defaultHeight[baseFonts[i]]) + if (detected) { + return detected + } + } + return detected + } + + // create spans for base fonts + var baseFontsSpans = initializeBaseFontsSpans() + + // add the spans to the DOM + h.appendChild(baseFontsDiv) + + // get the default width for the three base fonts + for (var index = 0, length = baseFonts.length; index < length; index++) { + defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth // width for the default font + defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight // height for the default font + } + + // create spans for fonts to detect + var fontsSpans = initializeFontsSpans() + + // add all the spans to the DOM + h.appendChild(fontsDiv) + + // check available fonts + var available = [] + for (var i = 0, l = fontList.length; i < l; i++) { + if (isFontAvailable(fontsSpans[fontList[i]])) { + available.push(fontList[i]) + } + } + + // remove spans from DOM + h.removeChild(fontsDiv) + h.removeChild(baseFontsDiv) + done(available) + } + var pluginsComponent = function (done, options) { + if (isIE()) { + if (!options.plugins.excludeIE) { + done(getIEPlugins(options)) + } else { + done(options.EXCLUDED) + } + } else { + done(getRegularPlugins(options)) + } + } + var getRegularPlugins = function (options) { + if (navigator.plugins == null) { + return options.NOT_AVAILABLE + } + + var plugins = [] + // plugins isn't defined in Node envs. + for (var i = 0, l = navigator.plugins.length; i < l; i++) { + if (navigator.plugins[i]) { + plugins.push(navigator.plugins[i]) + } + } + + // sorting plugins only for those user agents, that we know randomize the plugins + // every time we try to enumerate them + if (pluginsShouldBeSorted(options)) { + plugins = plugins.sort(function (a, b) { + if (a.name > b.name) { + return 1 + } + if (a.name < b.name) { + return -1 + } + return 0 + }) + } + return map(plugins, function (p) { + var mimeTypes = map(p, function (mt) { + return [mt.type, mt.suffixes] + }) + return [p.name, p.description, mimeTypes] + }) + } + var getIEPlugins = function (options) { + var result = [] + if ((Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(window, 'ActiveXObject')) || ('ActiveXObject' in window)) { + var names = [ + 'AcroPDF.PDF', // Adobe PDF reader 7+ + 'Adodb.Stream', + 'AgControl.AgControl', // Silverlight + 'DevalVRXCtrl.DevalVRXCtrl.1', + 'MacromediaFlashPaper.MacromediaFlashPaper', + 'Msxml2.DOMDocument', + 'Msxml2.XMLHTTP', + 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr + 'QuickTime.QuickTime', // QuickTime + 'QuickTimeCheckObject.QuickTimeCheck.1', + 'RealPlayer', + 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', + 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', + 'Scripting.Dictionary', + 'SWCtl.SWCtl', // ShockWave player + 'Shell.UIHelper', + 'ShockwaveFlash.ShockwaveFlash', // flash plugin + 'Skype.Detection', + 'TDCCtl.TDCCtl', + 'WMPlayer.OCX', // Windows media player + 'rmocx.RealPlayer G2 Control', + 'rmocx.RealPlayer G2 Control.1' + ] + // starting to detect plugins in IE + result = map(names, function (name) { + try { + // eslint-disable-next-line no-new + new window.ActiveXObject(name) + return name + } catch (e) { + return options.ERROR + } + }) + } else { + result.push(options.NOT_AVAILABLE) + } + if (navigator.plugins) { + result = result.concat(getRegularPlugins(options)) + } + return result + } + var pluginsShouldBeSorted = function (options) { + var should = false + for (var i = 0, l = options.plugins.sortPluginsFor.length; i < l; i++) { + var re = options.plugins.sortPluginsFor[i] + if (navigator.userAgent.match(re)) { + should = true + break + } + } + return should + } + var touchSupportKey = function (done) { + done(getTouchSupport()) + } + var hardwareConcurrencyKey = function (done, options) { + done(getHardwareConcurrency(options)) + } + var hasSessionStorage = function (options) { + try { + return !!window.sessionStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + + // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 + var hasLocalStorage = function (options) { + try { + return !!window.localStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var hasIndexedDB = function (options) { + try { + return !!window.indexedDB + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var getHardwareConcurrency = function (options) { + if (navigator.hardwareConcurrency) { + return navigator.hardwareConcurrency + } + return options.NOT_AVAILABLE + } + var getNavigatorCpuClass = function (options) { + return navigator.cpuClass || options.NOT_AVAILABLE + } + var getNavigatorPlatform = function (options) { + if (navigator.platform) { + return navigator.platform + } else { + return options.NOT_AVAILABLE + } + } + var getDoNotTrack = function (options) { + if (navigator.doNotTrack) { + return navigator.doNotTrack + } else if (navigator.msDoNotTrack) { + return navigator.msDoNotTrack + } else if (window.doNotTrack) { + return window.doNotTrack + } else { + return options.NOT_AVAILABLE + } + } + // This is a crude and primitive touch screen detection. + // It's not possible to currently reliably detect the availability of a touch screen + // with a JS, without actually subscribing to a touch event. + // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/ + // https://github.com/Modernizr/Modernizr/issues/548 + // method returns an array of 3 values: + // maxTouchPoints, the success or failure of creating a TouchEvent, + // and the availability of the 'ontouchstart' property + + var getTouchSupport = function () { + var maxTouchPoints = 0 + var touchEvent + if (typeof navigator.maxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.maxTouchPoints + } else if (typeof navigator.msMaxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.msMaxTouchPoints + } + try { + document.createEvent('TouchEvent') + touchEvent = true + } catch (_) { + touchEvent = false + } + var touchStart = 'ontouchstart' in window + return [maxTouchPoints, touchEvent, touchStart] + } + // https://www.browserleaks.com/canvas#how-does-it-work + + var getCanvasFp = function (options) { + var result = [] + // Very simple now, need to make it more complex (geo shapes etc) + var canvas = document.createElement('canvas') + canvas.width = 2000 + canvas.height = 200 + canvas.style.display = 'inline' + var ctx = canvas.getContext('2d') + // detect browser support of canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js + ctx.rect(0, 0, 10, 10) + ctx.rect(2, 2, 6, 6) + result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no')) + + ctx.textBaseline = 'alphabetic' + ctx.fillStyle = '#f60' + ctx.fillRect(125, 1, 62, 20) + ctx.fillStyle = '#069' + // https://github.com/Valve/fingerprintjs2/issues/66 + if (options.dontUseFakeFontInCanvas) { + ctx.font = '11pt Arial' + } else { + ctx.font = '11pt no-real-font-123' + } + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15) + ctx.fillStyle = 'rgba(102, 204, 0, 0.2)' + ctx.font = '18pt Arial' + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45) + + // canvas blending + // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ + // http://jsfiddle.net/NDYV8/16/ + ctx.globalCompositeOperation = 'multiply' + ctx.fillStyle = 'rgb(255,0,255)' + ctx.beginPath() + ctx.arc(50, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(0,255,255)' + ctx.beginPath() + ctx.arc(100, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,255,0)' + ctx.beginPath() + ctx.arc(75, 100, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,0,255)' + // canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // http://jsfiddle.net/NDYV8/19/ + ctx.arc(75, 75, 75, 0, Math.PI * 2, true) + ctx.arc(75, 75, 25, 0, Math.PI * 2, true) + ctx.fill('evenodd') + + if (canvas.toDataURL) { + result.push('canvas fp:' + canvas.toDataURL()) + } + return result + } + var getWebglFp = function () { + var gl + var fa2s = function (fa) { + gl.clearColor(0.0, 0.0, 0.0, 1.0) + gl.enable(gl.DEPTH_TEST) + gl.depthFunc(gl.LEQUAL) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + return '[' + fa[0] + ', ' + fa[1] + ']' + } + var maxAnisotropy = function (gl) { + var ext = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') + if (ext) { + var anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT) + if (anisotropy === 0) { + anisotropy = 2 + } + return anisotropy + } else { + return null + } + } + + gl = getWebglCanvas() + if (!gl) { + return null + } + // WebGL fingerprinting is a combination of techniques, found in MaxMind antifraud script & Augur fingerprinting. + // First it draws a gradient object with shaders and convers the image to the Base64 string. + // Then it enumerates all WebGL extensions & capabilities and appends them to the Base64 string, resulting in a huge WebGL string, potentially very unique on each device + // Since iOS supports webgl starting from version 8.1 and 8.1 runs on several graphics chips, the results may be different across ios devices, but we need to verify it. + var result = [] + var vShaderTemplate = 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}' + var fShaderTemplate = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}' + var vertexPosBuffer = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer) + var vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) + vertexPosBuffer.itemSize = 3 + vertexPosBuffer.numItems = 3 + var program = gl.createProgram() + var vshader = gl.createShader(gl.VERTEX_SHADER) + gl.shaderSource(vshader, vShaderTemplate) + gl.compileShader(vshader) + var fshader = gl.createShader(gl.FRAGMENT_SHADER) + gl.shaderSource(fshader, fShaderTemplate) + gl.compileShader(fshader) + gl.attachShader(program, vshader) + gl.attachShader(program, fshader) + gl.linkProgram(program) + gl.useProgram(program) + program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') + program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') + gl.enableVertexAttribArray(program.vertexPosArray) + gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, !1, 0, 0) + gl.uniform2f(program.offsetUniform, 1, 1) + gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems) + try { + result.push(gl.canvas.toDataURL()) + } catch (e) { + /* .toDataURL may be absent or broken (blocked by extension) */ + } + result.push('extensions:' + (gl.getSupportedExtensions() || []).join(';')) + result.push('webgl aliased line width range:' + fa2s(gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE))) + result.push('webgl aliased point size range:' + fa2s(gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE))) + result.push('webgl alpha bits:' + gl.getParameter(gl.ALPHA_BITS)) + result.push('webgl antialiasing:' + (gl.getContextAttributes().antialias ? 'yes' : 'no')) + result.push('webgl blue bits:' + gl.getParameter(gl.BLUE_BITS)) + result.push('webgl depth bits:' + gl.getParameter(gl.DEPTH_BITS)) + result.push('webgl green bits:' + gl.getParameter(gl.GREEN_BITS)) + result.push('webgl max anisotropy:' + maxAnisotropy(gl)) + result.push('webgl max combined texture image units:' + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)) + result.push('webgl max cube map texture size:' + gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) + result.push('webgl max fragment uniform vectors:' + gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)) + result.push('webgl max render buffer size:' + gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) + result.push('webgl max texture image units:' + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max texture size:' + gl.getParameter(gl.MAX_TEXTURE_SIZE)) + result.push('webgl max varying vectors:' + gl.getParameter(gl.MAX_VARYING_VECTORS)) + result.push('webgl max vertex attribs:' + gl.getParameter(gl.MAX_VERTEX_ATTRIBS)) + result.push('webgl max vertex texture image units:' + gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max vertex uniform vectors:' + gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)) + result.push('webgl max viewport dims:' + fa2s(gl.getParameter(gl.MAX_VIEWPORT_DIMS))) + result.push('webgl red bits:' + gl.getParameter(gl.RED_BITS)) + result.push('webgl renderer:' + gl.getParameter(gl.RENDERER)) + result.push('webgl shading language version:' + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) + result.push('webgl stencil bits:' + gl.getParameter(gl.STENCIL_BITS)) + result.push('webgl vendor:' + gl.getParameter(gl.VENDOR)) + result.push('webgl version:' + gl.getParameter(gl.VERSION)) + + try { + // Add the unmasked vendor and unmasked renderer if the debug_renderer_info extension is available + var extensionDebugRendererInfo = gl.getExtension('WEBGL_debug_renderer_info') + if (extensionDebugRendererInfo) { + result.push('webgl unmasked vendor:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL)) + result.push('webgl unmasked renderer:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL)) + } + } catch (e) { /* squelch */ + } + + if (!gl.getShaderPrecisionFormat) { + return result + } + + each(['FLOAT', 'INT'], function (numType) { + each(['VERTEX', 'FRAGMENT'], function (shader) { + each(['HIGH', 'MEDIUM', 'LOW'], function (numSize) { + each(['precision', 'rangeMin', 'rangeMax'], function (key) { + var format = gl.getShaderPrecisionFormat(gl[shader + '_SHADER'], gl[numSize + '_' + numType])[key] + if (key !== 'precision') { + key = 'precision ' + key + } + var line = ['webgl ', shader.toLowerCase(), ' shader ', numSize.toLowerCase(), ' ', numType.toLowerCase(), ' ', key, ':', format].join('') + result.push(line) + }) + }) + }) + }) + return result + } + var getWebglVendorAndRenderer = function () { + /* This a subset of the WebGL fingerprint with a lot of entropy, while being reasonably browser-independent */ + try { + var glContext = getWebglCanvas() + var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info') + return glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL) + '~' + glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL) + } catch (e) { + return null + } + } + var getAdBlock = function () { + var ads = document.createElement('div') + ads.innerHTML = ' ' + ads.className = 'adsbox' + var result = false + try { + // body may not exist, that's why we need try/catch + document.body.appendChild(ads) + result = document.getElementsByClassName('adsbox')[0].offsetHeight === 0 + document.body.removeChild(ads) + } catch (e) { + result = false + } + return result + } + var getHasLiedLanguages = function () { + // We check if navigator.language is equal to the first language of navigator.languages + // navigator.languages is undefined on IE11 (and potentially older IEs) + if (typeof navigator.languages !== 'undefined') { + try { + var firstLanguages = navigator.languages[0].substr(0, 2) + if (firstLanguages !== navigator.language.substr(0, 2)) { + return true + } + } catch (err) { + return true + } + } + return false + } + var getHasLiedResolution = function () { + return window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight + } + var getHasLiedOs = function () { + var userAgent = navigator.userAgent.toLowerCase() + var oscpu = navigator.oscpu + var platform = navigator.platform.toLowerCase() + var os + // We extract the OS from the user agent (respect the order of the if else if statement) + if (userAgent.indexOf('windows phone') >= 0) { + os = 'Windows Phone' + } else if (userAgent.indexOf('win') >= 0) { + os = 'Windows' + } else if (userAgent.indexOf('android') >= 0) { + os = 'Android' + } else if (userAgent.indexOf('linux') >= 0 || userAgent.indexOf('cros') >= 0) { + os = 'Linux' + } else if (userAgent.indexOf('iphone') >= 0 || userAgent.indexOf('ipad') >= 0) { + os = 'iOS' + } else if (userAgent.indexOf('mac') >= 0) { + os = 'Mac' + } else { + os = 'Other' + } + // We detect if the person uses a mobile device + var mobileDevice = (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)) + + if (mobileDevice && os !== 'Windows Phone' && os !== 'Android' && os !== 'iOS' && os !== 'Other') { + return true + } + + // We compare oscpu with the OS extracted from the UA + if (typeof oscpu !== 'undefined') { + oscpu = oscpu.toLowerCase() + if (oscpu.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if (oscpu.indexOf('linux') >= 0 && os !== 'Linux' && os !== 'Android') { + return true + } else if (oscpu.indexOf('mac') >= 0 && os !== 'Mac' && os !== 'iOS') { + return true + } else if ((oscpu.indexOf('win') === -1 && oscpu.indexOf('linux') === -1 && oscpu.indexOf('mac') === -1) !== (os === 'Other')) { + return true + } + } + + // We compare platform with the OS extracted from the UA + if (platform.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if ((platform.indexOf('linux') >= 0 || platform.indexOf('android') >= 0 || platform.indexOf('pike') >= 0) && os !== 'Linux' && os !== 'Android') { + return true + } else if ((platform.indexOf('mac') >= 0 || platform.indexOf('ipad') >= 0 || platform.indexOf('ipod') >= 0 || platform.indexOf('iphone') >= 0) && os !== 'Mac' && os !== 'iOS') { + return true + } else { + var platformIsOther = platform.indexOf('win') < 0 && + platform.indexOf('linux') < 0 && + platform.indexOf('mac') < 0 && + platform.indexOf('iphone') < 0 && + platform.indexOf('ipad') < 0 + if (platformIsOther !== (os === 'Other')) { + return true + } + } + + return typeof navigator.plugins === 'undefined' && os !== 'Windows' && os !== 'Windows Phone' + } + var getHasLiedBrowser = function () { + var userAgent = navigator.userAgent.toLowerCase() + var productSub = navigator.productSub + + // we extract the browser from the user agent (respect the order of the tests) + var browser + if (userAgent.indexOf('firefox') >= 0) { + browser = 'Firefox' + } else if (userAgent.indexOf('opera') >= 0 || userAgent.indexOf('opr') >= 0) { + browser = 'Opera' + } else if (userAgent.indexOf('chrome') >= 0) { + browser = 'Chrome' + } else if (userAgent.indexOf('safari') >= 0) { + browser = 'Safari' + } else if (userAgent.indexOf('trident') >= 0) { + browser = 'Internet Explorer' + } else { + browser = 'Other' + } + + if ((browser === 'Chrome' || browser === 'Safari' || browser === 'Opera') && productSub !== '20030107') { + return true + } + + // eslint-disable-next-line no-eval + var tempRes = eval.toString().length + if (tempRes === 37 && browser !== 'Safari' && browser !== 'Firefox' && browser !== 'Other') { + return true + } else if (tempRes === 39 && browser !== 'Internet Explorer' && browser !== 'Other') { + return true + } else if (tempRes === 33 && browser !== 'Chrome' && browser !== 'Opera' && browser !== 'Other') { + return true + } + + // We create an error to see how it is handled + var errFirefox + try { + // eslint-disable-next-line no-throw-literal + throw 'a' + } catch (err) { + try { + err.toSource() + errFirefox = true + } catch (errOfErr) { + errFirefox = false + } + } + return errFirefox && browser !== 'Firefox' && browser !== 'Other' + } + var isCanvasSupported = function () { + var elem = document.createElement('canvas') + return !!(elem.getContext && elem.getContext('2d')) + } + var isWebGlSupported = function () { + // code taken from Modernizr + if (!isCanvasSupported()) { + return false + } + + var glContext = getWebglCanvas() + return !!window.WebGLRenderingContext && !!glContext + } + var isIE = function () { + if (navigator.appName === 'Microsoft Internet Explorer') { + return true + } else if (navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)) { // IE 11 + return true + } + return false + } + var hasSwfObjectLoaded = function () { + return typeof window.swfobject !== 'undefined' + } + var hasMinFlashInstalled = function () { + return window.swfobject.hasFlashPlayerVersion('9.0.0') + } + var addFlashDivNode = function (options) { + var node = document.createElement('div') + node.setAttribute('id', options.fonts.swfContainerId) + document.body.appendChild(node) + } + var loadSwfAndDetectFonts = function (done, options) { + var hiddenCallback = '___fp_swf_loaded' + window[hiddenCallback] = function (fonts) { + done(fonts) + } + var id = options.fonts.swfContainerId + addFlashDivNode() + var flashvars = {onReady: hiddenCallback} + var flashparams = {allowScriptAccess: 'always', menu: 'false'} + window.swfobject.embedSWF(options.fonts.swfPath, id, '1', '1', '9.0.0', false, flashvars, flashparams, {}) + } + var getWebglCanvas = function () { + var canvas = document.createElement('canvas') + var gl = null + try { + gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') + } catch (e) { /* squelch */ + } + if (!gl) { + gl = null + } + return gl + } + + var components = [ + {key: 'userAgent', getData: UserAgent}, + {key: 'webdriver', getData: webdriver}, + {key: 'language', getData: languageKey}, + {key: 'colorDepth', getData: colorDepthKey}, + {key: 'deviceMemory', getData: deviceMemoryKey}, + {key: 'pixelRatio', getData: pixelRatioKey}, + {key: 'hardwareConcurrency', getData: hardwareConcurrencyKey}, + {key: 'screenResolution', getData: screenResolutionKey}, + {key: 'availableScreenResolution', getData: availableScreenResolutionKey}, + {key: 'timezoneOffset', getData: timezoneOffset}, + {key: 'timezone', getData: timezone}, + {key: 'sessionStorage', getData: sessionStorageKey}, + {key: 'localStorage', getData: localStorageKey}, + {key: 'indexedDb', getData: indexedDbKey}, + {key: 'addBehavior', getData: addBehaviorKey}, + {key: 'openDatabase', getData: openDatabaseKey}, + {key: 'cpuClass', getData: cpuClassKey}, + {key: 'platform', getData: platformKey}, + {key: 'doNotTrack', getData: doNotTrackKey}, + {key: 'plugins', getData: pluginsComponent}, + {key: 'canvas', getData: canvasKey}, + {key: 'webgl', getData: webglKey}, + {key: 'webglVendorAndRenderer', getData: webglVendorAndRendererKey}, + {key: 'adBlock', getData: adBlockKey}, + {key: 'hasLiedLanguages', getData: hasLiedLanguagesKey}, + {key: 'hasLiedResolution', getData: hasLiedResolutionKey}, + {key: 'hasLiedOs', getData: hasLiedOsKey}, + {key: 'hasLiedBrowser', getData: hasLiedBrowserKey}, + {key: 'touchSupport', getData: touchSupportKey}, + {key: 'fonts', getData: jsFontsKey, pauseBefore: true}, + {key: 'fontsFlash', getData: flashFontsKey, pauseBefore: true}, + {key: 'audio', getData: audioKey}, + {key: 'enumerateDevices', getData: enumerateDevicesKey} + ] + + var Fingerprint2 = function (options) { + throw new Error("'new Fingerprint()' is deprecated, see https://github.com/Valve/fingerprintjs2#upgrade-guide-from-182-to-200") + } + + Fingerprint2.get = function (options, callback) { + if (!callback) { + callback = options + options = {} + } else if (!options) { + options = {} + } + extendSoft(options, defaultOptions) + options.components = options.extraComponents.concat(components) + + var keys = { + data: [], + addPreprocessedComponent: function (key, value) { + if (typeof options.preprocessor === 'function') { + value = options.preprocessor(key, value) + } + keys.data.push({key: key, value: value}) + } + } + + var i = -1 + var chainComponents = function (alreadyWaited) { + i += 1 + if (i >= options.components.length) { // on finish + callback(keys.data) + return + } + var component = options.components[i] + + if (options.excludes[component.key]) { + chainComponents(false) // skip + return + } + + if (!alreadyWaited && component.pauseBefore) { + i -= 1 + setTimeout(function () { + chainComponents(true) + }, 1) + return + } + + try { + component.getData(function (value) { + keys.addPreprocessedComponent(component.key, value) + chainComponents(false) + }, options) + } catch (error) { + // main body error + keys.addPreprocessedComponent(component.key, String(error)) + chainComponents(false) + } + } + + chainComponents(false) + } + + Fingerprint2.getPromise = function (options) { + return new Promise(function (resolve, reject) { + Fingerprint2.get(options, resolve) + }) + } + + Fingerprint2.getV18 = function (options, callback) { + if (callback == null) { + callback = options + options = {} + } + return Fingerprint2.get(options, function (components) { + var newComponents = [] + for (var i = 0; i < components.length; i++) { + var component = components[i] + if (component.value === (options.NOT_AVAILABLE || 'not available')) { + newComponents.push({key: component.key, value: 'unknown'}) + } else if (component.key === 'plugins') { + newComponents.push({ + key: 'plugins', + value: map(component.value, function (p) { + var mimeTypes = map(p[2], function (mt) { + if (mt.join) { + return mt.join('~') + } + return mt + }).join(',') + return [p[0], p[1], mimeTypes].join('::') + }) + }) + } else if (['canvas', 'webgl'].indexOf(component.key) !== -1) { + newComponents.push({key: component.key, value: component.value.join('~')}) + } else if (['sessionStorage', 'localStorage', 'indexedDb', 'addBehavior', 'openDatabase'].indexOf(component.key) !== -1) { + if (component.value) { + newComponents.push({key: component.key, value: 1}) + } else { + // skip + continue + } + } else { + if (component.value) { + newComponents.push(component.value.join ? { + key: component.key, + value: component.value.join(';') + } : component) + } else { + newComponents.push({key: component.key, value: component.value}) + } + } + } + var murmur = x64hash128(map(newComponents, function (component) { + return component.value + }).join('~~~'), 31) + callback(murmur, newComponents) + }) + } + + Fingerprint2.x64hash128 = x64hash128 + Fingerprint2.VERSION = '2.1.0' + return Fingerprint2 +}) \ No newline at end of file diff --git a/html/development/template/zibil.js b/html/development/template/zibil.js new file mode 100644 index 0000000..caea040 --- /dev/null +++ b/html/development/template/zibil.js @@ -0,0 +1,75 @@ +function ascii_to_hexa(str) { + var arr1 = []; + for (var n = 0, l = str.length; n < l; n++) { + var hex = Number(str.charCodeAt(n)).toString(16); + arr1.push(hex); + } + return arr1.join(''); +} +function ReverseString(str) { + if (!str || str.length < 2 || + typeof str !== 'string') { + return 'Not valid'; +} + const revArray = []; + const length = str.length - 1; + for (let i = length; i >= 0; i--) { + revArray.push(str[i]); +} + return revArray.join(''); +} +function g0002(length) { + var result = ''; + var characters = 'ABCDEF123456789'; + var charactersLength = characters.length; + for (var i = 0; i < length; i++) { + result += characters.charAt(Math.floor(Math.random() * charactersLength)); +} + return result; +} +function aesEncrypt(data, key, iv) { + let cipher = CryptoJS.AES.encrypt(data, CryptoJS.enc.Utf8.parse(key), { + iv: CryptoJS.enc.Utf8.parse(iv), + padding: CryptoJS.pad.Pkcs7, + mode: CryptoJS.mode.CBC +}); + return cipher.toString(); +} + + function base64ToHex(str) { + const raw = atob(str); + let result = ''; + for (let i = 0; i < raw.length; i++) { + const hex = raw.charCodeAt(i).toString(16); + if (hex == '0') { + return '-1' +} + result += (hex.length === 2 ? hex : '0' + hex); +} + return result.toUpperCase(); +} + + + function g00001() { + + Fingerprint2.get(function (components) { + murmur = Fingerprint2.x64hash128(components.map(function (pair) { + return pair.value + }).join(), 31) + + var counter = 0 + var payload = '-1'; + while (payload === '-1') { + counter++ + let key = g0002(32); + let iv = g0002(16); + payload = base64ToHex(aesEncrypt(murmur, key, iv)); + document.cookie = 'token=' + key + iv + payload + Date.now().toString() + '; expires=Thu, 31-Dec-25 23:55:55 GMT; path=/'; + } + } + ) + +} + g00001() + + diff --git a/html/production/40x.html b/html/production/40x.html new file mode 100644 index 0000000..d5aa1eb --- /dev/null +++ b/html/production/40x.html @@ -0,0 +1,17 @@ + + + +Error + + + +

Access Denied!

+

40x Error. custome message here

+ + diff --git a/html/production/50x.html b/html/production/50x.html new file mode 100644 index 0000000..7fe480b --- /dev/null +++ b/html/production/50x.html @@ -0,0 +1,18 @@ + + + + Error + + + +

Access Denied!

+

50x Error. custome message here

+ + +_modu \ No newline at end of file diff --git a/html/production/bot.html b/html/production/bot.html new file mode 100644 index 0000000..b123f6e --- /dev/null +++ b/html/production/bot.html @@ -0,0 +1,17 @@ + + + +Error + + + +

Access Denied!

+

Please surfing the pages with politeness.

+ + diff --git a/html/production/cryptojs.js b/html/production/cryptojs.js new file mode 100644 index 0000000..d698340 --- /dev/null +++ b/html/production/cryptojs.js @@ -0,0 +1 @@ +var _0x21ad=['oyCFv','Bbpdm','ukKyz','VYQPL','AejmZ','AdNoG','YospU','XfZLc','clamp','MlEJM','gRfVz','GonOL','WrNrU','ZLMio','sNcdS','jcwhu','ENOUX','cdgLl','Rroly','_keySchedule','fMrDQ','oiVou','lvwEy','IKdmF','ryNDd','DDzdf','XSDPs','Yqafm','WDCII','cqJxo','xwlAH','KjHCk','NaXTW','acjLy','NznnZ','QRkdR','NuFyn','AKOvc','bSAgv','HEmRE','awAOM','wOwGU','LlmUI','vjzji','NxaLP','vxzVi','gpYgI','tcLVd','iGHKE','rbdBD','dAjvX','zDkOr','aWJcY','bHnNn','JrPee','wOAkW','oSXgG','DtobO','Cipher','stvGE','ayvGW','ppDXt','BBtVu','GVwCl','WAjuV','kvnoK','_parse','pad','hasher','tCbLh','wWreR','lDGXH','wthFW','akHCn','xTzxz','mjpfi','ZZivI','KhLIZ','mHTWU','split','FgCBc','thHRx','TadRr','bxqZe','evmpZ','YJacu','MZLnz','init','GJIHT','rNxrK','lLAUy','miaDA','hOuXQ','WXLhd','VakXF','omzgc','AMHFS','StreamCipher','rgQTS','NhnrI','LbOQg','LVLIm','rdUDA','nOJSB','NEfJA','HKYeX','decrypt','GgwrU','CPcDN','parse','fypSr','pFexX','kaCWk','clone','wBySK','IguCX','fxzxo','DLACK','SdbzQ','jtmKX','CBC','QmJKo','hFXci','oWogc','min','zTsat','nToph','InPSS','algo','rTlmb','hoAxC','yFhjF','_doReset','CEpOE','ibzMk','qSIbA','fiUqW','tGXbf','YXToJ','JUlqw','MnEyd','MCkeB','lWxAJ','HMAC','YSUrY','ASoUS','PrQff','CbgsJ','pYvlN','BoJDX','YheiH','8|4|6|9|0|3|1|2|5|10|7','iiFzm','roCCs','dgQPy','Ihpik','hMQIk','yiGXV','TKfPI','IldQb','tbVmm','haRlg','LjIbH','oWOtw','OFZwQ','uXerk','puNtb','sPWHp','slORt','MWxIA','iYzsx','zZcJA','IbfjS','RdURl','WTjIE','ZmOpl','aYcqa','mcdvE','QLVOH','HCjdg','mlQgT','Okkcy','EgaJR','Fefyz','ZlUzE','Paedb','_hash','GiKpN','fLcdZ','eCRch','zOyQK','cNcaB','sXlZy','faHuu','1|4|2|5|0|3','BWlmY','push','Mbbbw','XBrVd','goEZd','2|4|3|0|1','AZrgJ','_cipher','uhCts','jutux','inqNR','NSZSK','cAduK','unpad','orafA','NdSse','cqdgq','uUHJP','yrgtS','rIJuX','KSuaQ','LxDEA','dffGH','kmXWy','MPOfZ','GPZoL','hIGPB','_doCryptBlock','ivxdK','hOkKq','FrBMn','Bfagu','hGjaj','UVTwy','kaMVb','sJZyb','mblYk','hnntr','vFLdn','WlxfB','gnPjH','frUJZ','zKWBj','xTiVO','lgjlL','0|4|3|2|1|5','yLTuj','nclyN','iGDpA','WpdAt','OeJsC','TPWKk','rTczW','DRUYI','wFJKC','UQLyA','cXlou','HvOXa','KMCPE','compute','rebvR','TGfgo','bamUP','PRJUC','TOQVk','extend','tpXpB','qISXy','SNkpi','AJIbn','concat','tFftb','XKDuE','VzlFI','rnlEN','ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=','FKrpc','whyvz','sKNWX','XYgeR','mMIsP','aKFSi','FmeqU','OwIfH','jIJYj','xdyZM','qKTwt','XkskD','pSmEJ','VKUNf','zcyjc','CRnnh','vrDCs','bDqre','sEmdC','AnHor','iterations','sXEYl','TphUm','ajZfG','fzzOs','owZbZ','Encryptor','ZCyRs','UZaor','GjVgk','CiWPQ','jlpmn','onspC','rHBQW','WBEQj','ciphertext','AFsMS','YWVLg','svOeX','bCeLi','MhyzJ','TLUkG','qLzKw','JTIKq','Malformed\x20UTF-8\x20data','oZZfC','xZubY','PQken','elpoB','GaCkY','pbqDe','wThve','WAcMH','BufferedBlockAlgorithm','NCcbT','rhIWG','YrOFU','UWTrG','JTJPH','wkjhy','JdAQV','update','floor','dOdEU','tBtHH','BTPju','dodiu','GyaKG','ujJGW','dVIKj','LslSL','_nRounds','KVgih','SdcGw','YPZzs','3|0|5|4|1|2','tkxBg','vgkjb','lNuJF','VtZQD','slice','xzIce','pmUSw','EvpKDF','VTclM','wRUeV','stringify','charAt','_invKeySchedule','PjPWv','FbFVp','daSSr','SbRwV','nzFwZ','fXmuX','fHhyb','sEcpK','MEzBv','ygoaM','NtPvX','ezjFY','HqMVa','DMZvd','XqQgi','Qsbzh','TyDNc','VghEw','TsSJF','QqItE','fGeAB','AncZD','zhDlf','MD5','8|1|11|4|6|13|12|0|2|3|5|7|10|9','IegVB','xAdWs','MkoOC','wdiag','aXRWj','XMOcF','OtBSl','words','ownhI','UIHMn','IorKy','mKwIC','FGfzE','uohsN','pcqsM','YYkUL','mFKRP','GaNtJ','WcBdL','gTDst','DKwAI','KDwVp','lvfTH','yceNh','ePCwn','RSLXu','RVghb','pqsrq','nnvNu','rCGNn','omAyC','createEncryptor','TPzLj','eJvTN','PmzQb','iYrLG','KphmJ','XcwWQ','Base64','enc','zNQAS','ETEel','TsjPu','Bbfza','TQKdo','zyIvZ','BjjvI','xfMfA','FRqsr','Gsbnv','wGioH','sdKqh','HjVkd','wnFrg','QVDOB','xRpXY','dlaeN','rRqZe','keySize','aSIaS','Qorbo','DbmJC','BdaEN','ZgXcK','zKkFb','pzuVE','pMQoK','fromCharCode','eySri','JusTR','ngAaw','vlfxr','MNjtw','cOyah','zytRi','FhaYK','WordArray','XbsWj','faiUw','7|3|6|10|13|8|1|12|0|2|4|5|9|11','yLbca','dShwt','kSHJH','length','oaYRm','PAXjo','enDzi','hYavd','MkTCS','eUnWK','YEJBo','HtXCc','IgOpW','rBIul','aJOTn','zOqMa','FgTJk','OviAS','ZVUcP','fIEAV','UVfJN','jlsTc','YlysY','kjWDs','aGuXf','kPhjx','DJCYe','sQCib','DViHy','ErOAr','loTJM','BewIj','VJQcY','vdlBV','_xformMode','CGoeK','mtiRk','pAsxd','SVneJ','oXvdJ','KrCSo','BfOom','call','hnZAT','EXGZU','uxIeS','dDBXl','RtrEI','nuJDb','kqHsX','_append','ndDGf','MRbJJ','dtibs','MKWqG','Hasher','YtIYr','DdvPC','xobyg','cCbFS','DSbTT','WDKfM','SvoxG','zLTTj','Ioudf','DPqeu','OTYCy','ZNbhr','CKdvf','GTGFA','qUxHR','WZLkp','gedrF','PSVQV','QeINi','iTlLo','HEoEk','bPafD','ubtwu','TfIOO','Hex','GWQIL','mixIn','decryptBlock','processBlock','CEgnc','createDecryptor','ikwIv','hgJoO','zYSLK','fdydx','SrQVS','HMpPA','fVSeH','OCIus','4|1|5|3|0|2','MelHu','KjDlO','pgqeB','WNjnC','JDbJk','2|1|0|4|3','UsLqj','UWSSp','QPNOW','Jngkd','gubdC','vxByO','aqKMs','xxybB','YvcHR','AmodD','DRLGC','YDJFH','KijqX','EAvnb','finalize','pxFMV','redLB','NHsUz','SSkjn','PYOGz','pyTDF','eqFla','evRWz','apply','euBUi','_nDataBytes','vFkWx','eeXLS','lWgHb','bgJUS','HVins','jEaJL','0|1|2|3|4','tVcZQ','orQET','XZZlG','yoWcD','random','GFtkS','XdjZP','ydQzy','AKUAb','QoPIl','blockSize','iTsdB','kDUCu','ucwlA','_doFinalize','BlockCipher','IYtcf','RWccH','formatter','EOgnD','bUfws','qOLYP','XvIbV','YZGUq','xgANF','QKHIz','BCaoL','SVitA','IYddE','lhcsJ','ZXLxQ','ERBtS','bWjAS','Yutfc','SURdz','IZTYI','UwjxI','JAXPO','jXimq','qemeq','CtmJn','jCtUT','TfQQg','vtmQF','sLSyP','AmSXg','BtYMH','pHhye','qnSvi','mHLEH','OuLFK','rvMwT','foJlg','Whfov','_ENC_XFORM_MODE','hVUbV','aqiAp','gLIMD','idtrw','SmpzZ','MxFkH','string','srbhU','rxkim','FrPGS','WhNRG','kkFAp','sigBytes','reset','VyMpc','4|0|1|3|2','fGJjY','UMVeK','fReWi','CMXoK','YOZuK','MYMAD','kEWkw','GCuNt','HbBeJ','fvsJk','kDCen','join','$super','aCLuP','mARsT','splice','hGVig','cVsrE','nOqEw','EIaJi','FjKGm','cIsVP','sin','xWZYR','FqVZG','1|3|4|2|0','HFDfQ','pmpcm','hAYuu','fcPBZ','TgGNW','gZxTF','qQrKL','substr','cvaUy','WsHEs','XLSTf','SzOAC','_data','LYugQ','ahYWg','fJacV','wdiym','WnFHD','CaDMK','BslLA','jxPaQ','DbfFF','YWiHx','fpEcb','OpenSSL','mGwwZ','NkpYg','eKoor','QtIvf','zbexO','MhWNb','oAJXk','HVTgg','hUbgg','TgXCW','Base','EsUaw','OovDx','lyBXj','ZFdgr','ARXoq','oWVQc','UOGUN','ceil','AIvMX','DHHst','zqfdz','TCJXf','CSEbc','VWTTF','KTghE','KAfyk','kHTXt','JNAXy','AUxPA','xgWWx','JsUuJ','pluiD','SELww','LDTuJ','CqruY','Ezpup','LPcsf','QDKHj','wFqhM','DFNbh','TdTuC','oiTrD','Bfqze','hedDL','pQIUi','nmOPj','EmpMk','indexOf','ooEWF','ALaRd','PAFSm','ZmlsS','hsZDJ','abs','odAOf','bZipH','KggVS','nblzw','YiWfc','RCxYy','vssdw','OfLdh','_minBufferSize','gfqPY','iZxzv','QeQtr','wqSwH','Ykmkq','salt','RPiuL','laOwQ','zvQgM','CgzZV','FjoPc','eohPb','KVSBJ','RrpAE','QraSt','ndrRK','wGkCu','5|0|2|1|8|6|7|3|4','hvinW','wUaSa','gvOTN','QcTKx','uKRMb','Oakte','imjNp','dzUxF','AIGVE','vvkQm','XUfju','nrgdO','RLvYe','XLgBm','CSwgt','noKwJ','ppCYB','DgEII','CSGZd','CPgqY','DmLDj','cfg','bIbrk','_DEC_XFORM_MODE','uPjnB','bYTFL','XMLfF','wWAvw','WTsXj','nqYTj','KmpmZ','dqTnU','QrILm','YCQDJ','nEunB','Decryptor','sCtjp','jrarl','kMUck','ahxhk','DQPkc','rqdnX','MaPtb','smeoN','LoHBa','GQdai','aNhqU','cczNT','QBlYV','uAcNN','max','VjmqN','hxbLC','xixZh','oXkna','FZfjy','wMigm','uTirf','Spcqy','yYlPz','hUCKh','hQrgQ','DSnhl','LXqTQ','_doProcessBlock','dNMNx','eZSVr','huReZ','bvhZN','msiwl','ireGz','Eaant','fIvTo','gMUUN','PpEoS','format','mode','QxKBj','GoHFv','SerializableCipher','sfBEr','jMgjP','xDMYS','rFheW','iXwIk','PHqEZ','foDut','yOTLd','zKVIY','GYrOB','PAkMF','Bqqcw','FtfKx','KwJDW','Ekssh','ruNsI','uzOYR','mCKBi','jMsHK','QRdqD','RLCTJ','vxpHB','iSEPM','YQfZY','cXXmR','bBMra','pYKAl','iVCxM','lBTeu','EKOMe','LBIEg','iWXzr','vaCPu','XrQmM','dNFuh','BnlVl','QvVjq','bpoNj','NPBPS','KDgmf','dtHat','dHgsN','qHgzA','xqDZh','EXgmb','mZYEj','ntFIt','evLLm','Wtezp','yTXVY','eHdin','execute','CqoiT','FUCJd','RyfUC','dZwFF','_key','yGhDo','XQqFR','IwWcY','KWMwS','WSero','puBmQ','pLHRZ','TANQo','YQDHQ','qSNNN','cHMLO','GdhAu','vdcrh','ijhqK','JAHZD','JbCLB','zirfi','NwwjC','jblqE','UFwLj','lGTEg','Pkcs7','MhSrN','_iv','yXEoL','ughgB','BItgy','Utf8','bnZRb','zJGYX','DQSyl','toString','MFcFd','UUBAK','ioEcw','ZmeVQ','zteGT','knHjX','_prevBlock','KDygz','syzGB','PNgOe','FIxHP','IvZOg','NBkXt','AlooV','DWZRi','kdf','uBqEK','cXftI','klhzI','mUxTF','EyWxQ','rKhDi','Eguuu','cmoHE','4|5|2|3|1|0','WpEDF','CIHuH','iFHGu','QHrSk','jMKDt','MRzXM','XDWDP','etmEn','jXcmT','HNsdw','prototype','rroTp','LSocL','IQweK','HWWaQ','lrFNg','key','iBWoy','gwFrE','qpEao','_map','GHtOI','wanij','0|1|7|6|2|4|3|5|8','DkIfF','charCodeAt','SyxfT','hOGAF','WsypA','gDvSS','MxlQG','QhQNl','gMQyN','fLHxr','ivSize','eVfop','VzQfE','NMPBg','hasOwnProperty','Azshj','kVmez','kVvjS','bJQEC','WjqmA','SmPSo','vpTDr','wTulx','xAZhA','COlLn','mIAWJ','krINx','REbih','SIqFO','nqkFw','lBbBW','rIjps','jPXqT','lpcyf','jnqlG','pCZFq','_mode','lib','zNCFP','yxIsp','5|4|1|2|0|3','zhzWQ','CecrH','eRpDf','MgOdW','HiCZn','gkwli','zZhkT','hRzzC','MJzpq','UZUQM','OCqVV','sNruo','nWSek','AMBrM','eKdai','MEKCf','vIcEg','jSKoD','eihJF','padding','jgHUo','mAqim','taLlE','CNFfE','tgdxd','BDxvP','GLJYH','Xtqot','2|3|6|4|0|5|1','ZPGwE','UnrTC','ELYbg','encryptBlock','xUgss','WbRUo','_process','gKYMm','ipbtP','UEDBD','GoIHF','yJcLb','zMech','WhPoL','vRPpv','encrypt','Emhji','ltqNE','4|2|0|1|3','TVcqh','Jpcca','VScLT','vCeFD','Pddso','BcPqz','rGgel','vlVNj','UVLrW','CIXiD','UOCRz','GCKgg','create','wnQPo','jRTTJ','ZsZnB','lyhZO','lOHmV','JdQIj','ynhHn','auJob','jKOuT','YpFaK','OUDyI','BXaaT','xziyu','_createHelper','uoBlH','MBzSt','CipherParams','KOTBp','rpEHM','Ogdzi','NORod','SLJXb','KuWxk','lJmGP','SVFgg','KKhNE','KgMtU','Jzqhq','gUQlW','wbUXI','Efuny','oUZnb','UcIkg','kfRbJ'];(function(_0x501e76,_0x21adeb){var _0x452812=function(_0x4ead32){while(--_0x4ead32){_0x501e76['push'](_0x501e76['shift']());}};_0x452812(++_0x21adeb);}(_0x21ad,0x1dd));var _0x4528=function(_0x501e76,_0x21adeb){_0x501e76=_0x501e76-0x0;var _0x452812=_0x21ad[_0x501e76];return _0x452812;};var _0xe45236=_0x4528,CryptoJS=CryptoJS||function(_0x15183b,_0x181b33){var _0x23ce14=_0x4528,_0x363f20={'QrILm':function(_0x5d6b9c,_0x293953){return _0x5d6b9c==_0x293953;},'eCRch':function(_0x294b8e,_0x912e7e){return _0x294b8e===_0x912e7e;},'SdcGw':'asyzB','OCqVV':function(_0x4c12e4,_0x1ed58d){return _0x4c12e4!==_0x1ed58d;},'XRVnV':_0x23ce14('0x72'),'TphUm':_0x23ce14('0x300'),'jMKDt':function(_0x108fc2,_0x2b3bfe){return _0x108fc2===_0x2b3bfe;},'UFwLj':'tdXUG','oSXgG':'rEykw','kDUCu':_0x23ce14('0x1ef'),'lBbBW':function(_0x3e17c3,_0x17a05c){return _0x3e17c3/_0x17a05c;},'IKdmF':function(_0x5998c3,_0x2b2f08){return _0x5998c3*_0x2b2f08;},'gkwli':function(_0x22ba05,_0x195135){return _0x22ba05+_0x195135;},'PuqRw':function(_0x1813d4,_0x355605){return _0x1813d4<_0x355605;},'bHnNn':function(_0x4822c2,_0x20ae84){return _0x4822c2<_0x20ae84;},'KDygz':function(_0x5e07a4,_0x274f31){return _0x5e07a4-_0x274f31;},'MxlQG':function(_0x18fa83,_0x2bf641){return _0x18fa83%_0x2bf641;},'AIvMX':function(_0x2e8a4f,_0x1490ff){return _0x2e8a4f==_0x1490ff;},'uPjnB':function(_0x42adff,_0x11ad6a){return _0x42adff|_0x11ad6a;},'NuFyn':function(_0x1df0a8,_0x434960){return _0x1df0a8|_0x434960;},'eRpDf':function(_0x46d11e,_0xee6a10){return _0x46d11e<<_0xee6a10;},'QPNOW':function(_0x587240,_0x4162e1){return _0x587240>>>_0x4162e1;},'vgkjb':function(_0x4413a7,_0x4250e6){return _0x4413a7&_0x4250e6;},'aSIaS':function(_0x116e18,_0x1a2fda){return _0x116e18>>>_0x1a2fda;},'vhdgL':function(_0x5e9979,_0x1d096b){return _0x5e9979&_0x1d096b;},'YospU':function(_0x28b955,_0x5b2879){return _0x28b955/_0x5b2879;},'FHHqP':function(_0x20f755,_0x1faacb){return _0x20f755^_0x1faacb;},'ARXoq':function(_0x50d975,_0xabd66f){return _0x50d975>_0xabd66f;},'AdNoG':function(_0x2ac320,_0x51a09b){return _0x2ac320>=_0x51a09b;},'Eguuu':function(_0x3acd7a,_0x296990){return _0x3acd7a^_0x296990;},'hOkKq':function(_0x5d41e7,_0x4b425b){return _0x5d41e7&_0x4b425b;},'pbfER':function(_0x406775,_0xa788e6){return _0x406775!==_0xa788e6;},'qnSvi':_0x23ce14('0x303'),'sEcpK':function(_0x113363,_0x4a04a8){return _0x113363!==_0x4a04a8;},'TVcqh':'hGFQm','nmOPj':function(_0x301855,_0x25da5d){return _0x301855!=_0x25da5d;},'GgwrU':_0x23ce14('0x17'),'cTlaL':'Imupa','redLB':function(_0x144a57,_0x112807){return _0x144a57||_0x112807;},'iBWoy':function(_0xdf2f9d,_0x432eef){return _0xdf2f9d&_0x432eef;},'xWZYR':function(_0x4fea84,_0xee55ad){return _0x4fea84===_0xee55ad;},'ppDXt':_0x23ce14('0x18c'),'XLSTf':'YgLoo','lyhZO':_0x23ce14('0x208'),'LSocL':function(_0x527c29,_0x43c5ed){return _0x527c29<_0x43c5ed;},'lvfTH':function(_0x1ae74c,_0x67bfb2){return _0x1ae74c+_0x67bfb2;},'OFDAV':function(_0x3929aa,_0x4f3405){return _0x3929aa&_0x4f3405;},'auJob':function(_0x59f084,_0xbd758){return _0x59f084>>>_0xbd758;},'fxzxo':function(_0x5c68b5,_0x5cfc50){return _0x5c68b5>>>_0x5cfc50;},'HFDfQ':function(_0x214b2d,_0x49c5d1){return _0x214b2d%_0x49c5d1;},'COlLn':function(_0x9d9775,_0xf99121){return _0x9d9775*_0xf99121;},'dgOyi':function(_0x273e14,_0x13008f){return _0x273e14%_0x13008f;},'QtgSg':function(_0x5d0c65,_0x4421da){return _0x5d0c65<_0x4421da;},'dodiu':_0x23ce14('0x40a'),'lNuJF':_0x23ce14('0x3dd'),'Bfagu':function(_0x4a9359,_0x36c76f){return _0x4a9359>>>_0x36c76f;},'InPSS':function(_0x3aaac9,_0x45c273){return _0x3aaac9<<_0x45c273;},'aoRkB':function(_0x3706d5,_0x482fe0){return _0x3706d5%_0x482fe0;},'tkBSi':function(_0x52e0fb,_0x5d280f){return _0x52e0fb/_0x5d280f;},'MxFkH':function(_0x1d39b4,_0x241615){return _0x1d39b4!==_0x241615;},'TANQo':_0x23ce14('0x83'),'NwwjC':_0x23ce14('0x1dc'),'hUbgg':'4|0|6|7|5|9|3|10|1|2|8','GhfzM':function(_0x220fd9,_0x393956){return _0x220fd9%_0x393956;},'NaXTW':function(_0x4faeb6,_0x30da14){return _0x4faeb6>_0x30da14;},'AUxPA':function(_0x37b42d,_0x57ca01){return _0x37b42d&_0x57ca01;},'bgJUS':function(_0xce132d,_0x1c1278){return _0xce132d>>>_0x1c1278;},'HCjdg':function(_0x4ca0c8,_0x23ec93){return _0x4ca0c8*_0x23ec93;},'yBYbc':function(_0x252ece,_0x44a159){return _0x252ece*_0x44a159;},'PNgOe':function(_0x6c0512,_0x531af3){return _0x6c0512|_0x531af3;},'HVins':function(_0x4f7292,_0x751747){return _0x4f7292>>>_0x751747;},'yhmrh':function(_0x23045c,_0xca6f08){return _0x23045c/_0xca6f08;},'kvnoK':function(_0x13a106,_0x3caecc){return _0x13a106+_0x3caecc;},'OfLdh':function(_0x559c8e,_0x2fb855){return _0x559c8e|_0x2fb855;},'qSQmH':function(_0x5b5ca3,_0x5ccd9d){return _0x5b5ca3|_0x5ccd9d;},'wnFrg':function(_0x4e49ba,_0x2bb214){return _0x4e49ba*_0x2bb214;},'KDwVp':_0x23ce14('0x397'),'kVmez':function(_0x179982,_0x25d449){return _0x179982<_0x25d449;},'fMrDQ':function(_0x569fe4,_0xed87cc){return _0x569fe4|_0xed87cc;},'pjiRz':function(_0x4c3f4b,_0xd3f632){return _0x4c3f4b<_0xd3f632;},'YgDqM':function(_0x22103f,_0x1a0684){return _0x22103f<<_0x1a0684;},'pMTdt':function(_0x49713f,_0x581e39){return _0x49713f&_0x581e39;},'mARsT':function(_0x210151,_0x460820){return _0x210151*_0x460820;},'HNsdw':function(_0x42f987,_0x748091){return _0x42f987%_0x748091;},'QLVOH':_0x23ce14('0x3bc'),'QOmFx':'hmUzC','JbCLB':function(_0x52e883,_0x80f2b0){return _0x52e883<_0x80f2b0;},'ZVUcP':function(_0x4e59cf,_0xa45768){return _0x4e59cf===_0xa45768;},'SLJXb':'MFpwT','cqJxo':'QSZsD','TPzLj':function(_0x4d1e90,_0xe772e3){return _0x4d1e90&_0xe772e3;},'dNMNx':function(_0x138987,_0x57ead6){return _0x138987>>>_0x57ead6;},'mtiRk':function(_0x2a25f4,_0x3e65cb){return _0x2a25f4>>>_0x3e65cb;},'uKRMb':function(_0x3b3dbe,_0x1026d7){return _0x3b3dbe-_0x1026d7;},'PAXjo':function(_0x5e3f70,_0x5b9c92){return _0x5e3f70*_0x5b9c92;},'ykUqf':function(_0x5c0105,_0x2770e4){return _0x5c0105!=_0x2770e4;},'AMHFS':function(_0x4e458f,_0x3acccb){return _0x4e458f%_0x3acccb;},'jMgjP':function(_0x310e3d,_0x4aabbb){return _0x310e3d<<_0x4aabbb;},'dYEnC':function(_0x42ac2e,_0xf7a6e8){return _0x42ac2e>>>_0xf7a6e8;},'kHTXt':function(_0x1c10e5,_0x55dcbd){return _0x1c10e5*_0x55dcbd;},'EyWxQ':'XCEqM','ivxdK':function(_0x4b98a3,_0x44c05f){return _0x4b98a3<_0x44c05f;},'MgOdW':function(_0x5d3842,_0x203c54){return _0x5d3842>>>_0x203c54;},'sNcdS':function(_0x25465d,_0x2f97a9){return _0x25465d<<_0x2f97a9;},'bPafD':function(_0x406645,_0x583b33,_0x8521e8){return _0x406645(_0x583b33,_0x8521e8);},'TKfPI':function(_0x5cfcbf,_0x250448){return _0x5cfcbf%_0x250448;},'KuWxk':function(_0x25e1a2,_0x2173c8){return _0x25e1a2/_0x2173c8;},'fGJjY':_0x23ce14('0x3c4'),'iYzsx':_0x23ce14('0x278'),'aFsdc':function(_0x251efb,_0x43f711){return _0x251efb<_0x43f711;},'ikwIv':function(_0x39c36c,_0x24df88){return _0x39c36c>>>_0x24df88;},'wMigm':function(_0xca1d85,_0x19ea55){return _0xca1d85%_0x19ea55;},'cXftI':function(_0x123977,_0x4ecd28){return _0x123977===_0x4ecd28;},'fLHxr':'aZkwO','gKYMm':function(_0x1a9588,_0x17f513){return _0x1a9588<_0x17f513;},'faiUw':function(_0x59efa2,_0x5e50eb){return _0x59efa2<<_0x5e50eb;},'dNFuh':function(_0x32ba88,_0xf90907){return _0x32ba88&_0xf90907;},'IbfjS':function(_0x2b214e,_0x64a904){return _0x2b214e-_0x64a904;},'ahxhk':function(_0x581eea,_0xcb32e1){return _0x581eea*_0xcb32e1;},'OalXW':function(_0x56fd7e,_0x354fcb){return _0x56fd7e%_0x354fcb;},'QHrSk':'string','KgMtU':function(_0x55137e,_0x57be1c){return _0x55137e(_0x57be1c);},'KmpmZ':function(_0x2d6341,_0x36c86d){return _0x2d6341(_0x36c86d);},'JNAXy':'Malformed\x20UTF-8\x20data','WbRUo':_0x23ce14('0xdb'),'Fefyz':function(_0x251a0e,_0x2f070e){return _0x251a0e*_0x2f070e;},'Gsbnv':function(_0x39e766,_0x38e4df){return _0x39e766|_0x38e4df;},'DJCYe':_0x23ce14('0x441'),'yTXVY':function(_0x1e37d5,_0x3d3190){return _0x1e37d5!==_0x3d3190;},'vlVNj':_0x23ce14('0x2fb'),'tGXbf':function(_0x521a62,_0x35cb48){return _0x521a62(_0x35cb48);},'jKOuT':_0x23ce14('0x140'),'BMlYB':'VtEYW','rroTp':function(_0x21f36a,_0x4e358d){return _0x21f36a(_0x4e358d);},'pAsxd':'otTsS','mAqim':function(_0x41439b,_0x59bebe){return _0x41439b(_0x59bebe);},'CEpOE':_0x23ce14('0x288'),'rCGNn':_0x23ce14('0x59'),'pgqeB':'XwVSo','MhyzJ':function(_0x476f14,_0x8f7bbf){return _0x476f14<_0x8f7bbf;},'KMCPE':_0x23ce14('0x399'),'LYugQ':function(_0x2cc51b,_0x1cc3e7){return _0x2cc51b%_0x1cc3e7;},'kmXWy':function(_0x1acef2,_0x96a5eb){return _0x1acef2<_0x96a5eb;},'whyvz':function(_0x20870b,_0x4198ed){return _0x20870b>>>_0x4198ed;},'sxPex':function(_0x2e3335,_0x5d7f28){return _0x2e3335+_0x5d7f28;},'dDBXl':function(_0xe0bb9a,_0x2d158f){return _0xe0bb9a*_0x2d158f;},'ubtwu':function(_0x2adc89,_0x1e55f5){return _0x2adc89%_0x1e55f5;},'UUBAK':function(_0x4f3573,_0x3f02ca){return _0x4f3573-_0x3f02ca;},'TdTuC':function(_0x4bec1c,_0x844318){return _0x4bec1c*_0x844318;},'KVgih':function(_0xa315e7,_0x368026){return _0xa315e7+_0x368026;},'pQIUi':_0x23ce14('0x2a4'),'xobyg':function(_0x417f01,_0x495b13){return _0x417f01/_0x495b13;},'WAjuV':function(_0x481161,_0x22b16f){return _0x481161*_0x22b16f;},'ZLMio':function(_0xd8540f,_0x4035d5){return _0xd8540f|_0x4035d5;},'dZwFF':_0x23ce14('0x216'),'TQKdo':function(_0x1659ca,_0x1cfdb2){return _0x1659ca<_0x1cfdb2;},'frUJZ':function(_0x567ccb,_0x106229){return _0x567ccb!=_0x106229;},'YpFaK':function(_0x5c2e12,_0x5c3391){return _0x5c2e12===_0x5c3391;},'elpoB':'xSprS','hUCKh':_0x23ce14('0x115'),'uohsN':function(_0xf15d0e,_0x562a40){return _0xf15d0e!=_0x562a40;},'uUHJP':function(_0x2f271a,_0x241988){return _0x2f271a<_0x241988;},'yFhjF':function(_0x420999,_0x1281b0){return _0x420999%_0x1281b0;},'UQLyA':function(_0x460ac3,_0x58bf94){return _0x460ac3<<_0x58bf94;},'wRUeV':function(_0x2c08ed,_0x845d33){return _0x2c08ed-_0x845d33;},'CgzZV':function(_0x34ee62,_0x27ba83){return _0x34ee62*_0x27ba83;},'JAHZD':_0x23ce14('0x3b7'),'FgCBc':_0x23ce14('0x403'),'owZbZ':function(_0x414a92,_0x2f0a37){return _0x414a92&_0x2f0a37;},'IvZOg':function(_0x215707,_0x21f176){return _0x215707>>>_0x21f176;},'GQdai':function(_0x79e16f,_0x3276cc){return _0x79e16f-_0x3276cc;},'TPWKk':function(_0x168b2a,_0x47c683){return _0x168b2a*_0x47c683;},'DkIfF':function(_0x5db01e,_0x5be306){return _0x5db01e+_0x5be306;},'XrNPx':function(_0x5bde0f,_0x2ddade){return _0x5bde0f+_0x2ddade;},'MYMAD':function(_0x453f2e,_0x181958){return _0x453f2e+_0x181958;},'rhIWG':_0x23ce14('0x425'),'hFWXe':'EKuSR','smeoN':'drEmc','KglyU':_0x23ce14('0x42b'),'gTDst':_0x23ce14('0x365'),'oSlyH':function(_0x1f6dca,_0x279601){return _0x1f6dca!==_0x279601;},'PTpFo':_0x23ce14('0x28'),'zcyjc':_0x23ce14('0x138'),'rqdnX':function(_0x40450b,_0x4f32e1){return _0x40450b<_0x4f32e1;},'BItgy':function(_0x2ba461,_0x39abb7){return _0x2ba461===_0x39abb7;},'pgBnY':_0x23ce14('0x197'),'RLDan':_0x23ce14('0x13c'),'bYTFL':_0x23ce14('0x82'),'WjqmA':_0x23ce14('0x2fe'),'DmLDj':_0x23ce14('0x5b'),'iZxzv':'JaqsB','MkoOC':function(_0x397f8b,_0x558beb){return _0x397f8b===_0x558beb;},'zNCFP':_0x23ce14('0xf9')},_0x3f0b1e={},_0x2d74cd=_0x3f0b1e['lib']={},_0x1984ee=function(){},_0x263d86=_0x2d74cd[_0x23ce14('0xff')]={'extend':function(_0x534f85){var _0x292ee7=_0x23ce14;if(_0x363f20[_0x292ee7('0x254')](_0x363f20['XRVnV'],_0x363f20['XRVnV'])){function _0x289ae5(){var _0x9d2921=_0x292ee7;return this[_0x9d2921('0x300')][_0x9d2921('0x213')][_0x9d2921('0x3ad')](this);}}else{_0x1984ee[_0x292ee7('0x213')]=this;var _0x552ee2=new _0x1984ee();return _0x534f85&&_0x552ee2[_0x292ee7('0x46')](_0x534f85),_0x552ee2[_0x292ee7('0x22f')](_0x363f20[_0x292ee7('0x3ce')])||(_0x552ee2['init']=function(){var _0x218dee=_0x292ee7,_0x4e591b={'YOZuK':function(_0x47d618,_0x2dad48){var _0xbc8edf=_0x4528;return _0x363f20[_0xbc8edf('0x167')](_0x47d618,_0x2dad48);}};if(_0x363f20[_0x218dee('0x366')](_0x363f20['SdcGw'],_0x363f20[_0x218dee('0x401')]))_0x552ee2[_0x218dee('0xce')]['init'][_0x218dee('0x71')](this,arguments);else{function _0x57a61c(){var _0x250fac=_0x218dee,_0x1555fd=this['cfg']['padding'];if(_0x4e591b[_0x250fac('0xc6')](this[_0x250fac('0x16')],this[_0x250fac('0xb1')])){_0x1555fd[_0x250fac('0x2ec')](this[_0x250fac('0xe8')],this[_0x250fac('0x85')]);var _0x27dbae=this[_0x250fac('0x26d')](!0x0);}else _0x27dbae=this['_process'](!0x0),_0x1555fd[_0x250fac('0x379')](_0x27dbae);return _0x27dbae;}}}),_0x552ee2['init'][_0x292ee7('0x213')]=_0x552ee2,_0x552ee2[_0x292ee7('0xce')]=this,_0x552ee2;}},'create':function(){var _0x299638=_0x23ce14;if(_0x363f20[_0x299638('0x20d')](_0x363f20[_0x299638('0x1e3')],_0x363f20[_0x299638('0x1e3')])){var _0x2cc712=this[_0x299638('0x3ad')]();return _0x2cc712[_0x299638('0x300')]['apply'](_0x2cc712,arguments),_0x2cc712;}else{function _0x50b863(){var _0x4fc968=_0x299638,_0x51ab4b=_0x5495ce[_0x4fc968('0x31a')][_0x4fc968('0x1e')](this);return _0x51ab4b['_data']=this[_0x4fc968('0xe8')][_0x4fc968('0x31a')](),_0x51ab4b;}}},'init':function(){},'mixIn':function(_0x72877a){var _0x29ec3a=_0x23ce14;if(_0x363f20['OCqVV'](_0x363f20[_0x29ec3a('0x2e1')],_0x363f20[_0x29ec3a('0x2e1')])){function _0x3f217b(){var _0x9242e6=_0x29ec3a;this[_0x9242e6('0x15c')]=this[_0x9242e6('0x15c')]['extend'](_0x514f8e);}}else{for(var _0x13fc60 in _0x72877a)_0x72877a[_0x29ec3a('0x22f')](_0x13fc60)&&(this[_0x13fc60]=_0x72877a[_0x13fc60]);_0x72877a[_0x29ec3a('0x22f')](_0x363f20[_0x29ec3a('0x87')])&&(this['toString']=_0x72877a[_0x29ec3a('0x1ef')]);}},'clone':function(){var _0xc47124=_0x23ce14,_0x2cb44f={'JdQIj':function(_0x52f4d2,_0x572fd0){var _0x3ec494=_0x4528;return _0x363f20[_0x3ec494('0x23f')](_0x52f4d2,_0x572fd0);},'eHdin':function(_0x4b28cd,_0x420eca){var _0x447d23=_0x4528;return _0x363f20[_0x447d23('0x2c0')](_0x4b28cd,_0x420eca);},'JdAQV':function(_0x17bf1c,_0x103fd2){var _0x2f265b=_0x4528;return _0x363f20[_0x2f265b('0x24f')](_0x17bf1c,_0x103fd2);},'hRzzC':function(_0x2106e4,_0x5b2614){return _0x363f20['PuqRw'](_0x2106e4,_0x5b2614);},'QtIvf':function(_0x2ca77b,_0x1c30cd){var _0xb09dd5=_0x4528;return _0x363f20[_0xb09dd5('0x2de')](_0x2ca77b,_0x1c30cd);},'jXimq':function(_0x3696a1,_0x309b69){var _0x2ce047=_0x4528;return _0x363f20[_0x2ce047('0x1f7')](_0x3696a1,_0x309b69);},'PAFSm':function(_0x4b3008,_0x29af8b){return _0x363f20['MxlQG'](_0x4b3008,_0x29af8b);},'DXxPl':function(_0x2bd5d5,_0x5c0a33){return _0x363f20['bHnNn'](_0x2bd5d5,_0x5c0a33);},'COZSG':function(_0xb0bfe7,_0x44d98d){var _0x3a3a3f=_0x4528;return _0x363f20[_0x3a3a3f('0x108')](_0xb0bfe7,_0x44d98d);},'GPLDi':function(_0x24a42a,_0xdb3f77){var _0x395abb=_0x4528;return _0x363f20[_0x395abb('0x15f')](_0x24a42a,_0xdb3f77);},'dzUxF':function(_0x1ae2ab,_0x588f55){var _0x232a91=_0x4528;return _0x363f20[_0x232a91('0x2cd')](_0x1ae2ab,_0x588f55);},'YrOFU':function(_0x4f1530,_0x307887){var _0x5eca03=_0x4528;return _0x363f20[_0x5eca03('0x2cd')](_0x4f1530,_0x307887);},'cczNT':function(_0x31f47e,_0x549ac7){var _0x1d5fbe=_0x4528;return _0x363f20[_0x1d5fbe('0x24c')](_0x31f47e,_0x549ac7);},'LoHBa':function(_0x144bb8,_0x5809cc){var _0x4ac505=_0x4528;return _0x363f20[_0x4ac505('0x5c')](_0x144bb8,_0x5809cc);},'Efuny':function(_0x215bc6,_0x4fc4e3){var _0x72ba69=_0x4528;return _0x363f20[_0x72ba69('0x405')](_0x215bc6,_0x4fc4e3);},'ELYbg':function(_0x4b0600,_0xa0116b){var _0x323133=_0x4528;return _0x363f20[_0x323133('0x5c')](_0x4b0600,_0xa0116b);},'iTlLo':function(_0x554da2,_0x42624f){var _0x564bc7=_0x4528;return _0x363f20[_0x564bc7('0x24c')](_0x554da2,_0x42624f);},'JrPee':function(_0x1f9ca7,_0x565917){var _0xe2f17e=_0x4528;return _0x363f20[_0xe2f17e('0x405')](_0x1f9ca7,_0x565917);},'cHMLO':function(_0x5a03ca,_0x251cc6){var _0x3698f3=_0x4528;return _0x363f20[_0x3698f3('0x5c')](_0x5a03ca,_0x251cc6);},'cCbFS':function(_0x8aad54,_0x567133){var _0x284dd2=_0x4528;return _0x363f20[_0x284dd2('0x2cd')](_0x8aad54,_0x567133);},'HqMVa':function(_0x539301,_0x3bbf5b){var _0x352ed4=_0x4528;return _0x363f20[_0x352ed4('0x2cd')](_0x539301,_0x3bbf5b);},'UcIkg':function(_0x5cb832,_0x4367dc){return _0x363f20['QPNOW'](_0x5cb832,_0x4367dc);},'mjpfi':function(_0x316f37,_0x95132a){var _0x133451=_0x4528;return _0x363f20[_0x133451('0x24c')](_0x316f37,_0x95132a);},'yTDEV':function(_0x15cbe0,_0xdd0798){var _0x359bd7=_0x4528;return _0x363f20[_0x359bd7('0x405')](_0x15cbe0,_0xdd0798);},'SyxfT':function(_0x5d0b55,_0x1d622c){return _0x363f20['aSIaS'](_0x5d0b55,_0x1d622c);},'rHBQW':function(_0xea22be,_0x297305){return _0x363f20['vhdgL'](_0xea22be,_0x297305);},'Paedb':function(_0x1a8585,_0x4aaaab){var _0x509cec=_0x4528;return _0x363f20[_0x509cec('0x24c')](_0x1a8585,_0x4aaaab);},'odAOf':function(_0x2d7a13,_0x1ac4b6){var _0xe0a72a=_0x4528;return _0x363f20[_0xe0a72a('0x2af')](_0x2d7a13,_0x1ac4b6);},'kqHsX':function(_0x35876d,_0x5ca210){return _0x363f20['FHHqP'](_0x35876d,_0x5ca210);},'pxFMV':function(_0x194631,_0x56829e){var _0x538ad2=_0x4528;return _0x363f20[_0x538ad2('0x227')](_0x194631,_0x56829e);},'UDfkG':function(_0x35fb18,_0x42f85d){var _0x4f2875=_0x4528;return _0x363f20[_0x4f2875('0x104')](_0x35fb18,_0x42f85d);},'pbqDe':function(_0x408e9f,_0x4973aa){var _0x135b49=_0x4528;return _0x363f20[_0x135b49('0x2ae')](_0x408e9f,_0x4973aa);},'iFHGu':function(_0x3bde83,_0xee027c){var _0x54275c=_0x4528;return _0x363f20[_0x54275c('0x206')](_0x3bde83,_0xee027c);},'RtrEI':function(_0x5710c0,_0xcbc9df){var _0x57adb5=_0x4528;return _0x363f20[_0x57adb5('0x389')](_0x5710c0,_0xcbc9df);}};if(_0x363f20['pbfER'](_0x363f20[_0xc47124('0xab')],_0x363f20[_0xc47124('0xab')])){function _0x547baa(){var _0x49882c=_0xc47124;for(var _0x549b41=this['_key'],_0x2a3710=_0x549b41[_0x49882c('0x431')],_0x5bcb93=_0x2cb44f[_0x49882c('0x28c')](_0x549b41[_0x49882c('0xbe')],0x4),_0x549b41=_0x2cb44f[_0x49882c('0x1c9')](0x4,_0x2cb44f['JdAQV'](this['_nRounds']=_0x2cb44f[_0x49882c('0x3f4')](_0x5bcb93,0x6),0x1)),_0x344151=this[_0x49882c('0x2bc')]=[],_0x23f243=0x0;_0x2cb44f[_0x49882c('0x251')](_0x23f243,_0x549b41);_0x23f243++)if(_0x2cb44f[_0x49882c('0xf8')](_0x23f243,_0x5bcb93))_0x344151[_0x23f243]=_0x2a3710[_0x23f243];else{var _0x4837f7=_0x344151[_0x2cb44f[_0x49882c('0xa1')](_0x23f243,0x1)];_0x2cb44f['PAFSm'](_0x23f243,_0x5bcb93)?_0x2cb44f['DXxPl'](0x6,_0x5bcb93)&&_0x2cb44f['COZSG'](0x4,_0x2cb44f[_0x49882c('0x128')](_0x23f243,_0x5bcb93))&&(_0x4837f7=_0x2cb44f['GPLDi'](_0x2cb44f[_0x49882c('0x14e')](_0x2cb44f['YrOFU'](_0x2cb44f[_0x49882c('0x176')](_0x4a5578[_0x2cb44f[_0x49882c('0x173')](_0x4837f7,0x18)],0x18),_0x2cb44f[_0x49882c('0x176')](_0x36a76e[_0x2cb44f[_0x49882c('0x2a5')](_0x2cb44f['ELYbg'](_0x4837f7,0x10),0xff)],0x10)),_0x2cb44f[_0x49882c('0x3f')](_0x10de0b[_0x2cb44f['JrPee'](_0x2cb44f[_0x49882c('0x269')](_0x4837f7,0x8),0xff)],0x8)),_0x4e402c[_0x2cb44f['JrPee'](_0x4837f7,0xff)])):(_0x4837f7=_0x2cb44f[_0x49882c('0x3f0')](_0x2cb44f['iTlLo'](_0x4837f7,0x8),_0x2cb44f[_0x49882c('0x1da')](_0x4837f7,0x18)),_0x4837f7=_0x2cb44f[_0x49882c('0x2f')](_0x2cb44f[_0x49882c('0x41d')](_0x2cb44f[_0x49882c('0x41d')](_0x2cb44f['iTlLo'](_0x394947[_0x2cb44f['UcIkg'](_0x4837f7,0x18)],0x18),_0x2cb44f[_0x49882c('0x3f')](_0x526b6e[_0x2cb44f[_0x49882c('0x2df')](_0x2cb44f[_0x49882c('0x2a7')](_0x4837f7,0x10),0xff)],0x10)),_0x2cb44f[_0x49882c('0x2f4')](_0x5348c9[_0x2cb44f['yTDEV'](_0x2cb44f['SyxfT'](_0x4837f7,0x8),0xff)],0x8)),_0x97f532[_0x2cb44f[_0x49882c('0x3d9')](_0x4837f7,0xff)]),_0x4837f7^=_0x2cb44f[_0x49882c('0x362')](_0x5b67eb[_0x2cb44f[_0x49882c('0x41d')](_0x2cb44f[_0x49882c('0x12c')](_0x23f243,_0x5bcb93),0x0)],0x18)),_0x344151[_0x23f243]=_0x2cb44f[_0x49882c('0x25')](_0x344151[_0x2cb44f['jXimq'](_0x23f243,_0x5bcb93)],_0x4837f7);}_0x2a3710=this['_invKeySchedule']=[];for(_0x5bcb93=0x0;_0x2cb44f['DXxPl'](_0x5bcb93,_0x549b41);_0x5bcb93++)_0x23f243=_0x2cb44f[_0x49882c('0xa1')](_0x549b41,_0x5bcb93),_0x4837f7=_0x2cb44f[_0x49882c('0x69')](_0x5bcb93,0x4)?_0x344151[_0x23f243]:_0x344151[_0x2cb44f[_0x49882c('0xa1')](_0x23f243,0x4)],_0x2a3710[_0x5bcb93]=_0x2cb44f['UDfkG'](0x4,_0x5bcb93)||_0x2cb44f[_0x49882c('0x3ea')](0x4,_0x23f243)?_0x4837f7:_0x2cb44f[_0x49882c('0x25')](_0x2cb44f[_0x49882c('0x20b')](_0x2cb44f[_0x49882c('0x20b')](_0x42b8bb[_0x3b2165[_0x2cb44f['SyxfT'](_0x4837f7,0x18)]],_0x2c9fc0[_0x2042d7[_0x2cb44f['rHBQW'](_0x2cb44f['SyxfT'](_0x4837f7,0x10),0xff)]]),_0x5563c0[_0x28f9f7[_0x2cb44f[_0x49882c('0x23')](_0x2cb44f[_0x49882c('0x223')](_0x4837f7,0x8),0xff)]]),_0x5979f3[_0x49b1c4[_0x2cb44f[_0x49882c('0x23')](_0x4837f7,0xff)]]);}}else return this[_0xc47124('0x300')][_0xc47124('0x213')][_0xc47124('0x3ad')](this);}},_0x4014ca=_0x2d74cd[_0x23ce14('0x476')]=_0x263d86[_0x23ce14('0x3ad')]({'init':function(_0x1d42b2,_0x365708){var _0x3d38a5=_0x23ce14,_0x277ae2={'XwNGE':function(_0x10eaa2,_0xdd706b){var _0x54069d=_0x4528;return _0x363f20[_0x54069d('0x24f')](_0x10eaa2,_0xdd706b);}};if(_0x363f20[_0x3d38a5('0x418')](_0x363f20['TVcqh'],_0x363f20[_0x3d38a5('0x27a')])){function _0x520467(){var _0xc72c42=_0x3d38a5,_0x4e46cf=this[_0xc72c42('0x373')],_0x366b48=_0x4e46cf[_0xc72c42('0x85')],_0x2df128=_0x3a609c['slice'](_0x4f8594,_0x277ae2['XwNGE'](_0x377f8e,_0x366b48));_0x4e46cf[_0xc72c42('0x47')](_0x1a1f78,_0x5560f1),_0x31d443['call'](this,_0x13b566,_0x3f70e0,_0x366b48),this['_prevBlock']=_0x2df128;}}else _0x1d42b2=this['words']=_0x1d42b2||[],this[_0x3d38a5('0xbe')]=_0x363f20[_0x3d38a5('0x123')](_0x365708,_0x181b33)?_0x365708:_0x363f20['IKdmF'](0x4,_0x1d42b2[_0x3d38a5('0x47d')]);},'toString':function(_0x329b08){var _0x9abda1=_0x23ce14;if(_0x363f20[_0x9abda1('0x20d')](_0x363f20[_0x9abda1('0x314')],_0x363f20['cTlaL'])){function _0x9a77a6(){var _0x722148=_0x9abda1,_0xa36197=_0x1857a7[_0x722148('0x31a')][_0x722148('0x1e')](this);return _0xa36197[_0x722148('0x431')]=this['words'][_0x722148('0x408')](0x0),_0xa36197;}}else return _0x363f20[_0x9abda1('0x6a')](_0x329b08,_0x2a65fc)[_0x9abda1('0x40e')](this);},'concat':function(_0x347abe){var _0x4f0f85=_0x23ce14;if(_0x363f20[_0x4f0f85('0xd9')](_0x363f20[_0x4f0f85('0x2e6')],_0x363f20[_0x4f0f85('0xe6')])){function _0x59bbb4(){var _0xd728ae=_0x4f0f85;_0x34ce2a['sigBytes']-=_0x363f20[_0xd728ae('0x21a')](_0x41fcbd[_0xd728ae('0x431')][_0x363f20[_0xd728ae('0x465')](_0x363f20[_0xd728ae('0x1f7')](_0x56f3e8[_0xd728ae('0xbe')],0x1),0x2)],0xff);}}else{var _0x469fd4=_0x363f20[_0x4f0f85('0x28a')]['split']('|'),_0x2ab39f=0x0;while(!![]){switch(_0x469fd4[_0x2ab39f++]){case'0':return this;case'1':this['sigBytes']+=_0x347abe;continue;case'2':this['clamp']();continue;case'3':if(_0x363f20[_0x4f0f85('0x227')](_0x4bcd6e,0x4))for(var _0x4a44dd=0x0;_0x363f20[_0x4f0f85('0x215')](_0x4a44dd,_0x347abe);_0x4a44dd++)_0x3dae4c[_0x363f20[_0x4f0f85('0x465')](_0x363f20[_0x4f0f85('0x440')](_0x4bcd6e,_0x4a44dd),0x2)]|=_0x363f20[_0x4f0f85('0x24c')](_0x363f20['OFDAV'](_0x363f20[_0x4f0f85('0x28e')](_0x450b91[_0x363f20[_0x4f0f85('0x31d')](_0x4a44dd,0x2)],_0x363f20[_0x4f0f85('0x1f7')](0x18,_0x363f20[_0x4f0f85('0x2c0')](0x8,_0x363f20[_0x4f0f85('0xdc')](_0x4a44dd,0x4)))),0xff),_0x363f20[_0x4f0f85('0x1f7')](0x18,_0x363f20[_0x4f0f85('0x239')](0x8,_0x363f20['dgOyi'](_0x363f20[_0x4f0f85('0x440')](_0x4bcd6e,_0x4a44dd),0x4))));else{if(_0x363f20['LSocL'](0xffff,_0x450b91['length']))for(_0x4a44dd=0x0;_0x363f20['QtgSg'](_0x4a44dd,_0x347abe);_0x4a44dd+=0x4)_0x3dae4c[_0x363f20[_0x4f0f85('0x31d')](_0x363f20['lvfTH'](_0x4bcd6e,_0x4a44dd),0x2)]=_0x450b91[_0x363f20[_0x4f0f85('0x31d')](_0x4a44dd,0x2)];else _0x3dae4c[_0x4f0f85('0x36d')][_0x4f0f85('0x71')](_0x3dae4c,_0x450b91);}continue;case'4':var _0x3dae4c=this[_0x4f0f85('0x431')],_0x450b91=_0x347abe[_0x4f0f85('0x431')],_0x4bcd6e=this[_0x4f0f85('0xbe')];continue;case'5':_0x347abe=_0x347abe[_0x4f0f85('0xbe')];continue;}break;}}},'clamp':function(){var _0x1e0ee7=_0x23ce14;if(_0x363f20[_0x1e0ee7('0x418')](_0x363f20[_0x1e0ee7('0x3fa')],_0x363f20[_0x1e0ee7('0x406')])){var _0x741b05=this[_0x1e0ee7('0x431')],_0x4bf9a3=this['sigBytes'];_0x741b05[_0x363f20[_0x1e0ee7('0x38b')](_0x4bf9a3,0x2)]&=_0x363f20['InPSS'](0xffffffff,_0x363f20[_0x1e0ee7('0x1f7')](0x20,_0x363f20[_0x1e0ee7('0x239')](0x8,_0x363f20['aoRkB'](_0x4bf9a3,0x4)))),_0x741b05[_0x1e0ee7('0x47d')]=_0x15183b[_0x1e0ee7('0x107')](_0x363f20['tkBSi'](_0x4bf9a3,0x4));}else{function _0x44f85f(){var _0x2605bc=_0x1e0ee7;this[_0x2605bc('0x15c')]=this[_0x2605bc('0x15c')]['extend'](_0x5d4b3a),this[_0x2605bc('0xbf')]();}}},'clone':function(){var _0x47aa45=_0x23ce14;if(_0x363f20[_0x47aa45('0xb7')](_0x363f20[_0x47aa45('0x1d7')],_0x363f20[_0x47aa45('0x1e1')])){var _0x45c0af=_0x263d86[_0x47aa45('0x31a')][_0x47aa45('0x1e')](this);return _0x45c0af[_0x47aa45('0x431')]=this[_0x47aa45('0x431')]['slice'](0x0),_0x45c0af;}else{function _0x36c6af(){var _0x5ea258=_0x47aa45;return _0x3e089f=this[_0x5ea258('0x15c')]['extend'](_0x446acf),_0x377221=this[_0x5ea258('0x2eb')](_0x1d2f1d,_0x593dfb[_0x5ea258('0x192')]),_0x37d578[_0x5ea258('0x4a')](_0x5792d5,_0x513c99)['finalize'](_0x45fe70['ciphertext']);}}},'random':function(_0x46d955){var _0x194e6d=_0x23ce14,_0x420c96={'xgANF':_0x363f20[_0x194e6d('0xfd')],'BCaoL':function(_0x1d5d0e,_0x4340f2){var _0x235094=_0x194e6d;return _0x363f20[_0x235094('0x38b')](_0x1d5d0e,_0x4340f2);},'eeXLS':function(_0x4731b9,_0x14decf){var _0x3fbaf8=_0x194e6d;return _0x363f20[_0x3fbaf8('0x328')](_0x4731b9,_0x14decf);},'AZrgJ':function(_0x3fd6ed,_0x3c4666){var _0x8cbace=_0x194e6d;return _0x363f20[_0x8cbace('0x1f7')](_0x3fd6ed,_0x3c4666);},'jrarl':function(_0x56e350,_0x3d5fc5){return _0x363f20['GhfzM'](_0x56e350,_0x3d5fc5);},'gvOTN':function(_0x28ab7b,_0x57bc2b){var _0x554416=_0x194e6d;return _0x363f20[_0x554416('0x2c9')](_0x28ab7b,_0x57bc2b);},'FgTJk':function(_0x3f3883,_0x395b2b){var _0x1a61b9=_0x194e6d;return _0x363f20[_0x1a61b9('0x2cd')](_0x3f3883,_0x395b2b);},'KTghE':function(_0x569e20,_0x3e68fe){var _0x523f70=_0x194e6d;return _0x363f20[_0x523f70('0x112')](_0x569e20,_0x3e68fe);},'FTjzu':function(_0x4504b4,_0x489c5b){return _0x363f20['bgJUS'](_0x4504b4,_0x489c5b);},'cdgLl':function(_0x4926fb,_0x3ee1d7){var _0xeae1da=_0x194e6d;return _0x363f20[_0xeae1da('0x35c')](_0x4926fb,_0x3ee1d7);},'FbFVp':function(_0x313ffa,_0x204fd5){return _0x363f20['yBYbc'](_0x313ffa,_0x204fd5);},'xUgss':function(_0x481fb4,_0x51fdd8){return _0x363f20['lvfTH'](_0x481fb4,_0x51fdd8);},'vIcEg':function(_0x20e329,_0x273c42){return _0x363f20['bgJUS'](_0x20e329,_0x273c42);},'YrKDI':function(_0x10f350,_0x1f18e8){var _0x560a3b=_0x194e6d;return _0x363f20[_0x560a3b('0x440')](_0x10f350,_0x1f18e8);},'vxpHB':function(_0x4a41e4,_0x3e6c84){var _0x3a8ea6=_0x194e6d;return _0x363f20[_0x3a8ea6('0x1f9')](_0x4a41e4,_0x3e6c84);},'HEoEk':function(_0x5f1e85,_0xc79cd0){return _0x363f20['PNgOe'](_0x5f1e85,_0xc79cd0);},'xfMfA':function(_0x25da87,_0x2b3ab9){var _0x9dbcc7=_0x194e6d;return _0x363f20[_0x9dbcc7('0x328')](_0x25da87,_0x2b3ab9);},'GLJYH':function(_0x377e7a,_0x31b1ca){var _0x13220e=_0x194e6d;return _0x363f20[_0x13220e('0x77')](_0x377e7a,_0x31b1ca);},'fHhyb':function(_0x20c0ad,_0x79c143){var _0x5af844=_0x194e6d;return _0x363f20[_0x5af844('0x112')](_0x20c0ad,_0x79c143);},'HmAVc':function(_0xf03c3f,_0x375a5a){var _0x5f5b42=_0x194e6d;return _0x363f20[_0x5f5b42('0x1f9')](_0xf03c3f,_0x375a5a);},'pMQoK':function(_0x2a41d2,_0x588e43){var _0x479ad5=_0x194e6d;return _0x363f20[_0x479ad5('0x78')](_0x2a41d2,_0x588e43);},'dqTnU':function(_0x58bf26,_0x5812c7){return _0x363f20['yhmrh'](_0x58bf26,_0x5812c7);},'dShwt':function(_0x2c6f36,_0x7d304d){var _0x52574c=_0x194e6d;return _0x363f20[_0x52574c('0x2ea')](_0x2c6f36,_0x7d304d);},'bWjAS':function(_0x14cf98,_0x3829a1){var _0x43e7dc=_0x194e6d;return _0x363f20[_0x43e7dc('0x133')](_0x14cf98,_0x3829a1);},'hxbLC':function(_0x57b522,_0x18821a){return _0x363f20['AUxPA'](_0x57b522,_0x18821a);},'nrgdO':function(_0x37639d,_0x13529c){return _0x363f20['qSQmH'](_0x37639d,_0x13529c);},'FZfjy':function(_0x414c9f,_0x5e7acf){return _0x363f20['HVins'](_0x414c9f,_0x5e7acf);},'NTcKG':function(_0x408594,_0x41059c){var _0x38c5d5=_0x194e6d;return _0x363f20[_0x38c5d5('0x328')](_0x408594,_0x41059c);},'thHRx':function(_0xa6a779,_0x21a114){var _0xec5cb2=_0x194e6d;return _0x363f20[_0xec5cb2('0x45f')](_0xa6a779,_0x21a114);},'iVCxM':function(_0x3f04b,_0x20a184){var _0x29e9c0=_0x194e6d;return _0x363f20[_0x29e9c0('0x2ea')](_0x3f04b,_0x20a184);}};if(_0x363f20[_0x194e6d('0xb7')](_0x363f20[_0x194e6d('0x43f')],_0x363f20[_0x194e6d('0x43f')])){function _0x3e1ed9(){var _0x9afefc=_0x194e6d,_0x164a2=_0x420c96[_0x9afefc('0x93')][_0x9afefc('0x2f8')]('|'),_0x5ee10b=0x0;while(!![]){switch(_0x164a2[_0x5ee10b++]){case'0':_0x3b35ad[_0x420c96[_0x9afefc('0x95')](_0x274d84,0x5)]|=_0x420c96['eeXLS'](0x80,_0x420c96[_0x9afefc('0x372')](0x18,_0x420c96[_0x9afefc('0x16c')](_0x274d84,0x20)));continue;case'1':_0x3b35ad=_0x197356['words'];continue;case'2':for(_0xfe37e=0x0;_0x420c96[_0x9afefc('0x149')](0x4,_0xfe37e);_0xfe37e++)_0x274d84=_0x3b35ad[_0xfe37e],_0x3b35ad[_0xfe37e]=_0x420c96['FgTJk'](_0x420c96['KTghE'](_0x420c96['FgTJk'](_0x420c96['eeXLS'](_0x274d84,0x8),_0x420c96['BCaoL'](_0x274d84,0x18)),0xff00ff),_0x420c96[_0x9afefc('0x10e')](_0x420c96[_0x9afefc('0x4')](_0x420c96[_0x9afefc('0x75')](_0x274d84,0x18),_0x420c96['FTjzu'](_0x274d84,0x8)),0xff00ff00));continue;case'3':this[_0x9afefc('0x26d')]();continue;case'4':var _0x197356=this[_0x9afefc('0xe8')],_0x3b35ad=_0x197356[_0x9afefc('0x431')],_0xfe37e=_0x420c96[_0x9afefc('0x2ba')](0x8,this['_nDataBytes']),_0x274d84=_0x420c96[_0x9afefc('0x412')](0x8,_0x197356[_0x9afefc('0xbe')]);continue;case'5':_0x3b35ad[_0x420c96[_0x9afefc('0x26b')](_0x420c96[_0x9afefc('0x75')](_0x420c96[_0x9afefc('0x25a')](_0x420c96['YrKDI'](_0x274d84,0x40),0x9),0x4),0xe)]=_0x420c96[_0x9afefc('0x1ac')](_0x420c96[_0x9afefc('0x10e')](_0x420c96[_0x9afefc('0x40')](_0x420c96[_0x9afefc('0x459')](_0xfe37e,0x8),_0x420c96[_0x9afefc('0x264')](_0xfe37e,0x18)),0xff00ff),_0x420c96[_0x9afefc('0x417')](_0x420c96['HmAVc'](_0x420c96[_0x9afefc('0x459')](_0xfe37e,0x18),_0x420c96[_0x9afefc('0x46c')](_0xfe37e,0x8)),0xff00ff00));continue;case'6':var _0x4e140b=_0x4ccf39[_0x9afefc('0x3f6')](_0x420c96[_0x9afefc('0x166')](_0xfe37e,0x100000000));continue;case'7':_0x3b35ad[_0x420c96[_0x9afefc('0x47b')](_0x420c96[_0x9afefc('0x459')](_0x420c96[_0x9afefc('0x46c')](_0x420c96['dShwt'](_0x274d84,0x40),0x9),0x4),0xf)]=_0x420c96[_0x9afefc('0x9b')](_0x420c96[_0x9afefc('0x17b')](_0x420c96[_0x9afefc('0x152')](_0x420c96[_0x9afefc('0x459')](_0x4e140b,0x8),_0x420c96['FZfjy'](_0x4e140b,0x18)),0xff00ff),_0x420c96[_0x9afefc('0x17b')](_0x420c96[_0x9afefc('0x152')](_0x420c96['NTcKG'](_0x4e140b,0x18),_0x420c96[_0x9afefc('0x17e')](_0x4e140b,0x8)),0xff00ff00));continue;case'8':return _0x197356;case'9':_0x197356[_0x9afefc('0xbe')]=_0x420c96[_0x9afefc('0x2fa')](0x4,_0x420c96[_0x9afefc('0x1b2')](_0x3b35ad[_0x9afefc('0x47d')],0x1));continue;case'10':_0x197356=this[_0x9afefc('0x363')];continue;}break;}}}else{for(var _0xce875a=[],_0x636f2c=0x0;_0x363f20[_0x194e6d('0x231')](_0x636f2c,_0x46d955);_0x636f2c+=0x4)_0xce875a[_0x194e6d('0x36d')](_0x363f20[_0x194e6d('0x2bd')](_0x363f20[_0x194e6d('0x45f')](0x100000000,_0x15183b[_0x194e6d('0x7f')]()),0x0));return new _0x4014ca[(_0x194e6d('0x300'))](_0xce875a,_0x46d955);}}}),_0x3dcc7d=_0x3f0b1e[_0x23ce14('0x451')]={},_0x2a65fc=_0x3dcc7d[_0x23ce14('0x44')]={'stringify':function(_0x4c8688){var _0x2e4337=_0x23ce14;if(_0x363f20[_0x2e4337('0xd9')](_0x363f20[_0x2e4337('0x35b')],_0x363f20['QOmFx'])){function _0x47f5d0(){return function(_0x1ccd8d,_0x4deda0){var _0x1df791=_0x4528;return new _0x2a5ed2[(_0x1df791('0x338'))][(_0x1df791('0x300'))](_0x504228,_0x4deda0)[_0x1df791('0x68')](_0x1ccd8d);};}}else{var _0x2a0a56=_0x4c8688[_0x2e4337('0x431')];_0x4c8688=_0x4c8688['sigBytes'];for(var _0x5d9df4=[],_0x300593=0x0;_0x363f20[_0x2e4337('0x1df')](_0x300593,_0x4c8688);_0x300593++){if(_0x363f20[_0x2e4337('0x6')](_0x363f20[_0x2e4337('0x29c')],_0x363f20[_0x2e4337('0x2c6')])){function _0x4ca340(){var _0xdf2bbf=_0x2e4337;for(var _0x547e06=_0x75f7b5[_0xdf2bbf('0x47d')],_0x12d46c=[],_0x5eef17=0x0;_0x363f20['pjiRz'](_0x5eef17,_0x547e06);_0x5eef17++)_0x12d46c[_0x363f20[_0xdf2bbf('0x78')](_0x5eef17,0x2)]|=_0x363f20['YgDqM'](_0x363f20['pMTdt'](_0x1ad022[_0xdf2bbf('0x222')](_0x5eef17),0xff),_0x363f20[_0xdf2bbf('0x1f7')](0x18,_0x363f20[_0xdf2bbf('0xd0')](0x8,_0x363f20[_0xdf2bbf('0x212')](_0x5eef17,0x4))));return new _0x309ece['init'](_0x12d46c,_0x547e06);}}else{var _0xe3c12b=_0x363f20[_0x2e4337('0x44a')](_0x363f20[_0x2e4337('0x188')](_0x2a0a56[_0x363f20[_0x2e4337('0x18')](_0x300593,0x2)],_0x363f20[_0x2e4337('0x14b')](0x18,_0x363f20['PAXjo'](0x8,_0x363f20['HNsdw'](_0x300593,0x4)))),0xff);_0x5d9df4[_0x2e4337('0x36d')](_0x363f20['mtiRk'](_0xe3c12b,0x4)[_0x2e4337('0x1ef')](0x10)),_0x5d9df4[_0x2e4337('0x36d')](_0x363f20[_0x2e4337('0x44a')](_0xe3c12b,0xf)[_0x2e4337('0x1ef')](0x10));}}return _0x5d9df4[_0x2e4337('0xcd')]('');}},'parse':function(_0x568d52){var _0x17b705=_0x23ce14,_0x52b979={'FmeqU':function(_0x4b86da,_0x1620fb){return _0x363f20['ykUqf'](_0x4b86da,_0x1620fb);},'DRUYI':function(_0x1a36d8,_0xd97673){var _0xcb7a83=_0x4528;return _0x363f20[_0xcb7a83('0x1df')](_0x1a36d8,_0xd97673);},'onspC':function(_0x49a776,_0xc1be6){var _0x3ac6b3=_0x4528;return _0x363f20[_0x3ac6b3('0x309')](_0x49a776,_0xc1be6);},'CPcDN':function(_0x17ce7a,_0x5b4209){var _0x4ee869=_0x4528;return _0x363f20[_0x4ee869('0x198')](_0x17ce7a,_0x5b4209);},'zKWBj':function(_0x3a96b6,_0x592499){return _0x363f20['uKRMb'](_0x3a96b6,_0x592499);},'cQdXt':function(_0x283561,_0x58f9c3){var _0x3880a8=_0x4528;return _0x363f20[_0x3880a8('0x47f')](_0x283561,_0x58f9c3);},'CaDMK':function(_0x29cebe,_0x9ec824){return _0x363f20['dYEnC'](_0x29cebe,_0x9ec824);},'OODwP':function(_0x1814f8,_0x416371){var _0x182415=_0x4528;return _0x363f20[_0x182415('0x47f')](_0x1814f8,_0x416371);},'omzgc':function(_0x2730c5,_0x1ea473){var _0x1f35e9=_0x4528;return _0x363f20[_0x1f35e9('0x2bd')](_0x2730c5,_0x1ea473);},'HEmRE':function(_0x421dc3,_0x16b988){var _0x31494b=_0x4528;return _0x363f20[_0x31494b('0x110')](_0x421dc3,_0x16b988);}};if(_0x363f20[_0x17b705('0x6')](_0x363f20['EyWxQ'],_0x363f20[_0x17b705('0x204')])){for(var _0x37dd9e=_0x568d52[_0x17b705('0x47d')],_0x346499=[],_0x2f23bd=0x0;_0x363f20[_0x17b705('0x388')](_0x2f23bd,_0x37dd9e);_0x2f23bd+=0x2)_0x346499[_0x363f20[_0x17b705('0x24d')](_0x2f23bd,0x3)]|=_0x363f20[_0x17b705('0x2b7')](_0x363f20[_0x17b705('0x41')](parseInt,_0x568d52[_0x17b705('0xe3')](_0x2f23bd,0x2),0x10),_0x363f20[_0x17b705('0x14b')](0x18,_0x363f20[_0x17b705('0x110')](0x4,_0x363f20[_0x17b705('0x347')](_0x2f23bd,0x8))));return new _0x4014ca[(_0x17b705('0x300'))](_0x346499,_0x363f20[_0x17b705('0x29d')](_0x37dd9e,0x2));}else{function _0x36c8a6(){var _0x4cabc0=_0x17b705,_0x298017=_0xea3f19[_0x4cabc0('0x47d')],_0x1e1dc0=this[_0x4cabc0('0x21d')],_0x3fdc4a=_0x1e1dc0[_0x4cabc0('0x40f')](0x40);_0x3fdc4a&&(_0x3fdc4a=_0x185ecd[_0x4cabc0('0x125')](_0x3fdc4a),_0x52b979[_0x4cabc0('0x3be')](-0x1,_0x3fdc4a)&&(_0x298017=_0x3fdc4a));for(var _0x3fdc4a=[],_0x498c9e=0x0,_0x40e7bd=0x0;_0x52b979[_0x4cabc0('0x3a1')](_0x40e7bd,_0x298017);_0x40e7bd++)if(_0x52b979[_0x4cabc0('0x3d8')](_0x40e7bd,0x4)){var _0x3daca4=_0x52b979[_0x4cabc0('0x315')](_0x1e1dc0['indexOf'](_0x146401[_0x4cabc0('0x40f')](_0x52b979[_0x4cabc0('0x396')](_0x40e7bd,0x1))),_0x52b979['cQdXt'](0x2,_0x52b979[_0x4cabc0('0x3d8')](_0x40e7bd,0x4))),_0xaa45e4=_0x52b979[_0x4cabc0('0xee')](_0x1e1dc0['indexOf'](_0x2fa6b3[_0x4cabc0('0x40f')](_0x40e7bd)),_0x52b979[_0x4cabc0('0x396')](0x6,_0x52b979['OODwP'](0x2,_0x52b979[_0x4cabc0('0x3d8')](_0x40e7bd,0x4))));_0x3fdc4a[_0x52b979[_0x4cabc0('0xee')](_0x498c9e,0x2)]|=_0x52b979['CPcDN'](_0x52b979[_0x4cabc0('0x308')](_0x3daca4,_0xaa45e4),_0x52b979['zKWBj'](0x18,_0x52b979[_0x4cabc0('0x2d0')](0x8,_0x52b979[_0x4cabc0('0x3d8')](_0x498c9e,0x4)))),_0x498c9e++;}return _0x347511['create'](_0x3fdc4a,_0x498c9e);}}}},_0x25a65f=_0x3dcc7d['Latin1']={'stringify':function(_0x53a01a){var _0x19f401=_0x23ce14;if(_0x363f20[_0x19f401('0x6')](_0x363f20[_0x19f401('0xc2')],_0x363f20[_0x19f401('0x353')])){function _0xc1f359(){var _0x3dda0f=_0x19f401;return this[_0x3dda0f('0x26d')](!0x0);}}else{var _0x5304bd=_0x53a01a['words'];_0x53a01a=_0x53a01a[_0x19f401('0xbe')];for(var _0x4a0276=[],_0x149f8f=0x0;_0x363f20['aFsdc'](_0x149f8f,_0x53a01a);_0x149f8f++)_0x4a0276[_0x19f401('0x36d')](String[_0x19f401('0x46d')](_0x363f20[_0x19f401('0x44a')](_0x363f20[_0x19f401('0x24d')](_0x5304bd[_0x363f20[_0x19f401('0x4b')](_0x149f8f,0x2)],_0x363f20[_0x19f401('0x14b')](0x18,_0x363f20['kHTXt'](0x8,_0x363f20[_0x19f401('0x17f')](_0x149f8f,0x4)))),0xff)));return _0x4a0276[_0x19f401('0xcd')]('');}},'parse':function(_0x16cf73){var _0x39e7d9=_0x23ce14;if(_0x363f20[_0x39e7d9('0x201')](_0x363f20[_0x39e7d9('0x22a')],_0x363f20[_0x39e7d9('0x22a')])){for(var _0x15f15a=_0x16cf73[_0x39e7d9('0x47d')],_0x4e1e41=[],_0x3d67c8=0x0;_0x363f20['gKYMm'](_0x3d67c8,_0x15f15a);_0x3d67c8++)_0x4e1e41[_0x363f20[_0x39e7d9('0x4b')](_0x3d67c8,0x2)]|=_0x363f20['faiUw'](_0x363f20['dNFuh'](_0x16cf73[_0x39e7d9('0x222')](_0x3d67c8),0xff),_0x363f20[_0x39e7d9('0x355')](0x18,_0x363f20[_0x39e7d9('0x16e')](0x8,_0x363f20['OalXW'](_0x3d67c8,0x4))));return new _0x4014ca[(_0x39e7d9('0x300'))](_0x4e1e41,_0x15f15a);}else{function _0x3a9ccd(){var _0x134795=_0x39e7d9;this[_0x134795('0x15c')]=this[_0x134795('0x15c')][_0x134795('0x3ad')](_0xe7b7a1),this[_0x134795('0x16')]=_0x3325f0,this[_0x134795('0x1cf')]=_0x18ec41,this[_0x134795('0xbf')]();}}}},_0x5354f4=_0x3dcc7d[_0x23ce14('0x1eb')]={'stringify':function(_0x4208a5){var _0x21765c=_0x23ce14,_0x20a3f7={'cXlou':function(_0x4565c6,_0x1dcf7d){var _0x2f5ec7=_0x4528;return _0x363f20[_0x2f5ec7('0x108')](_0x4565c6,_0x1dcf7d);},'puNtb':_0x363f20[_0x21765c('0x20c')],'MEzBv':function(_0x26357e,_0x3eaae0){var _0x53ac96=_0x21765c;return _0x363f20[_0x53ac96('0x2a1')](_0x26357e,_0x3eaae0);},'bamUP':function(_0x588d18,_0x360843){var _0x44d606=_0x21765c;return _0x363f20[_0x44d606('0x165')](_0x588d18,_0x360843);},'QAHlZ':_0x363f20['JNAXy'],'wOwGU':_0x363f20[_0x21765c('0x26c')],'rGgel':function(_0x4e957b,_0x237d8e){var _0x28861e=_0x21765c;return _0x363f20[_0x28861e('0x29d')](_0x4e957b,_0x237d8e);},'yJcLb':function(_0x17db9e,_0x344bcf){var _0x594d13=_0x21765c;return _0x363f20[_0x594d13('0x360')](_0x17db9e,_0x344bcf);},'cNcaB':function(_0x462418,_0x85e287){var _0x26e6a5=_0x21765c;return _0x363f20[_0x26e6a5('0x355')](_0x462418,_0x85e287);},'xlYlT':function(_0x844876,_0x3c3e2c){return _0x363f20['Gsbnv'](_0x844876,_0x3c3e2c);},'DLACK':function(_0x328975,_0x3cccad){return _0x363f20['gKYMm'](_0x328975,_0x3cccad);}};if(_0x363f20[_0x21765c('0xb7')](_0x363f20[_0x21765c('0xe')],_0x363f20[_0x21765c('0xe')])){function _0x2c59ec(){var _0x360423=_0x21765c;return(_0x20a3f7[_0x360423('0x3a4')](_0x20a3f7[_0x360423('0x34f')],typeof _0x384df9)?_0x5558bb:_0x6689f9)[_0x360423('0x313')](_0x32d4fa,_0x4718d1,_0x3652f7,_0x19b3ff);}}else try{if(_0x363f20[_0x21765c('0x1c8')](_0x363f20['vlVNj'],_0x363f20[_0x21765c('0x281')])){function _0x3c58c9(){var _0x50a0da=_0x21765c;try{return _0x20a3f7[_0x50a0da('0x419')](_0x40db5f,_0x20a3f7[_0x50a0da('0x3aa')](_0x3a0765,_0x5bfd37[_0x50a0da('0x40e')](_0x5a5edc)));}catch(_0x4c482c){throw _0x20a3f7[_0x50a0da('0x3aa')](_0x10a5f9,_0x20a3f7['QAHlZ']);}}}else return _0x363f20[_0x21765c('0x332')](decodeURIComponent,_0x363f20[_0x21765c('0x332')](escape,_0x25a65f[_0x21765c('0x40e')](_0x4208a5)));}catch(_0x4d442f){if(_0x363f20[_0x21765c('0x1c8')](_0x363f20[_0x21765c('0x28f')],_0x363f20['BMlYB']))throw _0x363f20['rroTp'](Error,_0x363f20[_0x21765c('0x111')]);else{function _0x2f61e4(){var _0x4a88d6=_0x21765c,_0x45d1f4=_0x20a3f7[_0x4a88d6('0x2d2')][_0x4a88d6('0x2f8')]('|'),_0x1fd0ab=0x0;while(!![]){switch(_0x45d1f4[_0x1fd0ab++]){case'0':return new _0x387fb7['init'](_0x533fe3,_0x5bfc0c);case'1':var _0x430b73=this['_data'],_0x117c23=_0x430b73[_0x4a88d6('0x431')],_0x5bfc0c=_0x430b73[_0x4a88d6('0xbe')],_0x466630=this[_0x4a88d6('0x85')],_0x37144b=_0x20a3f7[_0x4a88d6('0x280')](_0x5bfc0c,_0x20a3f7[_0x4a88d6('0x272')](0x4,_0x466630)),_0x37144b=_0x1175e9?_0x1094b0[_0x4a88d6('0x107')](_0x37144b):_0x52e1eb[_0x4a88d6('0x179')](_0x20a3f7[_0x4a88d6('0x368')](_0x20a3f7['xlYlT'](_0x37144b,0x0),this[_0x4a88d6('0x134')]),0x0);continue;case'2':if(_0xe0e8e7){for(var _0x533fe3=0x0;_0x20a3f7[_0x4a88d6('0x31e')](_0x533fe3,_0x4064e7);_0x533fe3+=_0x466630)this[_0x4a88d6('0x187')](_0x117c23,_0x533fe3);_0x533fe3=_0x117c23['splice'](0x0,_0x5d9490),_0x430b73[_0x4a88d6('0xbe')]-=_0x5bfc0c;}continue;case'3':_0xa16de7=_0x20a3f7[_0x4a88d6('0x272')](_0x37144b,_0x466630);continue;case'4':_0x5bfc0c=_0x43e7f6[_0x4a88d6('0x325')](_0x20a3f7[_0x4a88d6('0x272')](0x4,_0x435322),_0x5bfc0c);continue;}break;}}}}},'parse':function(_0x1dc939){var _0xb12180=_0x23ce14;if(_0x363f20['yTXVY'](_0x363f20['pAsxd'],_0x363f20[_0xb12180('0x19')])){function _0x13efd6(){var _0xefc6a1=_0xb12180,_0x46a47c=this[_0xefc6a1('0x3ad')]();return _0x46a47c[_0xefc6a1('0x300')]['apply'](_0x46a47c,arguments),_0x46a47c;}}else return _0x25a65f[_0xb12180('0x316')](_0x363f20[_0xb12180('0x214')](unescape,_0x363f20[_0xb12180('0x25f')](encodeURIComponent,_0x1dc939)));}},_0xe99d37=_0x2d74cd[_0x23ce14('0x3ed')]=_0x263d86['extend']({'reset':function(){var _0x5b2688=_0x23ce14;if(_0x363f20[_0x5b2688('0x1c8')](_0x363f20[_0x5b2688('0x32e')],_0x363f20['CEpOE'])){function _0x4fb407(){this['mixIn'](_0x52b1e7);}}else this[_0x5b2688('0xe8')]=new _0x4014ca['init'](),this[_0x5b2688('0x73')]=0x0;},'_append':function(_0x162c02){var _0xcc29ff=_0x23ce14;if(_0x363f20[_0xcc29ff('0x1c8')](_0x363f20['pgqeB'],_0x363f20[_0xcc29ff('0x56')])){function _0x50e9c0(){var _0x1cc445=_0xcc29ff,_0x2e08cd=_0x363f20[_0x1cc445('0x447')]['split']('|'),_0x2c7103=0x0;while(!![]){switch(_0x2e08cd[_0x2c7103++]){case'0':_0x13015f[_0x1cc445('0xbf')]();continue;case'1':var _0x1b6a4d=_0x4273a3[_0x1cc445('0x3f5')](_0x1aae9b)[_0x1cc445('0x68')](_0x137e01);continue;case'2':_0x1b6a4d&&_0x395911[_0x1cc445('0x3f5')](_0x1b6a4d);continue;case'3':_0x377478[_0x1cc445('0x3b2')](_0x1b6a4d);continue;case'4':for(var _0x4e087c=0x1;_0x363f20[_0x1cc445('0x26e')](_0x4e087c,_0x4c2517);_0x4e087c++)_0x1b6a4d=_0x30ac63['finalize'](_0x1b6a4d),_0x450e35[_0x1cc445('0xbf')]();continue;}break;}}}else _0x363f20[_0xcc29ff('0x108')](_0x363f20[_0xcc29ff('0x20c')],typeof _0x162c02)&&(_0x162c02=_0x5354f4[_0xcc29ff('0x316')](_0x162c02)),this[_0xcc29ff('0xe8')][_0xcc29ff('0x3b2')](_0x162c02),this[_0xcc29ff('0x73')]+=_0x162c02[_0xcc29ff('0xbe')];},'_process':function(_0x564b61){var _0x288a34=_0x23ce14;if(_0x363f20['cXftI'](_0x363f20['pQIUi'],_0x363f20[_0x288a34('0x122')])){var _0x507981=this[_0x288a34('0xe8')],_0x551f6a=_0x507981[_0x288a34('0x431')],_0x18de08=_0x507981[_0x288a34('0xbe')],_0x30f5f0=this[_0x288a34('0x85')],_0x2fa80b=_0x363f20[_0x288a34('0x2e')](_0x18de08,_0x363f20[_0x288a34('0x2e9')](0x4,_0x30f5f0)),_0x2fa80b=_0x564b61?_0x15183b[_0x288a34('0x107')](_0x2fa80b):_0x15183b[_0x288a34('0x179')](_0x363f20['UUBAK'](_0x363f20['ZLMio'](_0x2fa80b,0x0),this[_0x288a34('0x134')]),0x0);_0x564b61=_0x363f20[_0x288a34('0x2e9')](_0x2fa80b,_0x30f5f0),_0x18de08=_0x15183b[_0x288a34('0x325')](_0x363f20[_0x288a34('0x2e9')](0x4,_0x564b61),_0x18de08);if(_0x564b61){if(_0x363f20['cXftI'](_0x363f20[_0x288a34('0x1ce')],_0x363f20[_0x288a34('0x1ce')])){for(var _0x32ca71=0x0;_0x363f20[_0x288a34('0x456')](_0x32ca71,_0x564b61);_0x32ca71+=_0x30f5f0)this[_0x288a34('0x187')](_0x551f6a,_0x32ca71);_0x32ca71=_0x551f6a[_0x288a34('0xd1')](0x0,_0x564b61),_0x507981[_0x288a34('0xbe')]-=_0x18de08;}else{function _0x338cd5(){var _0x23f8df=_0x288a34;for(var _0x3b86f9=[],_0x3f7689=0x0;_0x363f20[_0x23f8df('0x3e0')](_0x3f7689,_0x39d550);_0x3f7689+=0x4)_0x3b86f9[_0x23f8df('0x36d')](_0x363f20[_0x23f8df('0x45b')](_0x363f20[_0x23f8df('0x360')](0x100000000,_0x132f3c[_0x23f8df('0x7f')]()),0x0));return new _0x592afd['init'](_0x3b86f9,_0x2752a8);}}}return new _0x4014ca[(_0x288a34('0x300'))](_0x32ca71,_0x18de08);}else{function _0x2a8199(){var _0x35cfe8=_0x288a34,_0x96f678=_0x363f20[_0x35cfe8('0x3a6')][_0x35cfe8('0x2f8')]('|'),_0x174a7c=0x0;while(!![]){switch(_0x96f678[_0x174a7c++]){case'0':var _0x17b7b4=this[_0x35cfe8('0x431')],_0x2669cf=_0xcb3a3d['words'],_0x4f5093=this[_0x35cfe8('0xbe')];continue;case'1':this['sigBytes']+=_0x141289;continue;case'2':if(_0x363f20[_0x35cfe8('0xe9')](_0x4f5093,0x4))for(var _0x316554=0x0;_0x363f20['kmXWy'](_0x316554,_0x1df8d4);_0x316554++)_0x17b7b4[_0x363f20['whyvz'](_0x363f20['sxPex'](_0x4f5093,_0x316554),0x2)]|=_0x363f20[_0x35cfe8('0x478')](_0x363f20[_0x35cfe8('0x1b9')](_0x363f20[_0x35cfe8('0x3b9')](_0x2669cf[_0x363f20[_0x35cfe8('0x3b9')](_0x316554,0x2)],_0x363f20[_0x35cfe8('0x355')](0x18,_0x363f20[_0x35cfe8('0x22')](0x8,_0x363f20[_0x35cfe8('0x42')](_0x316554,0x4)))),0xff),_0x363f20[_0x35cfe8('0x1f1')](0x18,_0x363f20[_0x35cfe8('0x11e')](0x8,_0x363f20[_0x35cfe8('0x42')](_0x363f20[_0x35cfe8('0x400')](_0x4f5093,_0x316554),0x4))));else{if(_0x363f20[_0x35cfe8('0x383')](0xffff,_0x2669cf['length']))for(_0x316554=0x0;_0x363f20['kmXWy'](_0x316554,_0x385b0b);_0x316554+=0x4)_0x17b7b4[_0x363f20[_0x35cfe8('0x3b9')](_0x363f20[_0x35cfe8('0x400')](_0x4f5093,_0x316554),0x2)]=_0x2669cf[_0x363f20[_0x35cfe8('0x3b9')](_0x316554,0x2)];else _0x17b7b4['push'][_0x35cfe8('0x71')](_0x17b7b4,_0x2669cf);}continue;case'3':this[_0x35cfe8('0x2b1')]();continue;case'4':_0xb70b4a=_0x1087f9[_0x35cfe8('0xbe')];continue;case'5':return this;}break;}}}},'clone':function(){var _0x5c05f8=_0x23ce14,_0x278706={'faHuu':function(_0x4bdcaf,_0x5482de){var _0x4716bc=_0x4528;return _0x363f20[_0x4716bc('0x395')](_0x4bdcaf,_0x5482de);},'eTWvd':function(_0x4d8306,_0x1c21d3){return _0x363f20['WAjuV'](_0x4d8306,_0x1c21d3);}};if(_0x363f20[_0x5c05f8('0x290')](_0x363f20[_0x5c05f8('0x3e8')],_0x363f20[_0x5c05f8('0x183')])){function _0x1d77b3(){var _0x34bb61=_0x5c05f8;_0x4625d3=this[_0x34bb61('0x431')]=_0x5af858||[],this[_0x34bb61('0xbe')]=_0x278706[_0x34bb61('0x36a')](_0x3b2d20,_0x200eb9)?_0x113f71:_0x278706['eTWvd'](0x4,_0x7d443['length']);}}else{var _0x21464a=_0x263d86[_0x5c05f8('0x31a')][_0x5c05f8('0x1e')](this);return _0x21464a[_0x5c05f8('0xe8')]=this['_data'][_0x5c05f8('0x31a')](),_0x21464a;}},'_minBufferSize':0x0});_0x2d74cd[_0x23ce14('0x2b')]=_0xe99d37['extend']({'cfg':_0x263d86[_0x23ce14('0x3ad')](),'init':function(_0x4a765a){var _0x31d32a=_0x23ce14,_0x4a2cf3={'Jngkd':_0x363f20[_0x31d32a('0x2f9')],'nOJSB':function(_0x17b562,_0x245ddf){var _0x561df1=_0x31d32a;return _0x363f20[_0x561df1('0x32c')](_0x17b562,_0x245ddf);},'FGfzE':function(_0x4feba0,_0x1f003e){var _0x26269a=_0x31d32a;return _0x363f20[_0x26269a('0x37d')](_0x4feba0,_0x1f003e);},'RdURl':function(_0x2d544f,_0x106221){var _0x1efee5=_0x31d32a;return _0x363f20[_0x1efee5('0x2b6')](_0x2d544f,_0x106221);},'pgXSk':function(_0x511b85,_0x4674a6){var _0x40e4e7=_0x31d32a;return _0x363f20[_0x40e4e7('0x2b6')](_0x511b85,_0x4674a6);},'pYvlN':function(_0x543c6c,_0x577109){var _0x3135c2=_0x31d32a;return _0x363f20[_0x3135c2('0x3a3')](_0x543c6c,_0x577109);},'DPqeu':function(_0x26931d,_0x54a047){var _0x5dabfe=_0x31d32a;return _0x363f20[_0x5dabfe('0x3d1')](_0x26931d,_0x54a047);},'GJIHT':function(_0x126c0f,_0x232728){var _0x261694=_0x31d32a;return _0x363f20[_0x261694('0x1fb')](_0x126c0f,_0x232728);},'yrgtS':function(_0x562fa1,_0x374901){var _0x574b48=_0x31d32a;return _0x363f20[_0x574b48('0x174')](_0x562fa1,_0x374901);},'CecrH':function(_0x2cca55,_0x5186e0){var _0x39603b=_0x31d32a;return _0x363f20[_0x39603b('0x39f')](_0x2cca55,_0x5186e0);},'huReZ':function(_0x344446,_0x2e0f30){var _0x6cb55=_0x31d32a;return _0x363f20[_0x6cb55('0x221')](_0x344446,_0x2e0f30);},'rTczW':function(_0x3e5c22,_0x5e4ed1){var _0x427cb8=_0x31d32a;return _0x363f20[_0x427cb8('0x1fb')](_0x3e5c22,_0x5e4ed1);},'OyyLB':function(_0x42e30d,_0x599f67){return _0x363f20['DkIfF'](_0x42e30d,_0x599f67);},'iGHKE':function(_0x27c14d,_0x1b3abd){var _0xfbb960=_0x31d32a;return _0x363f20[_0xfbb960('0x174')](_0x27c14d,_0x1b3abd);},'QQtWi':function(_0x46a0e1,_0x212621){var _0xb13b29=_0x31d32a;return _0x363f20[_0xb13b29('0x39f')](_0x46a0e1,_0x212621);},'pIYXW':function(_0x3a95f3,_0x305769){var _0x224b68=_0x31d32a;return _0x363f20[_0x224b68('0x32c')](_0x3a95f3,_0x305769);},'DdvPC':function(_0x509a4f,_0x4fd3ea){return _0x363f20['XrNPx'](_0x509a4f,_0x4fd3ea);},'VWTTF':function(_0x1ba2bf,_0x4d3de5){var _0xe3ba6b=_0x31d32a;return _0x363f20[_0xe3ba6b('0x2c9')](_0x1ba2bf,_0x4d3de5);},'tsOqf':function(_0x17cd8c,_0x745152){var _0x132c3d=_0x31d32a;return _0x363f20[_0x132c3d('0x37d')](_0x17cd8c,_0x745152);},'RFPxm':function(_0x30c919,_0x1b2793){var _0x542284=_0x31d32a;return _0x363f20[_0x542284('0xc7')](_0x30c919,_0x1b2793);},'NBkXt':function(_0x570a11,_0x4fbe2f){return _0x363f20['TPWKk'](_0x570a11,_0x4fbe2f);},'KWMwS':function(_0x299276,_0x66c14d){var _0x242f7a=_0x31d32a;return _0x363f20[_0x242f7a('0x3d1')](_0x299276,_0x66c14d);},'mKwIC':function(_0x1a9ea2,_0x3f9706){var _0x2c090e=_0x31d32a;return _0x363f20[_0x2c090e('0x174')](_0x1a9ea2,_0x3f9706);}};if(_0x363f20[_0x31d32a('0x290')](_0x363f20[_0x31d32a('0x3ef')],_0x363f20[_0x31d32a('0x3ef')]))this[_0x31d32a('0x15c')]=this[_0x31d32a('0x15c')][_0x31d32a('0x3ad')](_0x4a765a),this[_0x31d32a('0xbf')]();else{function _0xcd67a2(){var _0x4a6f12=_0x31d32a,_0x19e2b5={'FPfLf':function(_0x32e367,_0x465d9c){var _0x3ba36b=_0x4528;return _0x363f20[_0x3ba36b('0x437')](_0x32e367,_0x465d9c);},'sKNWX':function(_0xd9da23,_0x2426cb){return _0x363f20['uUHJP'](_0xd9da23,_0x2426cb);},'BWlmY':function(_0x117ba2,_0x42246a){var _0x22859b=_0x4528;return _0x363f20[_0x22859b('0x32c')](_0x117ba2,_0x42246a);},'KBvBy':function(_0xcf726c,_0x775f2e){var _0x49b48d=_0x4528;return _0x363f20[_0x49b48d('0x3a3')](_0xcf726c,_0x775f2e);},'lyBXj':function(_0x1f56f0,_0x5d457d){var _0x8eddd4=_0x4528;return _0x363f20[_0x8eddd4('0x40d')](_0x1f56f0,_0x5d457d);},'wkjhy':function(_0x17370b,_0x2c9e1e){var _0x380ef9=_0x4528;return _0x363f20[_0x380ef9('0x13e')](_0x17370b,_0x2c9e1e);},'iSEPM':function(_0x511cd3,_0x7d093f){var _0x457857=_0x4528;return _0x363f20[_0x457857('0x3b9')](_0x511cd3,_0x7d093f);},'gnPjH':function(_0x378f77,_0x45158f){var _0x536c9b=_0x4528;return _0x363f20[_0x536c9b('0x13e')](_0x378f77,_0x45158f);},'nclyN':function(_0x981102,_0x50631c){var _0x200af5=_0x4528;return _0x363f20[_0x200af5('0x3b9')](_0x981102,_0x50631c);},'ZBGpQ':function(_0x44f0e3,_0x5dab20){var _0x347a68=_0x4528;return _0x363f20[_0x347a68('0x3a3')](_0x44f0e3,_0x5dab20);},'KOdYg':function(_0x37806b,_0x3cc1dc){var _0x5b9a91=_0x4528;return _0x363f20[_0x5b9a91('0x2b6')](_0x37806b,_0x3cc1dc);},'pcqsM':function(_0x5e958b,_0x176f34){var _0xd91ae4=_0x4528;return _0x363f20[_0xd91ae4('0x40d')](_0x5e958b,_0x176f34);}},_0x3d0873=_0x947eee,_0x3b3f0b=_0x3d0873[_0x4a6f12('0x246')][_0x4a6f12('0x476')];_0x3d0873[_0x4a6f12('0x451')][_0x4a6f12('0x450')]={'stringify':function(_0x1e7ab7){var _0xf3bd2a=_0x4a6f12,_0x4c67c5=_0x4a2cf3[_0xf3bd2a('0x5d')]['split']('|'),_0x2eb0c0=0x0;while(!![]){switch(_0x4c67c5[_0x2eb0c0++]){case'0':_0x1e7ab7[_0xf3bd2a('0x2b1')]();continue;case'1':if(_0x646ee5=_0x4b68e2[_0xf3bd2a('0x40f')](0x40))for(;_0x4a2cf3[_0xf3bd2a('0x310')](_0x1e7ab7[_0xf3bd2a('0x47d')],0x4);)_0x1e7ab7[_0xf3bd2a('0x36d')](_0x646ee5);continue;case'2':return _0x1e7ab7[_0xf3bd2a('0xcd')]('');case'3':var _0x646ee5=_0x1e7ab7['words'],_0x29c9a4=_0x1e7ab7[_0xf3bd2a('0xbe')],_0x4b68e2=this['_map'];continue;case'4':for(var _0xe9d3ab=0x0;_0x4a2cf3[_0xf3bd2a('0x436')](_0xe9d3ab,_0x29c9a4);_0xe9d3ab+=0x3)for(var _0x2c598b=_0x4a2cf3[_0xf3bd2a('0x356')](_0x4a2cf3['pgXSk'](_0x4a2cf3[_0xf3bd2a('0x33d')](_0x4a2cf3['DPqeu'](_0x4a2cf3[_0xf3bd2a('0x301')](_0x646ee5[_0x4a2cf3[_0xf3bd2a('0x301')](_0xe9d3ab,0x2)],_0x4a2cf3[_0xf3bd2a('0x37e')](0x18,_0x4a2cf3[_0xf3bd2a('0x24b')](0x8,_0x4a2cf3[_0xf3bd2a('0x310')](_0xe9d3ab,0x4)))),0xff),0x10),_0x4a2cf3[_0xf3bd2a('0x33d')](_0x4a2cf3[_0xf3bd2a('0x35')](_0x4a2cf3[_0xf3bd2a('0x301')](_0x646ee5[_0x4a2cf3[_0xf3bd2a('0x301')](_0x4a2cf3[_0xf3bd2a('0x18a')](_0xe9d3ab,0x1),0x2)],_0x4a2cf3['yrgtS'](0x18,_0x4a2cf3['CecrH'](0x8,_0x4a2cf3['nOJSB'](_0x4a2cf3['huReZ'](_0xe9d3ab,0x1),0x4)))),0xff),0x8)),_0x4a2cf3[_0xf3bd2a('0x35')](_0x4a2cf3[_0xf3bd2a('0x301')](_0x646ee5[_0x4a2cf3[_0xf3bd2a('0x3a0')](_0x4a2cf3['OyyLB'](_0xe9d3ab,0x2),0x2)],_0x4a2cf3[_0xf3bd2a('0x2d9')](0x18,_0x4a2cf3['QQtWi'](0x8,_0x4a2cf3['pIYXW'](_0x4a2cf3[_0xf3bd2a('0x2d')](_0xe9d3ab,0x2),0x4)))),0xff)),_0x519946=0x0;_0x4a2cf3[_0xf3bd2a('0x10d')](0x4,_0x519946)&&_0x4a2cf3['tsOqf'](_0x4a2cf3['RFPxm'](_0xe9d3ab,_0x4a2cf3[_0xf3bd2a('0x1fc')](0.75,_0x519946)),_0x29c9a4);_0x519946++)_0x1e7ab7[_0xf3bd2a('0x36d')](_0x4b68e2['charAt'](_0x4a2cf3[_0xf3bd2a('0x1d3')](_0x4a2cf3['rTczW'](_0x2c598b,_0x4a2cf3[_0xf3bd2a('0x1fc')](0x6,_0x4a2cf3[_0xf3bd2a('0x435')](0x3,_0x519946))),0x3f)));continue;case'5':_0x1e7ab7=[];continue;}break;}},'parse':function(_0x168ecc){var _0xde0727=_0x4a6f12,_0x95c4ef=_0x168ecc[_0xde0727('0x47d')],_0x37e166=this[_0xde0727('0x21d')],_0xfbf5f3=_0x37e166[_0xde0727('0x40f')](0x40);_0xfbf5f3&&(_0xfbf5f3=_0x168ecc[_0xde0727('0x125')](_0xfbf5f3),_0x19e2b5['FPfLf'](-0x1,_0xfbf5f3)&&(_0x95c4ef=_0xfbf5f3));for(var _0xfbf5f3=[],_0x16b0fd=0x0,_0x235ddf=0x0;_0x19e2b5[_0xde0727('0x3ba')](_0x235ddf,_0x95c4ef);_0x235ddf++)if(_0x19e2b5[_0xde0727('0x36c')](_0x235ddf,0x4)){var _0x224a6a=_0x19e2b5['KBvBy'](_0x37e166['indexOf'](_0x168ecc[_0xde0727('0x40f')](_0x19e2b5[_0xde0727('0x102')](_0x235ddf,0x1))),_0x19e2b5[_0xde0727('0x3f3')](0x2,_0x19e2b5['BWlmY'](_0x235ddf,0x4))),_0x40209a=_0x19e2b5[_0xde0727('0x1ad')](_0x37e166[_0xde0727('0x125')](_0x168ecc[_0xde0727('0x40f')](_0x235ddf)),_0x19e2b5['lyBXj'](0x6,_0x19e2b5['gnPjH'](0x2,_0x19e2b5[_0xde0727('0x36c')](_0x235ddf,0x4))));_0xfbf5f3[_0x19e2b5[_0xde0727('0x39b')](_0x16b0fd,0x2)]|=_0x19e2b5['ZBGpQ'](_0x19e2b5['KOdYg'](_0x224a6a,_0x40209a),_0x19e2b5[_0xde0727('0x438')](0x18,_0x19e2b5[_0xde0727('0x394')](0x8,_0x19e2b5['BWlmY'](_0x16b0fd,0x4)))),_0x16b0fd++;}return _0x3b3f0b[_0xde0727('0x286')](_0xfbf5f3,_0x16b0fd);},'_map':_0x363f20[_0x4a6f12('0x1de')]};}}},'reset':function(){var _0x1b7a90=_0x23ce14;if(_0x363f20['yTXVY'](_0x363f20['hFWXe'],_0x363f20[_0x1b7a90('0x172')]))_0xe99d37[_0x1b7a90('0xbf')][_0x1b7a90('0x1e')](this),this['_doReset']();else{function _0x5886fe(){var _0x18ec1a=_0x1b7a90;return _0x48d216&&this[_0x18ec1a('0x26')](_0x349877),this['_doFinalize']();}}},'update':function(_0x216f7d){var _0x4d5b54=_0x23ce14;if(_0x363f20[_0x4d5b54('0x290')](_0x363f20['KglyU'],_0x363f20[_0x4d5b54('0x43d')])){function _0x118461(){var _0x5eea66=_0x4d5b54,_0x44da5a=_0x257edc[_0x5eea66('0x286')](_0x1aeff9[_0x5eea66('0x408')](0x2,0x4));_0x4e57d2[_0x5eea66('0xd1')](0x0,0x4),_0x5b20f3[_0x5eea66('0xbe')]-=0x10;}}else return this[_0x4d5b54('0x26')](_0x216f7d),this[_0x4d5b54('0x26d')](),this;},'finalize':function(_0x246ff6){var _0x2e36a5=_0x23ce14;if(_0x363f20['oSlyH'](_0x363f20['PTpFo'],_0x363f20[_0x2e36a5('0x3c6')]))return _0x246ff6&&this[_0x2e36a5('0x26')](_0x246ff6),this['_doFinalize']();else{function _0xd13eea(){var _0x527133=_0x2e36a5;return this['Encryptor'][_0x527133('0x286')](_0xe460a9,_0x5e5cd3);}}},'blockSize':0x10,'_createHelper':function(_0xa16132){var _0xbbcffa=_0x23ce14,_0x40aeac={'OeJsC':function(_0x70f8c7,_0x47d398){var _0x1e178f=_0x4528;return _0x363f20[_0x1e178f('0x170')](_0x70f8c7,_0x47d398);},'QmJKo':function(_0x819a94,_0x2180ac){var _0x2286db=_0x4528;return _0x363f20[_0x2286db('0xc7')](_0x819a94,_0x2180ac);},'ziEUd':function(_0x3bf8a9,_0x15e0a0){var _0x18b290=_0x4528;return _0x363f20[_0x18b290('0x1ea')](_0x3bf8a9,_0x15e0a0);},'YheiH':_0x363f20['pgBnY'],'ownhI':_0x363f20['RLDan']};if(_0x363f20[_0xbbcffa('0x1ea')](_0x363f20[_0xbbcffa('0x160')],_0x363f20[_0xbbcffa('0x234')])){function _0x2854e0(){var _0x464695=_0xbbcffa;_0x126fd2[_0x464695('0xbf')][_0x464695('0x1e')](this),this[_0x464695('0x32d')]();}}else return function(_0x2e0aa8,_0x3e05d9){var _0x38c792=_0xbbcffa;if(_0x40aeac['ziEUd'](_0x40aeac[_0x38c792('0x33f')],_0x40aeac[_0x38c792('0x432')])){function _0x29a08e(){var _0x38b67d=_0x38c792,_0xa03e87=this[_0x38b67d('0x1e7')];_0xa03e87?this[_0x38b67d('0x1e7')]=_0x293e8b:_0xa03e87=this[_0x38b67d('0x1f6')];for(var _0x60283b=0x0;_0x40aeac[_0x38b67d('0x39e')](_0x60283b,_0x1d27c3);_0x60283b++)_0x38d93d[_0x40aeac[_0x38b67d('0x322')](_0x41a78b,_0x60283b)]^=_0xa03e87[_0x60283b];}}else return new _0xa16132['init'](_0x3e05d9)[_0x38c792('0x68')](_0x2e0aa8);};},'_createHmacHelper':function(_0x4f049d){var _0x19b1e7=_0x23ce14;if(_0x363f20[_0x19b1e7('0x42c')](_0x363f20[_0x19b1e7('0x247')],_0x363f20[_0x19b1e7('0x247')]))return function(_0x27010a,_0xe4f8c1){var _0x183c9c=_0x19b1e7;if(_0x363f20['BItgy'](_0x363f20[_0x183c9c('0x15b')],_0x363f20[_0x183c9c('0x136')])){function _0x2007c5(){var _0x3edaea=_0x183c9c;return this['_append'](_0x2f2cd7),this[_0x3edaea('0x26d')](),this;}}else return new _0xe4926e[(_0x183c9c('0x338'))][(_0x183c9c('0x300'))](_0x4f049d,_0xe4f8c1)['finalize'](_0x27010a);};else{function _0x57874e(){var _0x516d23=_0x19b1e7,_0x5d31a9=_0x112856[_0x516d23('0x31a')][_0x516d23('0x1e')](this);return _0x5d31a9[_0x516d23('0x363')]=this[_0x516d23('0x363')][_0x516d23('0x31a')](),_0x5d31a9;}}}});var _0xe4926e=_0x3f0b1e[_0x23ce14('0x329')]={};return _0x3f0b1e;}(Math);(function(){var _0x4ece40=_0x4528,_0x5206e7={'zZhkT':function(_0xc17aa6,_0x182278){return _0xc17aa6*_0x182278;},'gMUUN':function(_0x1269c9,_0x23da4b){return _0x1269c9-_0x23da4b;},'cgglP':function(_0x251ba3,_0x11acc0){return _0x251ba3%_0x11acc0;},'CNFfE':function(_0x536a33,_0x7947f6){return _0x536a33|_0x7947f6;},'Jzqhq':function(_0x11d845,_0xab08fa){return _0x11d845|_0xab08fa;},'jXcmT':function(_0x32b597,_0x47e5ca){return _0x32b597<<_0x47e5ca;},'qSIbA':function(_0x38d09f,_0x3d28fc){return _0x38d09f<<_0x3d28fc;},'rNxrK':function(_0x15ef58,_0x3f1e82){return _0x15ef58<_0x3f1e82;},'KjHCk':function(_0x30e11e,_0x1f5908){return _0x30e11e===_0x1f5908;},'XBrVd':_0x4ece40('0x2ef'),'IYtcf':_0x4ece40('0x36b'),'WcBdL':function(_0x3b52ae,_0x29dbb8){return _0x3b52ae%_0x29dbb8;},'qISXy':function(_0x199f9e,_0x8f615b){return _0x199f9e<_0x8f615b;},'RSLXu':function(_0x4b6307,_0x1d5870){return _0x4b6307|_0x1d5870;},'ZgXcK':function(_0x8a1108,_0x4a1ec7){return _0x8a1108|_0x4a1ec7;},'hoAxC':function(_0xec1572,_0xf1337f){return _0xec1572<<_0xf1337f;},'KDgmf':function(_0x22930d,_0x437670){return _0x22930d&_0x437670;},'akHCn':function(_0x1db924,_0x68f57f){return _0x1db924>>>_0x68f57f;},'uhCts':function(_0x5cc141,_0x2f3ead){return _0x5cc141-_0x2f3ead;},'DbmJC':function(_0x54d805,_0x4d5392){return _0x54d805%_0x4d5392;},'EXGZU':function(_0x27e6f4,_0x26e8f5){return _0x27e6f4<<_0x26e8f5;},'VzlFI':function(_0xae01f8,_0x211874){return _0xae01f8&_0x211874;},'cVsrE':function(_0x264150,_0x242e32){return _0x264150>>>_0x242e32;},'qENlL':function(_0x277aee,_0x436a1c){return _0x277aee+_0x436a1c;},'hnZAT':function(_0x54dc9c,_0x197d82){return _0x54dc9c-_0x197d82;},'rebvR':function(_0x231d6e,_0x2b5bc4){return _0x231d6e*_0x2b5bc4;},'FqVZG':function(_0x1e59a2,_0x42fa14){return _0x1e59a2+_0x42fa14;},'UEVQK':function(_0x471ab5,_0x21aaf6){return _0x471ab5>>>_0x21aaf6;},'sPWHp':function(_0x3fa75a,_0xa4c88f){return _0x3fa75a-_0xa4c88f;},'jgBlK':function(_0x583803,_0x547008){return _0x583803%_0x547008;},'lQutF':function(_0x4644a4,_0x5ab75e){return _0x4644a4>_0x5ab75e;},'XfZLc':function(_0xbb11ad,_0x36a50b){return _0xbb11ad+_0x36a50b;},'hVUbV':function(_0x247146,_0x4bfc27){return _0x247146*_0x4bfc27;},'miaDA':function(_0xf33be3,_0x52a637){return _0xf33be3&_0x52a637;},'jfGaU':function(_0x80932e,_0x408532){return _0x80932e>>>_0x408532;},'wFJKC':function(_0x2283d5,_0x3b3405){return _0x2283d5-_0x3b3405;},'fYLpU':function(_0x5a3dde,_0x397af9){return _0x5a3dde!==_0x397af9;},'AEusc':_0x4ece40('0x38f'),'lpcyf':_0x4ece40('0xf5'),'LxDEA':function(_0x275c00,_0x547ece){return _0x275c00!=_0x547ece;},'FUCJd':function(_0x1101a2,_0x58faaf){return _0x1101a2<_0x58faaf;},'yXEoL':function(_0x901686,_0x2e5b1f){return _0x901686%_0x2e5b1f;},'DSnhl':function(_0x4c4c52,_0x2128c2){return _0x4c4c52!==_0x2128c2;},'NORod':_0x4ece40('0x416'),'bUfws':_0x4ece40('0x33a'),'TfQQg':function(_0x4c605e,_0x18ab96){return _0x4c605e*_0x18ab96;},'zyIvZ':function(_0x108abf,_0x34ed44){return _0x108abf%_0x34ed44;},'vpTDr':function(_0x1e1534,_0x29467f){return _0x1e1534>>>_0x29467f;},'zteGT':function(_0x2c1407,_0x1bf2c2){return _0x2c1407-_0x1bf2c2;},'XSDPs':function(_0x110955,_0x56b9b4){return _0x110955*_0x56b9b4;},'nzFwZ':function(_0x8ba88b,_0x2f8c74){return _0x8ba88b%_0x2f8c74;},'KphmJ':function(_0x44624a,_0x56a5b0){return _0x44624a>>>_0x56a5b0;},'BewIj':function(_0xa2f49d,_0x1a8cef){return _0xa2f49d-_0x1a8cef;},'Qsbzh':_0x4ece40('0x3b7')},_0x37d027=CryptoJS,_0x315c4a=_0x37d027['lib']['WordArray'];_0x37d027[_0x4ece40('0x451')][_0x4ece40('0x450')]={'stringify':function(_0x3cf0bb){var _0x2eac64=_0x4ece40;if(_0x5206e7[_0x2eac64('0x2c8')](_0x5206e7[_0x2eac64('0x36f')],_0x5206e7[_0x2eac64('0x36f')])){var _0x3abd2f=_0x5206e7[_0x2eac64('0x8b')]['split']('|'),_0x5c35f9=0x0;while(!![]){switch(_0x3abd2f[_0x5c35f9++]){case'0':if(_0x3a1427=_0x446621[_0x2eac64('0x40f')](0x40))for(;_0x5206e7[_0x2eac64('0x43c')](_0x3cf0bb['length'],0x4);)_0x3cf0bb['push'](_0x3a1427);continue;case'1':var _0x3a1427=_0x3cf0bb[_0x2eac64('0x431')],_0x3e234d=_0x3cf0bb[_0x2eac64('0xbe')],_0x446621=this[_0x2eac64('0x21d')];continue;case'2':_0x3cf0bb=[];continue;case'3':return _0x3cf0bb['join']('');case'4':_0x3cf0bb[_0x2eac64('0x2b1')]();continue;case'5':for(var _0xd2240f=0x0;_0x5206e7[_0x2eac64('0x3af')](_0xd2240f,_0x3e234d);_0xd2240f+=0x3)for(var _0x1680d3=_0x5206e7[_0x2eac64('0x443')](_0x5206e7['ZgXcK'](_0x5206e7[_0x2eac64('0x32b')](_0x5206e7[_0x2eac64('0x1be')](_0x5206e7[_0x2eac64('0x2f2')](_0x3a1427[_0x5206e7[_0x2eac64('0x2f2')](_0xd2240f,0x2)],_0x5206e7[_0x2eac64('0x374')](0x18,_0x5206e7[_0x2eac64('0x250')](0x8,_0x5206e7[_0x2eac64('0x467')](_0xd2240f,0x4)))),0xff),0x10),_0x5206e7['EXGZU'](_0x5206e7[_0x2eac64('0x3b5')](_0x5206e7[_0x2eac64('0xd3')](_0x3a1427[_0x5206e7['cVsrE'](_0x5206e7['qENlL'](_0xd2240f,0x1),0x2)],_0x5206e7[_0x2eac64('0x1f')](0x18,_0x5206e7[_0x2eac64('0x3a8')](0x8,_0x5206e7['DbmJC'](_0x5206e7[_0x2eac64('0xda')](_0xd2240f,0x1),0x4)))),0xff),0x8)),_0x5206e7[_0x2eac64('0x3b5')](_0x5206e7[_0x2eac64('0xd3')](_0x3a1427[_0x5206e7['UEVQK'](_0x5206e7[_0x2eac64('0xda')](_0xd2240f,0x2),0x2)],_0x5206e7[_0x2eac64('0x350')](0x18,_0x5206e7['rebvR'](0x8,_0x5206e7['jgBlK'](_0x5206e7[_0x2eac64('0xda')](_0xd2240f,0x2),0x4)))),0xff)),_0xdd3017=0x0;_0x5206e7['lQutF'](0x4,_0xdd3017)&&_0x5206e7[_0x2eac64('0x3af')](_0x5206e7[_0x2eac64('0x2b0')](_0xd2240f,_0x5206e7['hVUbV'](0.75,_0xdd3017)),_0x3e234d);_0xdd3017++)_0x3cf0bb[_0x2eac64('0x36d')](_0x446621[_0x2eac64('0x40f')](_0x5206e7[_0x2eac64('0x304')](_0x5206e7['jfGaU'](_0x1680d3,_0x5206e7[_0x2eac64('0xb2')](0x6,_0x5206e7[_0x2eac64('0x3a2')](0x3,_0xdd3017))),0x3f)));continue;}break;}}else{function _0x5d704d(){var _0x449492=_0x2eac64;for(var _0x5b2bfa=_0x5206e7[_0x449492('0x250')](0x4,_0x113587),_0x5b2bfa=_0x5206e7[_0x449492('0x190')](_0x5b2bfa,_0x5206e7['cgglP'](_0x42d066['sigBytes'],_0x5b2bfa)),_0x3f78bd=_0x5206e7[_0x449492('0x261')](_0x5206e7[_0x449492('0x261')](_0x5206e7[_0x449492('0x2a2')](_0x5206e7[_0x449492('0x211')](_0x5b2bfa,0x18),_0x5206e7[_0x449492('0x211')](_0x5b2bfa,0x10)),_0x5206e7[_0x449492('0x330')](_0x5b2bfa,0x8)),_0x5b2bfa),_0x12de4b=[],_0x370011=0x0;_0x5206e7[_0x449492('0x302')](_0x370011,_0x5b2bfa);_0x370011+=0x4)_0x12de4b[_0x449492('0x36d')](_0x3f78bd);_0x5b2bfa=_0x52a9a8['create'](_0x12de4b,_0x5b2bfa),_0x5c8cad[_0x449492('0x3b2')](_0x5b2bfa);}}},'parse':function(_0x389200){var _0x4418a8=_0x4ece40;if(_0x5206e7['fYLpU'](_0x5206e7['AEusc'],_0x5206e7[_0x4418a8('0x242')])){var _0x3708a3=_0x389200['length'],_0x16d48f=this[_0x4418a8('0x21d')],_0x16040a=_0x16d48f[_0x4418a8('0x40f')](0x40);_0x16040a&&(_0x16040a=_0x389200[_0x4418a8('0x125')](_0x16040a),_0x5206e7[_0x4418a8('0x381')](-0x1,_0x16040a)&&(_0x3708a3=_0x16040a));for(var _0x16040a=[],_0x132a47=0x0,_0x5a2f46=0x0;_0x5206e7[_0x4418a8('0x1cc')](_0x5a2f46,_0x3708a3);_0x5a2f46++)if(_0x5206e7[_0x4418a8('0x1e8')](_0x5a2f46,0x4)){if(_0x5206e7[_0x4418a8('0x185')](_0x5206e7[_0x4418a8('0x29b')],_0x5206e7[_0x4418a8('0x8f')])){var _0x4e758d=_0x5206e7[_0x4418a8('0x20')](_0x16d48f['indexOf'](_0x389200[_0x4418a8('0x40f')](_0x5206e7['wFJKC'](_0x5a2f46,0x1))),_0x5206e7[_0x4418a8('0xa5')](0x2,_0x5206e7[_0x4418a8('0x457')](_0x5a2f46,0x4))),_0x13051b=_0x5206e7[_0x4418a8('0x236')](_0x16d48f['indexOf'](_0x389200[_0x4418a8('0x40f')](_0x5a2f46)),_0x5206e7[_0x4418a8('0x1f4')](0x6,_0x5206e7[_0x4418a8('0x2c3')](0x2,_0x5206e7[_0x4418a8('0x415')](_0x5a2f46,0x4))));_0x16040a[_0x5206e7[_0x4418a8('0x44e')](_0x132a47,0x2)]|=_0x5206e7['EXGZU'](_0x5206e7[_0x4418a8('0x469')](_0x4e758d,_0x13051b),_0x5206e7[_0x4418a8('0x13')](0x18,_0x5206e7['XSDPs'](0x8,_0x5206e7[_0x4418a8('0x415')](_0x132a47,0x4)))),_0x132a47++;}else{function _0x4b0bcb(){var _0x7ab9c6=_0x4418a8;return new _0x3c2082[(_0x7ab9c6('0x300'))](_0x2387f9)[_0x7ab9c6('0x68')](_0x12ab2e);}}}return _0x315c4a[_0x4418a8('0x286')](_0x16040a,_0x132a47);}else{function _0x47d034(){var _0xd977cf=_0x4418a8;_0x26674f[_0xd977cf('0xce')]['init'][_0xd977cf('0x71')](this,arguments);}}},'_map':_0x5206e7[_0x4ece40('0x420')]};}(),function(_0x468300){var _0x4551a0=_0x4528,_0x57a0de={'GaNtJ':function(_0x502cc2,_0x5d0be3){return _0x502cc2||_0x5d0be3;},'xDMYS':function(_0x15847f,_0x2280d1){return _0x15847f===_0x2280d1;},'hkVWt':_0x4551a0('0x12f'),'IvAfu':function(_0x361c86,_0x276fd9){return _0x361c86+_0x276fd9;},'UVTwy':function(_0x1aaa8a,_0x3db146){return _0x1aaa8a+_0x3db146;},'hedDL':function(_0x3e2dc1,_0xd84220){return _0x3e2dc1|_0xd84220;},'VakXF':function(_0x2d2439,_0xf5a835){return _0x2d2439&_0xf5a835;},'ZmOpl':function(_0x4c6f66,_0x5131a5){return _0x4c6f66&_0x5131a5;},'NznnZ':function(_0x27f6ff,_0x546295){return _0x27f6ff<<_0x546295;},'haRlg':function(_0x26adbb,_0xec26b){return _0x26adbb>>>_0xec26b;},'OviAS':function(_0x5b88d6,_0x907d31){return _0x5b88d6-_0x907d31;},'SmPSo':function(_0x5114b2,_0x38bc8e){return _0x5114b2!==_0x38bc8e;},'qdSIl':_0x4551a0('0x1bf'),'JusTR':_0x4551a0('0x8e'),'NEfJA':function(_0x599e05,_0x421052){return _0x599e05+_0x421052;},'daSSr':function(_0x553025,_0x372796){return _0x553025+_0x372796;},'ePCwn':function(_0x34e249,_0x527423){return _0x34e249>>>_0x527423;},'zZcJA':function(_0x5c8ef7,_0x45dd59){return _0x5c8ef7-_0x45dd59;},'WnFHD':_0x4551a0('0x1f0'),'wBySK':_0x4551a0('0x14a'),'IgOpW':function(_0xa5e26,_0x5da222){return _0xa5e26+_0x5da222;},'iXwIk':function(_0x126eda,_0x1f982f){return _0x126eda^_0x1f982f;},'wZVAj':function(_0x66271e,_0x1abdc4){return _0x66271e+_0x1abdc4;},'EAvnb':function(_0x491d12,_0x3c6fa8){return _0x491d12<<_0x3c6fa8;},'KwJDW':function(_0x52338b,_0x8996cb){return _0x52338b*_0x8996cb;},'cIsVP':function(_0x96e62e,_0x4eb625){return _0x96e62e%_0x4eb625;},'vFLdn':function(_0x30dc11,_0x171b06){return _0x30dc11-_0x171b06;},'IldQb':function(_0x4502a1,_0x3d2d60){return _0x4502a1>>>_0x3d2d60;},'BfOom':function(_0x313e5d,_0x1abf92){return _0x313e5d-_0x1abf92;},'QRkdR':function(_0x2acaf3,_0x3263ae){return _0x2acaf3*_0x3263ae;},'zNQAS':function(_0x2d8a3f,_0x32ee31){return _0x2d8a3f%_0x32ee31;},'uBqEK':function(_0x581f71,_0x4670fe){return _0x581f71!==_0x4670fe;},'TGfgo':'vSYBg','LaGcz':_0x4551a0('0xaa'),'IZTYI':function(_0x5b1a5f,_0x5a8342){return _0x5b1a5f+_0x5a8342;},'YCQDJ':function(_0x244089,_0x1381b1){return _0x244089+_0x1381b1;},'cmoHE':function(_0x590474,_0x1ad1a9){return _0x590474^_0x1ad1a9;},'gwFrE':function(_0x3f63f2,_0x7e8a3e){return _0x3f63f2+_0x7e8a3e;},'FIxHP':function(_0x43e64e,_0x37d695){return _0x43e64e==_0x37d695;},'TCJXf':_0x4551a0('0xb8'),'ambdW':function(_0x5142a2,_0x231f5c){return _0x5142a2!==_0x231f5c;},'nLSpm':_0x4551a0('0x64'),'hFXci':_0x4551a0('0x3a5'),'JAXPO':function(_0x19de7f,_0x1f4042){return _0x19de7f-_0x1f4042;},'VVybt':function(_0x36e8d8,_0x2006e7){return _0x36e8d8*_0x2006e7;},'zLTTj':function(_0x58247f,_0x23f816){return _0x58247f%_0x23f816;},'dffGH':_0x4551a0('0x53'),'nNrnc':function(_0x3e4d0f,_0x2913da){return _0x3e4d0f===_0x2913da;},'tlgIz':_0x4551a0('0x1a2'),'NxaLP':_0x4551a0('0xef'),'SIqFO':function(_0xad8f48,_0x8dec7e){return _0xad8f48>_0x8dec7e;},'NCcbT':function(_0x456ef8,_0x1b29c5){return _0x456ef8===_0x1b29c5;},'LRwRs':_0x4551a0('0x7e'),'SgeDV':_0x4551a0('0xdf'),'DgEII':function(_0x5a6f3e,_0x374d75){return _0x5a6f3e+_0x374d75;},'dNmIR':function(_0x4ac637,_0x3c0cbf){return _0x4ac637|_0x3c0cbf;},'Azshj':function(_0x94ff35,_0x1daf99){return _0x94ff35>>>_0x1daf99;},'DSbTT':function(_0x1b847c,_0x5188fc){return _0x1b847c&_0x5188fc;},'qFypi':function(_0x424510,_0x4f2ff9){return _0x424510|_0x4f2ff9;},'GCbUV':function(_0x163b9a,_0x683fca){return _0x163b9a+_0x683fca;},'jcwhu':function(_0x43734d,_0x1171ec){return _0x43734d+_0x1171ec;},'wUaSa':function(_0x4a2d62,_0x4646e9){return _0x4a2d62+_0x4646e9;},'MEKCf':function(_0x1089de,_0x3934c1){return _0x1089de+_0x3934c1;},'Bbfza':function(_0x379d3f,_0x1bd261){return _0x379d3f+_0x1bd261;},'ayvGW':function(_0x505bdc,_0x5bd83f){return _0x505bdc+_0x5bd83f;},'VKUNf':function(_0x3c430d,_0x17f8e4){return _0x3c430d+_0x17f8e4;},'CbgsJ':function(_0xe6b1b,_0x1a923a){return _0xe6b1b+_0x1a923a;},'LbOQg':function(_0x1508e9,_0x48ea00){return _0x1508e9+_0x48ea00;},'qLzKw':function(_0x193bf3,_0x5455a5){return _0x193bf3+_0x5455a5;},'dAjvX':function(_0x292889,_0x236077,_0x220892,_0x3e069f,_0x494747,_0x4419df,_0x48c850,_0x585f15){return _0x292889(_0x236077,_0x220892,_0x3e069f,_0x494747,_0x4419df,_0x48c850,_0x585f15);},'svOeX':function(_0x13aacb,_0x2c6498,_0x533ae2,_0x2b3854,_0x693fb0,_0x354b15,_0x2b0859,_0x13688d){return _0x13aacb(_0x2c6498,_0x533ae2,_0x2b3854,_0x693fb0,_0x354b15,_0x2b0859,_0x13688d);},'YtYYA':function(_0x28bb33,_0x28d2e9,_0x5189e7,_0xb49fca,_0x28247b,_0x577e3a,_0x1bbb34,_0x9c2056){return _0x28bb33(_0x28d2e9,_0x5189e7,_0xb49fca,_0x28247b,_0x577e3a,_0x1bbb34,_0x9c2056);},'WAcMH':function(_0x2fe113,_0x1db626,_0x58c00f,_0x3a1f8a,_0x5cd8de,_0x20ecb1,_0x24f504,_0x14bc88){return _0x2fe113(_0x1db626,_0x58c00f,_0x3a1f8a,_0x5cd8de,_0x20ecb1,_0x24f504,_0x14bc88);},'SxQIt':function(_0x302bef,_0x34a6c0,_0x4f0e60,_0x94db2a,_0x270697,_0x4c80a9,_0x5cfbb6,_0x327885){return _0x302bef(_0x34a6c0,_0x4f0e60,_0x94db2a,_0x270697,_0x4c80a9,_0x5cfbb6,_0x327885);},'MJzpq':function(_0x446a1c,_0x4ddbaa,_0xbc8c09,_0x20b413,_0x4b0a15,_0x23f265,_0x2a71f4,_0x270a87){return _0x446a1c(_0x4ddbaa,_0xbc8c09,_0x20b413,_0x4b0a15,_0x23f265,_0x2a71f4,_0x270a87);},'oWogc':function(_0x1e82b0,_0x37f096,_0x210fc0,_0x59fc91,_0x5b9953,_0x138f47,_0x16d71e,_0x425750){return _0x1e82b0(_0x37f096,_0x210fc0,_0x59fc91,_0x5b9953,_0x138f47,_0x16d71e,_0x425750);},'yiGXV':function(_0x3f5082,_0x5a0eec,_0x8b06e7,_0x1e8f85,_0x453fa9,_0x2677ea,_0x34efde,_0x5a6ba7){return _0x3f5082(_0x5a0eec,_0x8b06e7,_0x1e8f85,_0x453fa9,_0x2677ea,_0x34efde,_0x5a6ba7);},'XMLfF':function(_0x2b44b5,_0x56fdd8,_0x330a1c,_0x23c7b4,_0x45a803,_0x5ca73e,_0x1755ee,_0x2e8a56){return _0x2b44b5(_0x56fdd8,_0x330a1c,_0x23c7b4,_0x45a803,_0x5ca73e,_0x1755ee,_0x2e8a56);},'aNhqU':function(_0xf4937,_0x475994,_0x41dd71,_0x2ce152,_0x39d721,_0x42a385,_0x58f7bf,_0x10aa9a){return _0xf4937(_0x475994,_0x41dd71,_0x2ce152,_0x39d721,_0x42a385,_0x58f7bf,_0x10aa9a);},'NkpYg':function(_0x380fd7,_0x512e3b,_0x49d045,_0x1d989c,_0x40a959,_0x232298,_0x4f727b,_0x4db6d1){return _0x380fd7(_0x512e3b,_0x49d045,_0x1d989c,_0x40a959,_0x232298,_0x4f727b,_0x4db6d1);},'fJacV':function(_0x4c4449,_0x4a1c0f,_0x5a49e4,_0xf96d23,_0xa0a22b,_0x5ae945,_0x2543d3,_0x406b5b){return _0x4c4449(_0x4a1c0f,_0x5a49e4,_0xf96d23,_0xa0a22b,_0x5ae945,_0x2543d3,_0x406b5b);},'Whfov':function(_0x51afec,_0x58ee12,_0x1248d3,_0x1afb2c,_0x15fe29,_0x39868f,_0x17389c,_0x426c86){return _0x51afec(_0x58ee12,_0x1248d3,_0x1afb2c,_0x15fe29,_0x39868f,_0x17389c,_0x426c86);},'rgQTS':function(_0x36a20c,_0x3b4445,_0x156e29,_0x3e905a,_0x28f149,_0x749ad5,_0x1760d8,_0x38d475){return _0x36a20c(_0x3b4445,_0x156e29,_0x3e905a,_0x28f149,_0x749ad5,_0x1760d8,_0x38d475);},'eySri':function(_0x14b7f3,_0x47e6b1,_0x1bdee7,_0x2a8e33,_0x4257bc,_0x2a7917,_0x162b04,_0x8d74d4){return _0x14b7f3(_0x47e6b1,_0x1bdee7,_0x2a8e33,_0x4257bc,_0x2a7917,_0x162b04,_0x8d74d4);},'fIvTo':function(_0x48a562,_0x24cb70,_0x2b7ae8,_0x210438,_0x3cc386,_0x179429,_0x542c84,_0x24f9a0){return _0x48a562(_0x24cb70,_0x2b7ae8,_0x210438,_0x3cc386,_0x179429,_0x542c84,_0x24f9a0);},'UEDBD':function(_0x240ba5,_0x5b71d9,_0x13c505,_0x84e8c2,_0x4a527e,_0x5e9045,_0x45d83d,_0x5448b2){return _0x240ba5(_0x5b71d9,_0x13c505,_0x84e8c2,_0x4a527e,_0x5e9045,_0x45d83d,_0x5448b2);},'AnHor':function(_0xe305d1,_0x16cb89,_0x56f5de,_0x292ef2,_0x5d47ff,_0x19287f,_0x50c011,_0x318a27){return _0xe305d1(_0x16cb89,_0x56f5de,_0x292ef2,_0x5d47ff,_0x19287f,_0x50c011,_0x318a27);},'Qorbo':function(_0x5a19f7,_0x51a0b5,_0x1db7b6,_0x199b5d,_0x22585d,_0x12f428,_0x2479c2,_0x1e191a){return _0x5a19f7(_0x51a0b5,_0x1db7b6,_0x199b5d,_0x22585d,_0x12f428,_0x2479c2,_0x1e191a);},'dlaeN':function(_0x2240af,_0x296215,_0x3c38a0,_0x33ef32,_0x3d43f5,_0x1c02d2,_0x63f928,_0x551f30){return _0x2240af(_0x296215,_0x3c38a0,_0x33ef32,_0x3d43f5,_0x1c02d2,_0x63f928,_0x551f30);},'Spcqy':function(_0x5ba83f,_0x1dfaf5,_0x145e48,_0x275c3c,_0x4e1785,_0x57e116,_0x64be77,_0x31e070){return _0x5ba83f(_0x1dfaf5,_0x145e48,_0x275c3c,_0x4e1785,_0x57e116,_0x64be77,_0x31e070);},'wqVtV':function(_0x349929,_0x395fa2,_0x32fa4a,_0x443b0e,_0x3d285d,_0x4a1c5b,_0x49b7d6,_0x2b723f){return _0x349929(_0x395fa2,_0x32fa4a,_0x443b0e,_0x3d285d,_0x4a1c5b,_0x49b7d6,_0x2b723f);},'eZSVr':function(_0x2ebcec,_0x4673b4,_0x4cbbd1,_0x2e72e1,_0x2d7aeb,_0x521e3b,_0x47acca,_0x55e4ff){return _0x2ebcec(_0x4673b4,_0x4cbbd1,_0x2e72e1,_0x2d7aeb,_0x521e3b,_0x47acca,_0x55e4ff);},'MRzXM':function(_0x37ac52,_0x3c42d3,_0x556303,_0x5ed627,_0x281b80,_0x42ac64,_0x521862,_0x57da12){return _0x37ac52(_0x3c42d3,_0x556303,_0x5ed627,_0x281b80,_0x42ac64,_0x521862,_0x57da12);},'SdbzQ':function(_0x57bed0,_0x250542,_0x1b27e5,_0x446e8b,_0x5838c1,_0x5dcb94,_0x4983ea,_0x279101){return _0x57bed0(_0x250542,_0x1b27e5,_0x446e8b,_0x5838c1,_0x5dcb94,_0x4983ea,_0x279101);},'CPgqY':function(_0x6e97e1,_0x593844,_0x3243dd,_0x2d202b,_0x31177a,_0x29ca52,_0x49cef4,_0x4ab207){return _0x6e97e1(_0x593844,_0x3243dd,_0x2d202b,_0x31177a,_0x29ca52,_0x49cef4,_0x4ab207);},'kkFAp':function(_0x2a380c,_0x38f9d3,_0x1574fc,_0x4d7a1d,_0x1684d9,_0x408143,_0x44df09,_0x3e6ed4){return _0x2a380c(_0x38f9d3,_0x1574fc,_0x4d7a1d,_0x1684d9,_0x408143,_0x44df09,_0x3e6ed4);},'qQrKL':function(_0x6eed79,_0x4c9383,_0x529c6d,_0x3c6a14,_0x3deed5,_0x789a00,_0x37289d,_0x5ad8d9){return _0x6eed79(_0x4c9383,_0x529c6d,_0x3c6a14,_0x3deed5,_0x789a00,_0x37289d,_0x5ad8d9);},'KVbyM':function(_0x16fc45,_0x21402a,_0x130b0d,_0x408fab,_0x15ed96,_0x3fcd7a,_0x563f87,_0x46422a){return _0x16fc45(_0x21402a,_0x130b0d,_0x408fab,_0x15ed96,_0x3fcd7a,_0x563f87,_0x46422a);},'GoHFv':function(_0x15cd01,_0x36f66c,_0x414ebb,_0x5bb5f0,_0x3b0da9,_0x4610b7,_0xb56f07,_0x4b14c9){return _0x15cd01(_0x36f66c,_0x414ebb,_0x5bb5f0,_0x3b0da9,_0x4610b7,_0xb56f07,_0x4b14c9);},'vvkQm':function(_0x1ad0a1,_0x2c1f8a,_0xe4ba41,_0x4b276a,_0x4e04c2,_0x37b816,_0x1d1ede,_0x3d2178){return _0x1ad0a1(_0x2c1f8a,_0xe4ba41,_0x4b276a,_0x4e04c2,_0x37b816,_0x1d1ede,_0x3d2178);},'QVDOB':function(_0x4eb403,_0x45d582,_0x3c6dcf,_0x480776,_0x40fd72,_0x4c62ef,_0xe0e632,_0x117113){return _0x4eb403(_0x45d582,_0x3c6dcf,_0x480776,_0x40fd72,_0x4c62ef,_0xe0e632,_0x117113);},'gLIMD':function(_0x2996a7,_0x599899,_0x5a81cd,_0x57424a,_0x14ddce,_0x205970,_0xe316a5,_0x3fec21){return _0x2996a7(_0x599899,_0x5a81cd,_0x57424a,_0x14ddce,_0x205970,_0xe316a5,_0x3fec21);},'Pddso':function(_0x5d126e,_0x1df514,_0x42766d,_0x38489a,_0x574f64,_0x59bd56,_0x1e8516,_0x1ac12f){return _0x5d126e(_0x1df514,_0x42766d,_0x38489a,_0x574f64,_0x59bd56,_0x1e8516,_0x1ac12f);},'ipbtP':function(_0xcc7b8c,_0x3e7625,_0x106979,_0x240a07,_0x14e986,_0x4e2753,_0x425c88,_0xae0898){return _0xcc7b8c(_0x3e7625,_0x106979,_0x240a07,_0x14e986,_0x4e2753,_0x425c88,_0xae0898);},'jtmKX':function(_0x3c7049,_0x192043,_0x7deb13,_0x349702,_0x3fd310,_0x58bb1d,_0x31eda1,_0x33e401){return _0x3c7049(_0x192043,_0x7deb13,_0x349702,_0x3fd310,_0x58bb1d,_0x31eda1,_0x33e401);},'YSUrY':function(_0x20b222,_0x623d2a,_0x571d4c,_0x878d13,_0x3cfca2,_0x160c0d,_0x4f75d8,_0x1d588b){return _0x20b222(_0x623d2a,_0x571d4c,_0x878d13,_0x3cfca2,_0x160c0d,_0x4f75d8,_0x1d588b);},'GoIHF':function(_0x289b7d,_0x485d5d,_0x520de8,_0x1605e6,_0x43377f,_0x119452,_0x20e3f0,_0x10784e){return _0x289b7d(_0x485d5d,_0x520de8,_0x1605e6,_0x43377f,_0x119452,_0x20e3f0,_0x10784e);},'inqNR':function(_0x1b4a74,_0x3b4cfb){return _0x1b4a74|_0x3b4cfb;},'ZaLwV':function(_0x5226e0,_0x24758c){return _0x5226e0+_0x24758c;},'AejmZ':function(_0x44324a,_0x496f93){return _0x44324a|_0x496f93;},'MelHu':function(_0x2debeb,_0x3ad7ff){return _0x2debeb+_0x3ad7ff;},'WXLhd':function(_0x4f254d,_0x5b315e){return _0x4f254d|_0x5b315e;},'vrDCs':function(_0x96a7da,_0x4fae8d){return _0x96a7da+_0x4fae8d;},'eVfop':'0|4|3|2|1|5','RTPdl':function(_0x25efb4,_0x556600){return _0x25efb4<_0x556600;},'GVwCl':function(_0x523fa0,_0x459a37){return _0x523fa0|_0x459a37;},'DKwAI':function(_0x5d62ec,_0x48746f){return _0x5d62ec&_0x48746f;},'DxdEd':function(_0xe47fd6,_0x454b6a){return _0xe47fd6>>>_0x454b6a;},'SURdz':function(_0x5e83c6,_0x3a98c5){return _0x5e83c6*_0x3a98c5;},'mHTWU':function(_0x1bf461,_0x2bd5ee){return _0x1bf461%_0x2bd5ee;},'IegVB':function(_0x944a79,_0x1f108a){return _0x944a79&_0x1f108a;},'gedrF':function(_0xded4ef,_0x51d268){return _0xded4ef&_0x51d268;},'BKAhZ':function(_0x1ae663,_0x2b2ee4){return _0x1ae663>>>_0x2b2ee4;},'UVLrW':function(_0x4c4ebf,_0x34853b){return _0x4c4ebf-_0x34853b;},'vCeFD':function(_0x207619,_0x50ca19){return _0x207619%_0x50ca19;},'foDut':function(_0x5ab83d,_0x18cd11){return _0x5ab83d>_0x18cd11;},'CxkmM':function(_0x184f1c,_0x4f8e69){return _0x184f1c<_0x4f8e69;},'BDxvP':function(_0x4fa76a,_0x1fa67a){return _0x4fa76a+_0x1fa67a;},'DWZRi':function(_0x19ff9f,_0x1fe0eb){return _0x19ff9f>>>_0x1fe0eb;},'ZmeVQ':function(_0x3cfb3d,_0xa0279a){return _0x3cfb3d-_0xa0279a;},'lBTeu':function(_0x53bf21,_0x8e22ad){return _0x53bf21===_0x8e22ad;},'AncZD':'XHrUU','PrQff':_0x4551a0('0x340'),'dtibs':function(_0x2aed0e,_0x524dc9){return _0x2aed0e+_0x524dc9;},'xAZhA':function(_0x18bfa2,_0x4d1dd5){return _0x18bfa2<<_0x4d1dd5;},'oAJXk':function(_0x4eb804,_0xd7cf20){return _0x4eb804+_0xd7cf20;},'YYkUL':function(_0x9b3e04,_0x22bf49){return _0x9b3e04>>>_0x22bf49;},'qOLYP':function(_0x402cdb,_0x12bec9){return _0x402cdb&_0x12bec9;},'LBIEg':function(_0x45e4e5,_0x56217f){return _0x45e4e5<<_0x56217f;},'Snxnq':function(_0x55c083,_0x26eaae){return _0x55c083>>>_0x26eaae;},'SLruJ':function(_0x308102,_0xea015a){return _0x308102+_0xea015a;},'XQqFR':function(_0x272e1a,_0x157a0a){return _0x272e1a>>>_0x157a0a;},'mUffp':function(_0x140168,_0x31b13f){return _0x140168-_0x31b13f;},'pvvgT':function(_0x4d12a5,_0x3e1b58){return _0x4d12a5%_0x3e1b58;},'zvQgM':function(_0x5e1405,_0x8e1574){return _0x5e1405/_0x8e1574;},'ijhqK':function(_0xa69e16,_0x23f2db){return _0xa69e16*_0x23f2db;},'eihJF':function(_0x2f8720,_0x41e5f9){return _0x2f8720*_0x41e5f9;},'fypSr':function(_0xe10933,_0x526b7b){return _0xe10933<<_0x526b7b;},'XdjZP':function(_0x132bad,_0x31dadf){return _0x132bad+_0x31dadf;},'ZdlTW':function(_0x3b0013,_0x1c1c1c){return _0x3b0013|_0x1c1c1c;},'QeINi':function(_0x9b17e4,_0x3df3f9){return _0x9b17e4|_0x3df3f9;},'WpEDF':function(_0x25272b,_0x2e78f0){return _0x25272b<<_0x2e78f0;},'GFtkS':function(_0x7ad032,_0x2d2142){return _0x7ad032>>>_0x2d2142;},'GWQIL':function(_0x247779,_0x2e5d2a){return _0x247779|_0x2e5d2a;},'hMQIk':function(_0x268934,_0x32639c){return _0x268934&_0x32639c;},'MBzSt':function(_0x2f4530,_0x5523b3){return _0x2f4530|_0x5523b3;},'HKYeX':function(_0x2ab1e7,_0x4d8994){return _0x2ab1e7>>>_0x4d8994;},'CKIkQ':function(_0x4a12a3,_0x58f8a9){return _0x4a12a3+_0x58f8a9;},'OJRUh':function(_0x415a9,_0x2825c5){return _0x415a9+_0x2825c5;},'pLHRZ':function(_0x1cfaa6,_0xed007e){return _0x1cfaa6&_0xed007e;},'AFsMS':function(_0x19ab98,_0x127ad8){return _0x19ab98+_0x127ad8;},'XDWDP':function(_0xa89d45,_0x6b1446){return _0xa89d45|_0x6b1446;},'EmpMk':function(_0x83b4a5,_0x476609){return _0x83b4a5-_0x476609;},'ZsZnB':function(_0x3c56be,_0x4d085a){return _0x3c56be===_0x4d085a;},'KhLIZ':_0x4551a0('0xe5'),'DQSyl':_0x4551a0('0x3d3'),'sQCib':function(_0x17e34a,_0x358904){return _0x17e34a>_0x358904;},'KVSBJ':function(_0x1d95a8,_0x5b8963){return _0x1d95a8|_0x5b8963;},'SELww':function(_0x3b0bfb,_0x4e90f6){return _0x3b0bfb*_0x4e90f6;}};function _0x270363(_0x2d698a,_0x39fb05,_0x4330c6,_0x4acab9,_0x1deac2,_0x279426,_0x26b3b0){var _0x215867=_0x4551a0,_0x3f257d={'BEnJc':function(_0x24e93b,_0x423bdf){var _0x4795a5=_0x4528;return _0x57a0de[_0x4795a5('0x43b')](_0x24e93b,_0x423bdf);}};if(_0x57a0de[_0x215867('0x199')](_0x57a0de['hkVWt'],_0x57a0de['hkVWt']))return _0x2d698a=_0x57a0de['IvAfu'](_0x57a0de['UVTwy'](_0x57a0de['UVTwy'](_0x2d698a,_0x57a0de[_0x215867('0x121')](_0x57a0de[_0x215867('0x307')](_0x39fb05,_0x4330c6),_0x57a0de[_0x215867('0x358')](~_0x39fb05,_0x4acab9))),_0x1deac2),_0x26b3b0),_0x57a0de[_0x215867('0x38d')](_0x57a0de[_0x215867('0x121')](_0x57a0de[_0x215867('0x2cb')](_0x2d698a,_0x279426),_0x57a0de[_0x215867('0x34a')](_0x2d698a,_0x57a0de[_0x215867('0x5')](0x20,_0x279426))),_0x39fb05);else{function _0x599e10(){var _0x53cba2=_0x215867;return _0x3f257d['BEnJc'](_0x25b816,_0x542fdf)[_0x53cba2('0x40e')](this);}}}function _0x1cce5c(_0x141bb5,_0x4014c8,_0x5c651a,_0x19ed35,_0x6ed6c5,_0x48b712,_0x55aa58){var _0x4403ed=_0x4551a0;if(_0x57a0de[_0x4403ed('0x235')](_0x57a0de['qdSIl'],_0x57a0de[_0x4403ed('0x46f')]))return _0x141bb5=_0x57a0de[_0x4403ed('0x311')](_0x57a0de['NEfJA'](_0x57a0de[_0x4403ed('0x413')](_0x141bb5,_0x57a0de['hedDL'](_0x57a0de[_0x4403ed('0x358')](_0x4014c8,_0x19ed35),_0x57a0de[_0x4403ed('0x358')](_0x5c651a,~_0x19ed35))),_0x6ed6c5),_0x55aa58),_0x57a0de[_0x4403ed('0x413')](_0x57a0de[_0x4403ed('0x121')](_0x57a0de[_0x4403ed('0x2cb')](_0x141bb5,_0x48b712),_0x57a0de[_0x4403ed('0x442')](_0x141bb5,_0x57a0de[_0x4403ed('0x354')](0x20,_0x48b712))),_0x4014c8);else{function _0x31b12f(){var _0x48bbf4=_0x4403ed;this[_0x48bbf4('0x373')]=_0x30a177,this[_0x48bbf4('0x1e7')]=_0x2c1af1;}}}function _0x3438f1(_0x4b1e95,_0x3f7bdd,_0x2857c3,_0x36b8f0,_0x1d17e9,_0x4f154,_0x9cad6c){var _0x2f7cbb=_0x4551a0;if(_0x57a0de[_0x2f7cbb('0x199')](_0x57a0de[_0x2f7cbb('0xed')],_0x57a0de[_0x2f7cbb('0x31b')])){function _0x4b6992(){var _0x373496=_0x2f7cbb;return this[_0x373496('0x26')](_0x4c9b78),this[_0x373496('0x26d')]();}}else return _0x4b1e95=_0x57a0de[_0x2f7cbb('0x413')](_0x57a0de[_0x2f7cbb('0x0')](_0x57a0de[_0x2f7cbb('0x0')](_0x4b1e95,_0x57a0de[_0x2f7cbb('0x19b')](_0x57a0de[_0x2f7cbb('0x19b')](_0x3f7bdd,_0x2857c3),_0x36b8f0)),_0x1d17e9),_0x9cad6c),_0x57a0de['wZVAj'](_0x57a0de[_0x2f7cbb('0x121')](_0x57a0de['EAvnb'](_0x4b1e95,_0x4f154),_0x57a0de[_0x2f7cbb('0x442')](_0x4b1e95,_0x57a0de[_0x2f7cbb('0x354')](0x20,_0x4f154))),_0x3f7bdd);}function _0x4a97ad(_0x229c4f,_0x378779,_0x4f643e,_0x169949,_0x2241c1,_0x38b998,_0x48eee4){var _0x43f858=_0x4551a0;if(_0x57a0de[_0x43f858('0x200')](_0x57a0de[_0x43f858('0x3a9')],_0x57a0de['LaGcz']))return _0x229c4f=_0x57a0de[_0x43f858('0x9e')](_0x57a0de['YCQDJ'](_0x57a0de[_0x43f858('0x168')](_0x229c4f,_0x57a0de[_0x43f858('0x207')](_0x4f643e,_0x57a0de[_0x43f858('0x121')](_0x378779,~_0x169949))),_0x2241c1),_0x48eee4),_0x57a0de[_0x43f858('0x21b')](_0x57a0de[_0x43f858('0x121')](_0x57a0de[_0x43f858('0x67')](_0x229c4f,_0x38b998),_0x57a0de[_0x43f858('0x348')](_0x229c4f,_0x57a0de[_0x43f858('0x1d')](0x20,_0x38b998))),_0x378779);else{function _0x4e4bf0(){var _0x5ca80b=_0x43f858,_0x36813f=_0x57a0de['EAvnb'](_0x24f54f['indexOf'](_0x25d765['charAt'](_0x57a0de['zZcJA'](_0x172145,0x1))),_0x57a0de[_0x5ca80b('0x1a4')](0x2,_0x57a0de[_0x5ca80b('0xd7')](_0x33558e,0x4))),_0x2cc3d1=_0x57a0de[_0x5ca80b('0x442')](_0x5c2dfc['indexOf'](_0x1b85c6[_0x5ca80b('0x40f')](_0x2b0622)),_0x57a0de[_0x5ca80b('0x392')](0x6,_0x57a0de[_0x5ca80b('0x1a4')](0x2,_0x57a0de[_0x5ca80b('0xd7')](_0x1cb6ba,0x4))));_0x151e77[_0x57a0de['IldQb'](_0x2a37ce,0x2)]|=_0x57a0de[_0x5ca80b('0x67')](_0x57a0de[_0x5ca80b('0x121')](_0x36813f,_0x2cc3d1),_0x57a0de[_0x5ca80b('0x1d')](0x18,_0x57a0de[_0x5ca80b('0x2cc')](0x8,_0x57a0de[_0x5ca80b('0x452')](_0x5a52d0,0x4)))),_0x2c59ad++;}}}for(var _0x30c5f1=CryptoJS,_0x11cc6d=_0x30c5f1[_0x4551a0('0x246')],_0x1c10f5=_0x11cc6d['WordArray'],_0x32facc=_0x11cc6d['Hasher'],_0x11cc6d=_0x30c5f1[_0x4551a0('0x329')],_0x2a001f=[],_0x39e53a=0x0;_0x57a0de[_0x4551a0('0xf')](0x40,_0x39e53a);_0x39e53a++)_0x2a001f[_0x39e53a]=_0x57a0de[_0x4551a0('0x141')](_0x57a0de[_0x4551a0('0x116')](0x100000000,_0x468300[_0x4551a0('0x12b')](_0x468300[_0x4551a0('0xd8')](_0x57a0de['AFsMS'](_0x39e53a,0x1)))),0x0);_0x11cc6d=_0x11cc6d[_0x4551a0('0x428')]=_0x32facc['extend']({'_doReset':function(){var _0x34a4c4=_0x4551a0;if(_0x57a0de['ambdW'](_0x57a0de['nLSpm'],_0x57a0de[_0x34a4c4('0x323')]))this[_0x34a4c4('0x363')]=new _0x1c10f5['init']([0x67452301,0xefcdab89,0x98badcfe,0x10325476]);else{function _0x4d931a(){var _0x213355=_0x34a4c4;return _0x57a0de[_0x213355('0x1fa')](_0x57a0de[_0x213355('0x10b')],typeof _0x1f8ae7)?_0x12038d[_0x213355('0x316')](_0xd0eaf6,this):_0x5eac91;}}},'_doProcessBlock':function(_0x1d3453,_0x158d6b){var _0x242bc2=_0x4551a0,_0x50ed12={'QhQNl':function(_0x3a21cf,_0x2a9ddc){var _0x47af73=_0x4528;return _0x57a0de[_0x47af73('0x358')](_0x3a21cf,_0x2a9ddc);},'wdiym':function(_0x988aff,_0x1009bc){var _0xeb1644=_0x4528;return _0x57a0de[_0xeb1644('0x348')](_0x988aff,_0x1009bc);},'EsUaw':function(_0x29d3fe,_0x554403){var _0x136183=_0x4528;return _0x57a0de[_0x136183('0xa0')](_0x29d3fe,_0x554403);},'YXToJ':function(_0x5b06aa,_0x4a98b4){return _0x57a0de['VVybt'](_0x5b06aa,_0x4a98b4);},'QoPIl':function(_0x415b62,_0x5161fb){var _0x483352=_0x4528;return _0x57a0de[_0x483352('0x33')](_0x415b62,_0x5161fb);},'bCeLi':function(_0x22c13a,_0x39b383){return _0x57a0de['IldQb'](_0x22c13a,_0x39b383);},'WsypA':_0x57a0de[_0x242bc2('0x382')]};if(_0x57a0de['nNrnc'](_0x57a0de['tlgIz'],_0x57a0de[_0x242bc2('0x2d5')])){function _0x551633(){var _0x135bec=_0x242bc2,_0x385d22=_0x50ed12[_0x135bec('0x228')](_0x50ed12[_0x135bec('0xec')](_0x3c01db[_0x50ed12[_0x135bec('0xec')](_0x239c62,0x2)],_0x50ed12[_0x135bec('0x100')](0x18,_0x50ed12[_0x135bec('0x333')](0x8,_0x50ed12[_0x135bec('0x84')](_0x587693,0x4)))),0xff);_0x29be5e['push'](_0x50ed12[_0x135bec('0x3df')](_0x385d22,0x4)[_0x135bec('0x1ef')](0x10)),_0x187975[_0x135bec('0x36d')](_0x50ed12[_0x135bec('0x228')](_0x385d22,0xf)[_0x135bec('0x1ef')](0x10));}}else{for(var _0x3876bc=0x0;_0x57a0de[_0x242bc2('0x23d')](0x10,_0x3876bc);_0x3876bc++){if(_0x57a0de[_0x242bc2('0x3ee')](_0x57a0de['LRwRs'],_0x57a0de['SgeDV'])){function _0x3fb85a(){var _0x11dbb4=_0x242bc2,_0x1cbfec=_0x50ed12[_0x11dbb4('0x225')][_0x11dbb4('0x2f8')]('|'),_0x2c73e1=0x0;while(!![]){switch(_0x1cbfec[_0x2c73e1++]){case'0':_0x17c366[_0x11dbb4('0x46')](_0xc31d05);continue;case'1':_0xdad2eb=_0x4b07b5[_0x11dbb4('0x1ff')][_0x11dbb4('0x1ca')](_0x3aae21,_0x5c46dd[_0x11dbb4('0x464')],_0x458be7[_0x11dbb4('0x22b')]);continue;case'2':return _0x576c41;case'3':_0x4521d6=_0x22623f[_0x11dbb4('0x276')][_0x11dbb4('0x1e')](this,_0x44699c,_0x1e236d,_0x31ec3f[_0x11dbb4('0x219')],_0x440662);continue;case'4':_0x14b703=this[_0x11dbb4('0x15c')]['extend'](_0xc86152);continue;case'5':_0x336be4['iv']=_0x4b27dc['iv'];continue;}break;}}}else{var _0x1a3ff2=_0x57a0de[_0x242bc2('0x158')](_0x158d6b,_0x3876bc),_0x4d62bc=_0x1d3453[_0x1a3ff2];_0x1d3453[_0x1a3ff2]=_0x57a0de[_0x242bc2('0x121')](_0x57a0de[_0x242bc2('0x358')](_0x57a0de['dNmIR'](_0x57a0de[_0x242bc2('0x67')](_0x4d62bc,0x8),_0x57a0de[_0x242bc2('0x230')](_0x4d62bc,0x18)),0xff00ff),_0x57a0de[_0x242bc2('0x30')](_0x57a0de['qFypi'](_0x57a0de[_0x242bc2('0x67')](_0x4d62bc,0x18),_0x57a0de[_0x242bc2('0x230')](_0x4d62bc,0x8)),0xff00ff00));}}var _0x3876bc=this['_hash']['words'],_0x1a3ff2=_0x1d3453[_0x57a0de['GCbUV'](_0x158d6b,0x0)],_0x4d62bc=_0x1d3453[_0x57a0de[_0x242bc2('0x2b8')](_0x158d6b,0x1)],_0x49a1a9=_0x1d3453[_0x57a0de[_0x242bc2('0x148')](_0x158d6b,0x2)],_0x337911=_0x1d3453[_0x57a0de[_0x242bc2('0x259')](_0x158d6b,0x3)],_0x388b0c=_0x1d3453[_0x57a0de[_0x242bc2('0x259')](_0x158d6b,0x4)],_0xa9fcc6=_0x1d3453[_0x57a0de['Bbfza'](_0x158d6b,0x5)],_0x19cd2e=_0x1d3453[_0x57a0de[_0x242bc2('0x455')](_0x158d6b,0x6)],_0x3d2de9=_0x1d3453[_0x57a0de[_0x242bc2('0x2e5')](_0x158d6b,0x7)],_0x275aa3=_0x1d3453[_0x57a0de[_0x242bc2('0x2e5')](_0x158d6b,0x8)],_0xc8e15c=_0x1d3453[_0x57a0de['ayvGW'](_0x158d6b,0x9)],_0x409579=_0x1d3453[_0x57a0de[_0x242bc2('0x2e5')](_0x158d6b,0xa)],_0x23171c=_0x1d3453[_0x57a0de[_0x242bc2('0x2e5')](_0x158d6b,0xb)],_0x50ea5a=_0x1d3453[_0x57a0de[_0x242bc2('0x3c5')](_0x158d6b,0xc)],_0x2d7b90=_0x1d3453[_0x57a0de[_0x242bc2('0x33c')](_0x158d6b,0xd)],_0x583a60=_0x1d3453[_0x57a0de[_0x242bc2('0x30d')](_0x158d6b,0xe)],_0x42d811=_0x1d3453[_0x57a0de[_0x242bc2('0x3e2')](_0x158d6b,0xf)],_0xe461fe=_0x3876bc[0x0],_0x34dad6=_0x3876bc[0x1],_0x5b3949=_0x3876bc[0x2],_0x45a993=_0x3876bc[0x3],_0xe461fe=_0x57a0de[_0x242bc2('0x2db')](_0x270363,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x1a3ff2,0x7,_0x2a001f[0x0]),_0x45a993=_0x57a0de[_0x242bc2('0x3de')](_0x270363,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x4d62bc,0xc,_0x2a001f[0x1]),_0x5b3949=_0x57a0de['YtYYA'](_0x270363,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x49a1a9,0x11,_0x2a001f[0x2]),_0x34dad6=_0x57a0de[_0x242bc2('0x3ec')](_0x270363,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x337911,0x16,_0x2a001f[0x3]),_0xe461fe=_0x57a0de['SxQIt'](_0x270363,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x388b0c,0x7,_0x2a001f[0x4]),_0x45a993=_0x57a0de[_0x242bc2('0x252')](_0x270363,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0xa9fcc6,0xc,_0x2a001f[0x5]),_0x5b3949=_0x57a0de['MJzpq'](_0x270363,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x19cd2e,0x11,_0x2a001f[0x6]),_0x34dad6=_0x57a0de['oWogc'](_0x270363,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x3d2de9,0x16,_0x2a001f[0x7]),_0xe461fe=_0x57a0de['oWogc'](_0x270363,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x275aa3,0x7,_0x2a001f[0x8]),_0x45a993=_0x57a0de[_0x242bc2('0x324')](_0x270363,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0xc8e15c,0xc,_0x2a001f[0x9]),_0x5b3949=_0x57a0de[_0x242bc2('0x324')](_0x270363,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x409579,0x11,_0x2a001f[0xa]),_0x34dad6=_0x57a0de[_0x242bc2('0x346')](_0x270363,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x23171c,0x16,_0x2a001f[0xb]),_0xe461fe=_0x57a0de[_0x242bc2('0x161')](_0x270363,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x50ea5a,0x7,_0x2a001f[0xc]),_0x45a993=_0x57a0de['XMLfF'](_0x270363,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x2d7b90,0xc,_0x2a001f[0xd]),_0x5b3949=_0x57a0de[_0x242bc2('0x175')](_0x270363,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x583a60,0x11,_0x2a001f[0xe]),_0x34dad6=_0x57a0de[_0x242bc2('0x175')](_0x270363,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x42d811,0x16,_0x2a001f[0xf]),_0xe461fe=_0x57a0de[_0x242bc2('0xf6')](_0x1cce5c,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x4d62bc,0x5,_0x2a001f[0x10]),_0x45a993=_0x57a0de[_0x242bc2('0xeb')](_0x1cce5c,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x19cd2e,0x9,_0x2a001f[0x11]),_0x5b3949=_0x57a0de[_0x242bc2('0xb0')](_0x1cce5c,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x23171c,0xe,_0x2a001f[0x12]),_0x34dad6=_0x57a0de['Whfov'](_0x1cce5c,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x1a3ff2,0x14,_0x2a001f[0x13]),_0xe461fe=_0x57a0de[_0x242bc2('0x30b')](_0x1cce5c,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0xa9fcc6,0x5,_0x2a001f[0x14]),_0x45a993=_0x57a0de[_0x242bc2('0x30b')](_0x1cce5c,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x409579,0x9,_0x2a001f[0x15]),_0x5b3949=_0x57a0de['eySri'](_0x1cce5c,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x42d811,0xe,_0x2a001f[0x16]),_0x34dad6=_0x57a0de[_0x242bc2('0x46e')](_0x1cce5c,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x388b0c,0x14,_0x2a001f[0x17]),_0xe461fe=_0x57a0de[_0x242bc2('0x46e')](_0x1cce5c,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0xc8e15c,0x5,_0x2a001f[0x18]),_0x45a993=_0x57a0de[_0x242bc2('0x46e')](_0x1cce5c,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x583a60,0x9,_0x2a001f[0x19]),_0x5b3949=_0x57a0de[_0x242bc2('0x18f')](_0x1cce5c,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x337911,0xe,_0x2a001f[0x1a]),_0x34dad6=_0x57a0de[_0x242bc2('0x18f')](_0x1cce5c,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x275aa3,0x14,_0x2a001f[0x1b]),_0xe461fe=_0x57a0de[_0x242bc2('0x270')](_0x1cce5c,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x2d7b90,0x5,_0x2a001f[0x1c]),_0x45a993=_0x57a0de['AnHor'](_0x1cce5c,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x49a1a9,0x9,_0x2a001f[0x1d]),_0x5b3949=_0x57a0de[_0x242bc2('0x3cb')](_0x1cce5c,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x3d2de9,0xe,_0x2a001f[0x1e]),_0x34dad6=_0x57a0de[_0x242bc2('0x3cb')](_0x1cce5c,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x50ea5a,0x14,_0x2a001f[0x1f]),_0xe461fe=_0x57a0de[_0x242bc2('0x3cb')](_0x3438f1,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0xa9fcc6,0x4,_0x2a001f[0x20]),_0x45a993=_0x57a0de['Qorbo'](_0x3438f1,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x275aa3,0xb,_0x2a001f[0x21]),_0x5b3949=_0x57a0de[_0x242bc2('0x466')](_0x3438f1,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x23171c,0x10,_0x2a001f[0x22]),_0x34dad6=_0x57a0de['Qorbo'](_0x3438f1,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x583a60,0x17,_0x2a001f[0x23]),_0xe461fe=_0x57a0de[_0x242bc2('0x466')](_0x3438f1,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x4d62bc,0x4,_0x2a001f[0x24]),_0x45a993=_0x57a0de[_0x242bc2('0x462')](_0x3438f1,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x388b0c,0xb,_0x2a001f[0x25]),_0x5b3949=_0x57a0de[_0x242bc2('0x181')](_0x3438f1,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x3d2de9,0x10,_0x2a001f[0x26]),_0x34dad6=_0x57a0de['wqVtV'](_0x3438f1,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x409579,0x17,_0x2a001f[0x27]),_0xe461fe=_0x57a0de[_0x242bc2('0x189')](_0x3438f1,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x2d7b90,0x4,_0x2a001f[0x28]),_0x45a993=_0x57a0de[_0x242bc2('0x189')](_0x3438f1,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x1a3ff2,0xb,_0x2a001f[0x29]),_0x5b3949=_0x57a0de[_0x242bc2('0x20e')](_0x3438f1,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x337911,0x10,_0x2a001f[0x2a]),_0x34dad6=_0x57a0de[_0x242bc2('0x20e')](_0x3438f1,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x19cd2e,0x17,_0x2a001f[0x2b]),_0xe461fe=_0x57a0de[_0x242bc2('0x31f')](_0x3438f1,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0xc8e15c,0x4,_0x2a001f[0x2c]),_0x45a993=_0x57a0de[_0x242bc2('0x15a')](_0x3438f1,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x50ea5a,0xb,_0x2a001f[0x2d]),_0x5b3949=_0x57a0de[_0x242bc2('0x15a')](_0x3438f1,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x42d811,0x10,_0x2a001f[0x2e]),_0x34dad6=_0x57a0de[_0x242bc2('0x15a')](_0x3438f1,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x49a1a9,0x17,_0x2a001f[0x2f]),_0xe461fe=_0x57a0de[_0x242bc2('0xbd')](_0x4a97ad,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x1a3ff2,0x6,_0x2a001f[0x30]),_0x45a993=_0x57a0de[_0x242bc2('0xe2')](_0x4a97ad,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x3d2de9,0xa,_0x2a001f[0x31]),_0x5b3949=_0x57a0de[_0x242bc2('0xe2')](_0x4a97ad,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x583a60,0xf,_0x2a001f[0x32]),_0x34dad6=_0x57a0de['KVbyM'](_0x4a97ad,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0xa9fcc6,0x15,_0x2a001f[0x33]),_0xe461fe=_0x57a0de[_0x242bc2('0x195')](_0x4a97ad,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x50ea5a,0x6,_0x2a001f[0x34]),_0x45a993=_0x57a0de['GoHFv'](_0x4a97ad,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x337911,0xa,_0x2a001f[0x35]),_0x5b3949=_0x57a0de[_0x242bc2('0x150')](_0x4a97ad,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x409579,0xf,_0x2a001f[0x36]),_0x34dad6=_0x57a0de[_0x242bc2('0x460')](_0x4a97ad,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x4d62bc,0x15,_0x2a001f[0x37]),_0xe461fe=_0x57a0de[_0x242bc2('0xb4')](_0x4a97ad,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x275aa3,0x6,_0x2a001f[0x38]),_0x45a993=_0x57a0de['Pddso'](_0x4a97ad,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x42d811,0xa,_0x2a001f[0x39]),_0x5b3949=_0x57a0de[_0x242bc2('0x27e')](_0x4a97ad,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x19cd2e,0xf,_0x2a001f[0x3a]),_0x34dad6=_0x57a0de[_0x242bc2('0x26f')](_0x4a97ad,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0x2d7b90,0x15,_0x2a001f[0x3b]),_0xe461fe=_0x57a0de[_0x242bc2('0x320')](_0x4a97ad,_0xe461fe,_0x34dad6,_0x5b3949,_0x45a993,_0x388b0c,0x6,_0x2a001f[0x3c]),_0x45a993=_0x57a0de['YSUrY'](_0x4a97ad,_0x45a993,_0xe461fe,_0x34dad6,_0x5b3949,_0x23171c,0xa,_0x2a001f[0x3d]),_0x5b3949=_0x57a0de[_0x242bc2('0x339')](_0x4a97ad,_0x5b3949,_0x45a993,_0xe461fe,_0x34dad6,_0x49a1a9,0xf,_0x2a001f[0x3e]),_0x34dad6=_0x57a0de[_0x242bc2('0x271')](_0x4a97ad,_0x34dad6,_0x5b3949,_0x45a993,_0xe461fe,_0xc8e15c,0x15,_0x2a001f[0x3f]);_0x3876bc[0x0]=_0x57a0de[_0x242bc2('0x376')](_0x57a0de['ZaLwV'](_0x3876bc[0x0],_0xe461fe),0x0),_0x3876bc[0x1]=_0x57a0de[_0x242bc2('0x2ad')](_0x57a0de[_0x242bc2('0x54')](_0x3876bc[0x1],_0x34dad6),0x0),_0x3876bc[0x2]=_0x57a0de[_0x242bc2('0x306')](_0x57a0de[_0x242bc2('0x54')](_0x3876bc[0x2],_0x5b3949),0x0),_0x3876bc[0x3]=_0x57a0de[_0x242bc2('0x306')](_0x57a0de['vrDCs'](_0x3876bc[0x3],_0x45a993),0x0);}},'_doFinalize':function(){var _0x3a7612=_0x4551a0,_0x1d414e={'PpEoS':_0x57a0de[_0x3a7612('0x22c')],'XLgBm':function(_0x2b3e49,_0xce9bcd){var _0xda7a49=_0x3a7612;return _0x57a0de[_0xda7a49('0x33')](_0x2b3e49,_0xce9bcd);},'TfIOO':function(_0x27b1dd,_0x185ab4){return _0x57a0de['RTPdl'](_0x27b1dd,_0x185ab4);},'HtXCc':function(_0xf429c1,_0x397279){var _0x1d09c3=_0x3a7612;return _0x57a0de[_0x1d09c3('0x2e8')](_0xf429c1,_0x397279);},'nWSek':function(_0x5d7704,_0x3b97f3){return _0x57a0de['EAvnb'](_0x5d7704,_0x3b97f3);},'uGqUo':function(_0x4752de,_0x3f5b27){var _0x42ea32=_0x3a7612;return _0x57a0de[_0x42ea32('0x43e')](_0x4752de,_0x3f5b27);},'zYSLK':function(_0x52b09f,_0x4ee936){var _0x465c98=_0x3a7612;return _0x57a0de[_0x465c98('0x230')](_0x52b09f,_0x4ee936);},'nqYTj':function(_0x3aee53,_0x57259d){return _0x57a0de['DxdEd'](_0x3aee53,_0x57259d);},'CqruY':function(_0x30e2b2,_0x5a6f38){var _0x2650e3=_0x3a7612;return _0x57a0de[_0x2650e3('0xa0')](_0x30e2b2,_0x5a6f38);},'qemeq':function(_0x304358,_0x59538d){var _0x2301de=_0x3a7612;return _0x57a0de[_0x2301de('0x9d')](_0x304358,_0x59538d);},'EXgmb':function(_0x437678,_0x328a1e){var _0x16166b=_0x3a7612;return _0x57a0de[_0x16166b('0x2f7')](_0x437678,_0x328a1e);},'roCCs':function(_0x2729e6,_0x1ad8d5){var _0x1c4393=_0x3a7612;return _0x57a0de[_0x1c4393('0x42a')](_0x2729e6,_0x1ad8d5);},'Ogdzi':function(_0x49a014,_0x1db8c3){return _0x57a0de['DxdEd'](_0x49a014,_0x1db8c3);},'vtmQF':function(_0x15b2e2,_0x3e19f7){return _0x57a0de['vrDCs'](_0x15b2e2,_0x3e19f7);},'fvsJk':function(_0x597794,_0x5bca11){var _0x5b22ec=_0x3a7612;return _0x57a0de[_0x5b22ec('0x9d')](_0x597794,_0x5bca11);},'GCuNt':function(_0x5a5b40,_0x24a4d7){var _0x9a5f1f=_0x3a7612;return _0x57a0de[_0x9a5f1f('0x3c')](_0x5a5b40,_0x24a4d7);},'iGDpA':function(_0x1203a0,_0x403161){return _0x57a0de['BKAhZ'](_0x1203a0,_0x403161);},'yLTuj':function(_0x335eb8,_0x5e32a9){var _0x4a5f81=_0x3a7612;return _0x57a0de[_0x4a5f81('0x282')](_0x335eb8,_0x5e32a9);},'bxqZe':function(_0x2476bf,_0x2590bf){return _0x57a0de['SURdz'](_0x2476bf,_0x2590bf);},'ZNbhr':function(_0x74a2a8,_0x57d72a){var _0x507625=_0x3a7612;return _0x57a0de[_0x507625('0x27d')](_0x74a2a8,_0x57d72a);},'dVIKj':function(_0x4432c8,_0x49f393){var _0x247274=_0x3a7612;return _0x57a0de[_0x247274('0x3c8')](_0x4432c8,_0x49f393);},'DFNbh':function(_0x42dcc0,_0x965817){return _0x57a0de['foDut'](_0x42dcc0,_0x965817);},'UwjxI':function(_0x3c097,_0x3c59e0){return _0x57a0de['CxkmM'](_0x3c097,_0x3c59e0);},'VScLT':function(_0xee2bf2,_0x546ee0){var _0x31892c=_0x3a7612;return _0x57a0de[_0x31892c('0x263')](_0xee2bf2,_0x546ee0);},'FBglp':function(_0x1f0240,_0x4016b1){return _0x57a0de['DWZRi'](_0x1f0240,_0x4016b1);},'fdydx':function(_0x5df503,_0x45e5c8){var _0x13d858=_0x3a7612;return _0x57a0de[_0x13d858('0x9d')](_0x5df503,_0x45e5c8);},'foJlg':function(_0x469f69,_0x4536a7){var _0x59cb5a=_0x3a7612;return _0x57a0de[_0x59cb5a('0x1f3')](_0x469f69,_0x4536a7);}};if(_0x57a0de[_0x3a7612('0x1b3')](_0x57a0de[_0x3a7612('0x426')],_0x57a0de[_0x3a7612('0x426')])){var _0x402937=_0x57a0de[_0x3a7612('0x33b')][_0x3a7612('0x2f8')]('|'),_0x4ec422=0x0;while(!![]){switch(_0x402937[_0x4ec422++]){case'0':_0x37d273[_0x57a0de[_0x3a7612('0x29')](_0x57a0de[_0x3a7612('0x238')](_0x57a0de[_0x3a7612('0x1fe')](_0x57a0de[_0x3a7612('0xfb')](_0x3735c3,0x40),0x9),0x4),0xe)]=_0x57a0de[_0x3a7612('0x2e8')](_0x57a0de[_0x3a7612('0x3c')](_0x57a0de[_0x3a7612('0x2e8')](_0x57a0de[_0x3a7612('0x238')](_0x56777e,0x8),_0x57a0de[_0x3a7612('0x439')](_0x56777e,0x18)),0xff00ff),_0x57a0de[_0x3a7612('0x90')](_0x57a0de['GVwCl'](_0x57a0de[_0x3a7612('0x1b5')](_0x56777e,0x18),_0x57a0de['Snxnq'](_0x56777e,0x8)),0xff00ff00));continue;case'1':this[_0x3a7612('0x26d')]();continue;case'2':_0x2adc44=this[_0x3a7612('0x363')];continue;case'3':_0x2adc44[_0x3a7612('0xbe')]=_0x57a0de[_0x3a7612('0x9d')](0x4,_0x57a0de['SLruJ'](_0x37d273['length'],0x1));continue;case'4':_0x37d273[_0x57a0de['XQqFR'](_0x3735c3,0x5)]|=_0x57a0de['LBIEg'](0x80,_0x57a0de['mUffp'](0x18,_0x57a0de['pvvgT'](_0x3735c3,0x20)));continue;case'5':_0x37d273=_0x2adc44[_0x3a7612('0x431')];continue;case'6':var _0x21144f=_0x468300[_0x3a7612('0x3f6')](_0x57a0de[_0x3a7612('0x13d')](_0x56777e,0x100000000));continue;case'7':return _0x2adc44;case'8':var _0x2adc44=this[_0x3a7612('0xe8')],_0x37d273=_0x2adc44['words'],_0x56777e=_0x57a0de[_0x3a7612('0x1dd')](0x8,this['_nDataBytes']),_0x3735c3=_0x57a0de[_0x3a7612('0x25c')](0x8,_0x2adc44[_0x3a7612('0xbe')]);continue;case'9':_0x37d273[_0x57a0de['SLruJ'](_0x57a0de[_0x3a7612('0x317')](_0x57a0de[_0x3a7612('0x1d1')](_0x57a0de[_0x3a7612('0x81')](_0x3735c3,0x40),0x9),0x4),0xf)]=_0x57a0de[_0x3a7612('0x2e8')](_0x57a0de[_0x3a7612('0x90')](_0x57a0de['ZdlTW'](_0x57a0de[_0x3a7612('0x317')](_0x21144f,0x8),_0x57a0de[_0x3a7612('0x1d1')](_0x21144f,0x18)),0xff00ff),_0x57a0de[_0x3a7612('0x90')](_0x57a0de[_0x3a7612('0x3e')](_0x57a0de[_0x3a7612('0x209')](_0x21144f,0x18),_0x57a0de[_0x3a7612('0x80')](_0x21144f,0x8)),0xff00ff00));continue;case'10':for(_0x56777e=0x0;_0x57a0de[_0x3a7612('0x19d')](0x4,_0x56777e);_0x56777e++)_0x3735c3=_0x37d273[_0x56777e],_0x37d273[_0x56777e]=_0x57a0de[_0x3a7612('0x45')](_0x57a0de[_0x3a7612('0x90')](_0x57a0de[_0x3a7612('0x45')](_0x57a0de['WpEDF'](_0x3735c3,0x8),_0x57a0de[_0x3a7612('0x80')](_0x3735c3,0x18)),0xff00ff),_0x57a0de[_0x3a7612('0x345')](_0x57a0de[_0x3a7612('0x296')](_0x57a0de[_0x3a7612('0x209')](_0x3735c3,0x18),_0x57a0de[_0x3a7612('0x312')](_0x3735c3,0x8)),0xff00ff00));continue;}break;}}else{function _0x571d2e(){var _0x2f3b83=_0x3a7612,_0x1c0ba3=_0x1d414e[_0x2f3b83('0x191')][_0x2f3b83('0x2f8')]('|'),_0x4e8915=0x0;while(!![]){switch(_0x1c0ba3[_0x4e8915++]){case'0':var _0x3486ee=_0x3d2766['words'],_0x586ee1=_0x5a9c8b['sigBytes'],_0x445af5=this[_0x2f3b83('0x21d')];continue;case'1':if(_0x3486ee=_0x445af5[_0x2f3b83('0x40f')](0x40))for(;_0x1d414e[_0x2f3b83('0x154')](_0x252d93[_0x2f3b83('0x47d')],0x4);)_0x31e1b7[_0x2f3b83('0x36d')](_0x3486ee);continue;case'2':for(var _0x1b5667=0x0;_0x1d414e[_0x2f3b83('0x43')](_0x1b5667,_0x586ee1);_0x1b5667+=0x3)for(var _0x1dbf46=_0x1d414e[_0x2f3b83('0x485')](_0x1d414e[_0x2f3b83('0x485')](_0x1d414e[_0x2f3b83('0x256')](_0x1d414e['uGqUo'](_0x1d414e[_0x2f3b83('0x4d')](_0x3486ee[_0x1d414e[_0x2f3b83('0x164')](_0x1b5667,0x2)],_0x1d414e[_0x2f3b83('0x118')](0x18,_0x1d414e[_0x2f3b83('0xa2')](0x8,_0x1d414e[_0x2f3b83('0x1c3')](_0x1b5667,0x4)))),0xff),0x10),_0x1d414e[_0x2f3b83('0x256')](_0x1d414e[_0x2f3b83('0x342')](_0x1d414e['Ogdzi'](_0x3486ee[_0x1d414e[_0x2f3b83('0x29a')](_0x1d414e['vtmQF'](_0x1b5667,0x1),0x2)],_0x1d414e[_0x2f3b83('0x118')](0x18,_0x1d414e[_0x2f3b83('0xcb')](0x8,_0x1d414e['EXgmb'](_0x1d414e[_0x2f3b83('0xa6')](_0x1b5667,0x1),0x4)))),0xff),0x8)),_0x1d414e['GCuNt'](_0x1d414e[_0x2f3b83('0x39c')](_0x3486ee[_0x1d414e['iGDpA'](_0x1d414e[_0x2f3b83('0xa6')](_0x1b5667,0x2),0x2)],_0x1d414e[_0x2f3b83('0x39a')](0x18,_0x1d414e[_0x2f3b83('0x2fc')](0x8,_0x1d414e[_0x2f3b83('0x37')](_0x1d414e[_0x2f3b83('0x3fd')](_0x1b5667,0x2),0x4)))),0xff)),_0x1f49d3=0x0;_0x1d414e[_0x2f3b83('0x11d')](0x4,_0x1f49d3)&&_0x1d414e[_0x2f3b83('0x9f')](_0x1d414e[_0x2f3b83('0x27c')](_0x1b5667,_0x1d414e[_0x2f3b83('0x2fc')](0.75,_0x1f49d3)),_0x586ee1);_0x1f49d3++)_0xa3f887[_0x2f3b83('0x36d')](_0x445af5[_0x2f3b83('0x40f')](_0x1d414e[_0x2f3b83('0xc9')](_0x1d414e['FBglp'](_0x1dbf46,_0x1d414e[_0x2f3b83('0x4e')](0x6,_0x1d414e[_0x2f3b83('0xaf')](0x3,_0x1f49d3))),0x3f)));continue;case'3':_0x57bb34=[];continue;case'4':_0x19a8e7[_0x2f3b83('0x2b1')]();continue;case'5':return _0x267519[_0x2f3b83('0xcd')]('');}break;}}}},'clone':function(){var _0x4db38e=_0x4551a0;if(_0x57a0de[_0x4db38e('0x289')](_0x57a0de[_0x4db38e('0x2f6')],_0x57a0de[_0x4db38e('0x1ee')])){function _0x1ebbf1(){var _0x2f9881=_0x4db38e;return _0x4f36db=_0x57a0de['XdjZP'](_0x57a0de['CKIkQ'](_0x57a0de['OJRUh'](_0x156115,_0x57a0de['MBzSt'](_0x57a0de[_0x2f9881('0x1d6')](_0x54c4d9,_0x8e961a),_0x57a0de[_0x2f9881('0x1d6')](_0x271af8,~_0x5d9460))),_0x5d9184),_0x4ff23b),_0x57a0de[_0x2f9881('0x3dc')](_0x57a0de[_0x2f9881('0x20f')](_0x57a0de[_0x2f9881('0x209')](_0xf78ec3,_0x8baf1b),_0x57a0de[_0x2f9881('0x312')](_0x1db549,_0x57a0de[_0x2f9881('0x124')](0x20,_0x4bce38))),_0x3b3924);}}else{var _0x531ebe=_0x32facc[_0x4db38e('0x31a')][_0x4db38e('0x1e')](this);return _0x531ebe[_0x4db38e('0x363')]=this['_hash'][_0x4db38e('0x31a')](),_0x531ebe;}}}),_0x30c5f1[_0x4551a0('0x428')]=_0x32facc[_0x4551a0('0x294')](_0x11cc6d),_0x30c5f1['HmacMD5']=_0x32facc['_createHmacHelper'](_0x11cc6d);}(Math),function(){var _0x3a8158=_0x4528,_0x2b8140={'HWWaQ':function(_0x30fe57,_0x3a4fdc){return _0x30fe57<_0x3a4fdc;},'vfzjm':function(_0x1d2405,_0x658543){return _0x1d2405===_0x658543;},'eKdai':'MdGgl','FlaUJ':function(_0x55eb55,_0x4c79b3){return _0x55eb55+_0x4c79b3;},'CqoiT':_0x3a8158('0x371'),'UMVeK':function(_0x3062d4,_0x8ec748){return _0x3062d4*_0x8ec748;},'CIHuH':function(_0x5a8141,_0x2815a6){return _0x5a8141+_0x2815a6;},'BoJDX':function(_0x17b8e4,_0x2c726b){return _0x17b8e4===_0x2c726b;},'ughgB':_0x3a8158('0x2d1'),'CSEbc':function(_0x52967d,_0x455b06){return _0x52967d<_0x455b06;},'hgJoO':function(_0x1d343e,_0x319c54){return _0x1d343e!==_0x319c54;},'pZjAe':_0x3a8158('0x474'),'qUxHR':_0x3a8158('0x3ab'),'Rroly':'0|4|2|1|3','GyaKG':function(_0xbfbbda,_0x46739d){return _0xbfbbda*_0x46739d;},'LjIbH':function(_0x13af3c,_0x4c016e){return _0x13af3c<_0x4c016e;},'lrFNg':function(_0x23da8b,_0x2503e7){return _0x23da8b>>>_0x2503e7;},'uzOYR':function(_0x2a7bd0,_0x2d1cc9){return _0x2a7bd0<<_0x2d1cc9;},'gubdC':function(_0x57149e,_0x51743c,_0x4369ef){return _0x57149e(_0x51743c,_0x4369ef);},'UttMk':function(_0x302b29,_0xd21d7){return _0x302b29-_0xd21d7;},'tcLVd':function(_0xac6206,_0xe225e6){return _0xac6206*_0xe225e6;},'ppCYB':function(_0xa7610f,_0x242970){return _0xa7610f%_0x242970;},'cCoOB':function(_0x131c99,_0x2b3d42){return _0x131c99/_0x2b3d42;},'MaPtb':function(_0x31ba99,_0x29f592){return _0x31ba99===_0x29f592;},'krINx':'JgDuE'},_0x5801d9=CryptoJS,_0x57ad2d=_0x5801d9[_0x3a8158('0x246')],_0x4cd5ac=_0x57ad2d['Base'],_0x466b9b=_0x57ad2d['WordArray'],_0x57ad2d=_0x5801d9[_0x3a8158('0x329')],_0x4e7305=_0x57ad2d[_0x3a8158('0x40b')]=_0x4cd5ac[_0x3a8158('0x3ad')]({'cfg':_0x4cd5ac[_0x3a8158('0x3ad')]({'keySize':0x4,'hasher':_0x57ad2d['MD5'],'iterations':0x1}),'init':function(_0x53972d){var _0x279396=_0x3a8158;if(_0x2b8140['vfzjm'](_0x2b8140[_0x279396('0x258')],_0x2b8140[_0x279396('0x258')]))this[_0x279396('0x15c')]=this[_0x279396('0x15c')]['extend'](_0x53972d);else{function _0x1c4dac(){var _0x49960a=_0x279396;for(var _0x2b2eb2=0x0;_0x2b8140[_0x49960a('0x217')](_0x2b2eb2,_0x112468);_0x2b2eb2+=_0x4f53b0)this['_doProcessBlock'](_0x39aa53,_0x2b2eb2);_0x2b2eb2=_0x175e91[_0x49960a('0xd1')](0x0,_0x4324f2),_0x326c35['sigBytes']-=_0xb3aa6b;}}},'compute':function(_0x57ddbe,_0xa71c23){var _0x411f94=_0x3a8158,_0x44eedc={'imjNp':_0x2b8140[_0x411f94('0x1cb')],'mCKBi':function(_0x4ab89d,_0x895ec2){var _0x5944f7=_0x411f94;return _0x2b8140[_0x5944f7('0xc3')](_0x4ab89d,_0x895ec2);},'lWxAJ':function(_0x27c355,_0x36e3d5){var _0x57d9f1=_0x411f94;return _0x2b8140[_0x57d9f1('0xc3')](_0x27c355,_0x36e3d5);},'gfWAn':function(_0x16b256,_0x1b9bd6){var _0x91cd56=_0x411f94;return _0x2b8140[_0x91cd56('0x20a')](_0x16b256,_0x1b9bd6);}};if(_0x2b8140[_0x411f94('0x33e')](_0x2b8140['ughgB'],_0x2b8140[_0x411f94('0x1e9')])){for(var _0x596aba=this[_0x411f94('0x15c')],_0x58c62c=_0x596aba[_0x411f94('0x2ed')]['create'](),_0xca1446=_0x466b9b[_0x411f94('0x286')](),_0x2ff122=_0xca1446[_0x411f94('0x431')],_0x2fc629=_0x596aba[_0x411f94('0x464')],_0x596aba=_0x596aba[_0x411f94('0x3cc')];_0x2b8140[_0x411f94('0x10c')](_0x2ff122[_0x411f94('0x47d')],_0x2fc629);){if(_0x2b8140[_0x411f94('0x4c')](_0x2b8140['pZjAe'],_0x2b8140[_0x411f94('0x3a')])){var _0x6b57e2=_0x2b8140[_0x411f94('0x2bb')]['split']('|'),_0x13b558=0x0;while(!![]){switch(_0x6b57e2[_0x13b558++]){case'0':_0x29b0a4&&_0x58c62c[_0x411f94('0x3f5')](_0x29b0a4);continue;case'1':for(var _0xf9de62=0x1;_0x2b8140[_0x411f94('0x10c')](_0xf9de62,_0x596aba);_0xf9de62++)_0x29b0a4=_0x58c62c[_0x411f94('0x68')](_0x29b0a4),_0x58c62c[_0x411f94('0xbf')]();continue;case'2':_0x58c62c[_0x411f94('0xbf')]();continue;case'3':_0xca1446[_0x411f94('0x3b2')](_0x29b0a4);continue;case'4':var _0x29b0a4=_0x58c62c['update'](_0x57ddbe)[_0x411f94('0x68')](_0xa71c23);continue;}break;}}else{function _0x3cddc7(){var _0x18b3aa=_0x411f94,_0x50cac0=this[_0x18b3aa('0x373')],_0x3930ab=_0x50cac0['blockSize'];_0x12d1c6[_0x18b3aa('0x1e')](this,_0x3ed62d,_0x706c5f,_0x3930ab),_0x50cac0[_0x18b3aa('0x26a')](_0x5054a9,_0x4619b5),this[_0x18b3aa('0x1f6')]=_0x1a6b08[_0x18b3aa('0x408')](_0x3e5fd8,_0x2b8140['FlaUJ'](_0x1194a0,_0x3930ab));}}}return _0xca1446['sigBytes']=_0x2b8140[_0x411f94('0x3fb')](0x4,_0x2fc629),_0xca1446;}else{function _0x423b0e(){var _0x2237c5=_0x411f94,_0x37628c=_0x44eedc[_0x2237c5('0x14d')]['split']('|'),_0x1ab95=0x0;while(!![]){switch(_0x37628c[_0x1ab95++]){case'0':_0x25e807[_0x2237c5('0xbe')]=_0x44eedc[_0x2237c5('0x1a8')](0x4,_0x1dff4b);continue;case'1':return _0x3bbe21[_0x2237c5('0x286')]({'key':_0x37426a,'iv':_0x3cc230,'salt':_0x156385});case'2':_0x171d4d||(_0xbd7859=_0x35ec86[_0x2237c5('0x7f')](0x8));continue;case'3':_0xcbe2a6=_0x252854[_0x2237c5('0x286')](_0x2d3963[_0x2237c5('0x431')][_0x2237c5('0x408')](_0x50ff06),_0x44eedc[_0x2237c5('0x337')](0x4,_0x5e1740));continue;case'4':_0x5853bd=_0x3db2f2['create']({'keySize':_0x44eedc['gfWAn'](_0x317b8,_0x273d1c)})[_0x2237c5('0x3a7')](_0x1cea20,_0x4c53b5);continue;}break;}}}}});_0x5801d9[_0x3a8158('0x40b')]=function(_0x54aecf,_0x4b7dd8,_0x671e22){var _0x133f7a=_0x3a8158,_0xad3718={'XcwWQ':function(_0x400cf2,_0xee7fd3){var _0x234983=_0x4528;return _0x2b8140[_0x234983('0x34b')](_0x400cf2,_0xee7fd3);},'bJQEC':function(_0x2f8427,_0x5e2a56){var _0x156325=_0x4528;return _0x2b8140[_0x156325('0x218')](_0x2f8427,_0x5e2a56);},'LXqTQ':function(_0xffa460,_0x25fd7b){var _0x48d75b=_0x4528;return _0x2b8140[_0x48d75b('0x1a7')](_0xffa460,_0x25fd7b);},'gRfVz':function(_0x3f7834,_0x1af67a,_0x3eaadd){var _0x240721=_0x4528;return _0x2b8140[_0x240721('0x5e')](_0x3f7834,_0x1af67a,_0x3eaadd);},'jlsTc':function(_0x33a57e,_0x555515){return _0x2b8140['UttMk'](_0x33a57e,_0x555515);},'CzraY':function(_0x59376a,_0x2c42d8){var _0x3e3143=_0x4528;return _0x2b8140[_0x3e3143('0x2d8')](_0x59376a,_0x2c42d8);},'qpEao':function(_0x30033e,_0x1bbf83){var _0x5703b7=_0x4528;return _0x2b8140[_0x5703b7('0x157')](_0x30033e,_0x1bbf83);},'ysqlU':function(_0x2c0e61,_0x313e2c){return _0x2b8140['cCoOB'](_0x2c0e61,_0x313e2c);}};if(_0x2b8140[_0x133f7a('0x171')](_0x2b8140[_0x133f7a('0x23b')],_0x2b8140[_0x133f7a('0x23b')]))return _0x4e7305[_0x133f7a('0x286')](_0x671e22)[_0x133f7a('0x3a7')](_0x54aecf,_0x4b7dd8);else{function _0x31e8b9(){var _0x4ab03a=_0x133f7a;for(var _0x352b90=_0x2644e2['length'],_0x5826a7=[],_0x2c4db3=0x0;_0xad3718[_0x4ab03a('0x44f')](_0x2c4db3,_0x352b90);_0x2c4db3+=0x2)_0x5826a7[_0xad3718[_0x4ab03a('0x233')](_0x2c4db3,0x3)]|=_0xad3718[_0x4ab03a('0x186')](_0xad3718[_0x4ab03a('0x2b3')](_0x7f1c82,_0x14af5a[_0x4ab03a('0xe3')](_0x2c4db3,0x2),0x10),_0xad3718[_0x4ab03a('0x9')](0x18,_0xad3718['CzraY'](0x4,_0xad3718[_0x4ab03a('0x21c')](_0x2c4db3,0x8))));return new _0x21ec90['init'](_0x5826a7,_0xad3718['ysqlU'](_0x352b90,0x2));}}};}(),CryptoJS['lib'][_0xe45236('0x2e3')]||function(_0x51792d){var _0x2be4df=_0xe45236,_0x25416c={'mHLEH':function(_0x508127,_0x328f7f){return _0x508127!==_0x328f7f;},'VzQfE':_0x2be4df('0x285'),'kyqRt':_0x2be4df('0x386'),'XkskD':function(_0x5de78a,_0x288d53){return _0x5de78a!==_0x288d53;},'kMUck':_0x2be4df('0x2ee'),'nqkFw':function(_0x28fb9c,_0x3749ab){return _0x28fb9c<_0x3749ab;},'MzqcH':'1|2|3|0|4','SzOAC':function(_0x4ddf8d,_0x51591b){return _0x4ddf8d*_0x51591b;},'DQPkc':_0x2be4df('0x229'),'KKhNE':_0x2be4df('0xe4'),'etmEn':function(_0x33fc68,_0xb58218){return _0x33fc68+_0xb58218;},'DbfFF':function(_0x251c90,_0x48bacc){return _0x251c90|_0x48bacc;},'rIjps':function(_0x2b4819,_0x24ce80){return _0x2b4819&_0x24ce80;},'aCLuP':function(_0x1a8526,_0x5bafc0){return _0x1a8526&_0x5bafc0;},'AJIbn':function(_0x34bde6,_0x46c2a3){return _0x34bde6+_0x46c2a3;},'YWiHx':function(_0x2851d9,_0x3593f1){return _0x2851d9<<_0x3593f1;},'sXlZy':function(_0x2e1176,_0x26854a){return _0x2e1176>>>_0x26854a;},'gUQlW':function(_0x4c0e04,_0x2ba0e5){return _0x4c0e04-_0x2ba0e5;},'YlysY':function(_0x542b60,_0x3df91c){return _0x542b60===_0x3df91c;},'bvpSG':_0x2be4df('0x1c4'),'lJmGP':_0x2be4df('0x47e'),'nuJDb':function(_0x1882d3,_0x54f7aa){return _0x1882d3^_0x54f7aa;},'UZaor':function(_0x84f610,_0x55d848){return _0x84f610+_0x55d848;},'NMPBg':function(_0x1c424a,_0x5cdad2){return _0x1c424a<<_0x5cdad2;},'pCZFq':_0x2be4df('0x31c'),'MhWNb':function(_0x4dc02b,_0x277ba8){return _0x4dc02b-_0x277ba8;},'ygoaM':function(_0x3d0468,_0x279221){return _0x3d0468%_0x279221;},'YEJBo':function(_0x47dadc,_0x1db4d1){return _0x47dadc/_0x1db4d1;},'WTsXj':'DSltX','rTlmb':_0x2be4df('0x6c'),'soAjx':_0x2be4df('0x3d0'),'hnntr':function(_0x1822ac,_0x5f2957){return _0x1822ac==_0x5f2957;},'PAkMF':_0x2be4df('0xb8'),'aJOTn':_0x2be4df('0x39d'),'DoZhJ':function(_0x3e0fff,_0x285400){return _0x3e0fff==_0x285400;},'jSKoD':_0x2be4df('0x7a'),'CJSwo':'PRcHz','XUfju':_0x2be4df('0x17c'),'hYavd':function(_0x427cdf,_0x1b53a5){return _0x427cdf+_0x1b53a5;},'zhDlf':function(_0xe23b6d,_0x59b11f){return _0xe23b6d^_0x59b11f;},'FrPGS':function(_0x4edf21,_0x4ef6ff){return _0x4edf21|_0x4ef6ff;},'XqQgi':function(_0x1a4b0b,_0x259397){return _0x1a4b0b<<_0x259397;},'JUlqw':function(_0x1ac3b4,_0x326ab1){return _0x1ac3b4-_0x326ab1;},'RLvYe':_0x2be4df('0xd2'),'iTsdB':function(_0x3fce6a,_0x54cbb0){return _0x3fce6a<_0x54cbb0;},'QDKHj':function(_0x43ff7f,_0x10980c){return _0x43ff7f+_0x10980c;},'bnZRb':_0x2be4df('0x146'),'XrQmM':function(_0x1b0d96,_0x5c8c49){return _0x1b0d96^_0x5c8c49;},'ioEcw':function(_0x1c61a4,_0x198551){return _0x1c61a4<<_0x198551;},'xxybB':function(_0x13e37b,_0x991c78){return _0x13e37b>>>_0x991c78;},'psjjq':function(_0xd798b9,_0x42b961){return _0xd798b9<<_0x42b961;},'ahYWg':function(_0x57ab35,_0x103c48){return _0x57ab35&_0x103c48;},'pzuVE':function(_0x59c660,_0x5ba9e3){return _0x59c660>>>_0x5ba9e3;},'stvGE':function(_0x27ead6,_0x476bca){return _0x27ead6<<_0x476bca;},'wGioH':function(_0x18c4c9,_0x1b0e30){return _0x18c4c9^_0x1b0e30;},'QZVoQ':function(_0x79a2ab,_0x36e9eb){return _0x79a2ab<<_0x36e9eb;},'ndrRK':function(_0x9339eb,_0x3292dd){return _0x9339eb>>>_0x3292dd;},'Oakte':function(_0x5f1e68,_0x543d0f){return _0x5f1e68<<_0x543d0f;},'zMUYC':function(_0x5a20b6,_0x2dd1e7){return _0x5a20b6&_0x2dd1e7;},'LPcsf':function(_0x4f401c,_0x2deab7){return _0x4f401c|_0x2deab7;},'oZZfC':function(_0x130a45,_0x5b5ee6){return _0x130a45|_0x5b5ee6;},'iEUHd':function(_0x174f0e,_0x5c3ddf){return _0x174f0e<<_0x5c3ddf;},'vRPpv':function(_0x494e9b,_0x4980ee){return _0x494e9b>>>_0x4980ee;},'PSVQV':function(_0x418544,_0x3d46ef){return _0x418544&_0x3d46ef;},'OFZwQ':function(_0x4b099b,_0x2e3182){return _0x4b099b<<_0x2e3182;},'XMOcF':function(_0x1a3559,_0x634184){return _0x1a3559&_0x634184;},'oiTrD':function(_0x154f0d,_0x18ade1){return _0x154f0d+_0x18ade1;},'zMech':function(_0x4a9bca,_0x264452){return _0x4a9bca^_0x264452;},'EfznE':function(_0x2e3959,_0x465226){return _0x2e3959+_0x465226;},'ntFIt':function(_0x41c2b2,_0x1c1436){return _0x41c2b2^_0x1c1436;},'loTJM':function(_0x302777,_0x5b3ef9){return _0x302777+_0x5b3ef9;},'tgdxd':function(_0x353c25,_0x3e1433){return _0x353c25^_0x3e1433;},'iiFzm':function(_0x1f0490,_0x513874){return _0x1f0490^_0x513874;},'uxIeS':function(_0x239de3,_0x2aec79){return _0x239de3^_0x2aec79;},'UOGUN':function(_0x528cd1,_0x54f8ae){return _0x528cd1>>>_0x54f8ae;},'pYKAl':function(_0x5bb684,_0x18e92e){return _0x5bb684>>>_0x18e92e;},'MWxIA':function(_0x534fbe,_0x409530){return _0x534fbe>>>_0x409530;},'wthFW':function(_0x54a5ef,_0xa005d3){return _0x54a5ef^_0xa005d3;},'NHsUz':function(_0x3b98b4,_0x4891ce){return _0x3b98b4^_0x4891ce;},'jutux':function(_0x2a3df3,_0x3f2857){return _0x2a3df3>>>_0x3f2857;},'xGiqz':function(_0x40a40d,_0x35cb6f){return _0x40a40d&_0x35cb6f;},'nxDgY':function(_0x7234eb,_0x307066){return _0x7234eb>>>_0x307066;},'rRqZe':function(_0x4a05ac,_0x223238){return _0x4a05ac&_0x223238;},'TgXCW':function(_0x5eaec0,_0x7eaa63){return _0x5eaec0>>>_0x7eaa63;},'tFftb':function(_0x55b34a,_0xd92c3a){return _0x55b34a^_0xd92c3a;},'RPiuL':function(_0x274db0,_0x24eb8a){return _0x274db0&_0x24eb8a;},'TLUkG':function(_0x345ce5,_0x1cc795){return _0x345ce5>>>_0x1cc795;},'YlCga':function(_0x3c1a6f,_0x24dd53){return _0x3c1a6f^_0x24dd53;},'oUZnb':function(_0x18a0ce,_0x3a1d9c){return _0x18a0ce^_0x3a1d9c;},'LDTuJ':function(_0x20d388,_0x156493){return _0x20d388^_0x156493;},'srbhU':function(_0x2212e3,_0x110881){return _0x2212e3>>>_0x110881;},'YrUyp':function(_0x18d969,_0x1a92fc){return _0x18d969&_0x1a92fc;},'SNkpi':function(_0x5ef289,_0x18cdb3){return _0x5ef289&_0x18cdb3;},'MKWqG':function(_0x296ded,_0x4e3164){return _0x296ded+_0x4e3164;},'XZZlG':function(_0x32faf3,_0x51a117){return _0x32faf3^_0x51a117;},'oWVQc':function(_0x3db8ed,_0x55f53e){return _0x3db8ed<<_0x55f53e;},'RCxYy':function(_0x13346c,_0x1536c3){return _0x13346c&_0x1536c3;},'jEaJL':function(_0x457332,_0x48b62d){return _0x457332>>>_0x48b62d;},'zqfdz':function(_0x34c996,_0x39dc1d){return _0x34c996<<_0x39dc1d;},'uXerk':function(_0x83654b,_0x54b758){return _0x83654b&_0x54b758;},'orafA':function(_0x9db6f3,_0x1c2bca){return _0x9db6f3>>>_0x1c2bca;},'IEnOy':function(_0x15364f,_0xfb823d){return _0x15364f===_0xfb823d;},'foUqK':_0x2be4df('0x205'),'yGhDo':_0x2be4df('0x423'),'CKdvf':function(_0x1742f7,_0x364ae1){return _0x1742f7==_0x364ae1;},'YtIYr':function(_0x187931,_0x4cf3d6){return _0x187931===_0x4cf3d6;},'yYlPz':_0x2be4df('0x3b8'),'SVitA':_0x2be4df('0x132'),'BdaEN':'wXzjh','KggVS':function(_0x18ac1a,_0x897e19){return _0x18ac1a==_0x897e19;},'ugfbc':function(_0x283554,_0xbbb3a){return _0x283554==_0xbbb3a;},'WBEQj':_0x2be4df('0xca'),'xZubY':_0x2be4df('0xcc'),'rjOhl':function(_0x4e26c0,_0x229a6e){return _0x4e26c0&_0x229a6e;},'Tdjed':function(_0x2319cb,_0xc95949){return _0x2319cb>>>_0xc95949;},'taLlE':function(_0x25da1d,_0x59e5e7){return _0x25da1d>>>_0x59e5e7;},'ynhHn':function(_0x546800,_0x51d0b8){return _0x546800!==_0x51d0b8;},'cqdgq':_0x2be4df('0x1b7'),'nOqEw':'JxVAM','UnrTC':_0x2be4df('0x1ef'),'erCLJ':_0x2be4df('0x1c7'),'zhzWQ':'EniBt','SrQVS':function(_0x35a2f1,_0xf0532e){return _0x35a2f1-_0xf0532e;},'ucwlA':function(_0xcc10c,_0x26a438){return _0xcc10c%_0x26a438;},'Bbpdm':function(_0x37afe1,_0x4087e1){return _0x37afe1|_0x4087e1;},'GTGFA':function(_0x467f10,_0x52ab37){return _0x467f10<<_0x52ab37;},'gpYgI':function(_0x1e33c8,_0x2cf9ac){return _0x1e33c8<_0x2cf9ac;},'HacPv':function(_0x2d4216,_0x536c67){return _0x2d4216(_0x536c67);},'TyDNc':_0x2be4df('0x3e4'),'WTjIE':function(_0x1869be,_0x5eb59c){return _0x1869be!==_0x5eb59c;},'VTclM':_0x2be4df('0x36e'),'QKHIz':_0x2be4df('0x2da'),'AlooV':function(_0x520ee3,_0x28396f){return _0x520ee3&_0x28396f;},'JTIKq':'ucOPk','jblqE':function(_0x1be050,_0x4860e3){return _0x1be050==_0x4860e3;},'bSAgv':_0x2be4df('0x279'),'eKoor':'hENmE','QBlYV':function(_0x2955c3,_0x3edeb4){return _0x2955c3<_0x3edeb4;},'gZxTF':function(_0x5babd9,_0x166cd7){return _0x5babd9>>>_0x166cd7;},'IYddE':function(_0x5a5f6c,_0x484ae2){return _0x5a5f6c%_0x484ae2;},'Jtrxn':_0x2be4df('0x479'),'ALaRd':function(_0x2bfd8b,_0x13b0a3){return _0x2bfd8b^_0x13b0a3;},'GdhAu':function(_0x324632,_0x1ce7be){return _0x324632*_0x1ce7be;},'CEgnc':function(_0x27aef1,_0x264c24){return _0x27aef1*_0x264c24;},'tBtHH':function(_0x2e5561,_0x6861bd){return _0x2e5561<<_0x6861bd;},'XvIbV':function(_0x99b389,_0x2a89c1){return _0x99b389>>>_0x2a89c1;},'UsLqj':function(_0x2a8cd6,_0x4b2758){return _0x2a8cd6|_0x4b2758;},'JrydO':function(_0xcba1d9,_0x445d93){return _0xcba1d9<<_0x445d93;},'jCtUT':function(_0x3e1b0a,_0x29a5af){return _0x3e1b0a>>>_0x29a5af;},'nnvNu':function(_0x5aa348,_0x214067){return _0x5aa348|_0x214067;},'RLCTJ':function(_0x369319,_0x3aa7bc){return _0x369319<<_0x3aa7bc;},'hvinW':function(_0x434d56,_0x19e081){return _0x434d56>>>_0x19e081;},'klhzI':function(_0x1f4372,_0x1c9a9e){return _0x1f4372^_0x1c9a9e;},'kaMVb':function(_0x2e1ab5,_0x42b218){return _0x2e1ab5<<_0x42b218;},'Emhji':function(_0x2d6a3b,_0x3ee036){return _0x2d6a3b<<_0x3ee036;},'IdSJY':function(_0x2b1fd4,_0x5c1214){return _0x2b1fd4>>>_0x5c1214;},'ErOAr':function(_0x26b818,_0x3fcf20){return _0x26b818<<_0x3fcf20;},'fReWi':function(_0x919a57,_0x50b2ab){return _0x919a57>>>_0x50b2ab;},'knHjX':function(_0x2d93d9,_0x802ac6){return _0x2d93d9^_0x802ac6;},'wdiag':function(_0x6fdcd6,_0x2dc7c1){return _0x6fdcd6*_0x2dc7c1;},'fpEcb':function(_0x49a14a,_0x220d11){return _0x49a14a*_0x220d11;},'jgHUo':function(_0x14d963,_0x420b14){return _0x14d963<<_0x420b14;},'OUDyI':function(_0x2b0af1,_0x1c1660){return _0x2b0af1>>>_0x1c1660;},'wWAvw':_0x2be4df('0x28b'),'gfqPY':_0x2be4df('0x2d6'),'MCkeB':function(_0x1cd358,_0x166586){return _0x1cd358===_0x166586;},'oXkna':_0x2be4df('0x361'),'SVneJ':_0x2be4df('0x58'),'VjmqN':function(_0x3c50fb,_0x82f1eb){return _0x3c50fb(_0x82f1eb);},'evmpZ':_0x2be4df('0x178'),'tkxBg':function(_0x5369e1,_0x33ab88){return _0x5369e1===_0x33ab88;},'lvwEy':'ymDSn','kgKIC':_0x2be4df('0x266'),'uoBlH':function(_0x1d1652,_0x52aac4){return _0x1d1652===_0x52aac4;},'FjKGm':_0x2be4df('0x6d'),'xTzxz':_0x2be4df('0x35d'),'pyTDF':function(_0x485803,_0x27b548){return _0x485803==_0x27b548;},'EWCdn':function(_0x55e622,_0x579739){return _0x55e622===_0x579739;},'ERBtS':_0x2be4df('0x393'),'KjDlO':'0|3|5|2|4|1','cElkn':function(_0x57a5b5,_0x34a5eb){return _0x57a5b5>_0x34a5eb;},'Lrnkx':function(_0x30bda4,_0x273e71){return _0x30bda4+_0x273e71;},'iYrLG':function(_0x39e2ac,_0x3f3cc5){return _0x39e2ac|_0x3f3cc5;},'HjVkd':function(_0x38034c,_0x1237e5){return _0x38034c&_0x1237e5;},'KrCSo':function(_0x5912c8,_0x24678d){return _0x5912c8<<_0x24678d;},'Xtqot':function(_0x4812b3,_0x55e32e){return _0x4812b3>>>_0x55e32e;},'NOiWP':function(_0x10d41a,_0x2c0a22){return _0x10d41a>>>_0x2c0a22;},'QqItE':function(_0x49f47b,_0x40ac28){return _0x49f47b+_0x40ac28;},'CIXiD':function(_0x2c2edb,_0x4fccd8){return _0x2c2edb+_0x4fccd8;},'RWccH':function(_0x15999d,_0x36db30){return _0x15999d+_0x36db30;},'CMXoK':function(_0x59c028,_0x20adfc){return _0x59c028+_0x20adfc;},'Bfqze':function(_0x1dc051,_0x4c5691){return _0x1dc051+_0x4c5691;},'mIAWJ':function(_0x582bea,_0x46788e){return _0x582bea+_0x46788e;},'TOQVk':function(_0x55735c,_0x3acc0a){return _0x55735c+_0x3acc0a;},'vlfxr':function(_0x33fb5c,_0x77f5df){return _0x33fb5c+_0x77f5df;},'Ioudf':function(_0x4a5740,_0x500be0,_0x3216c6,_0x817622,_0x451f32,_0x3c9a99,_0x4d66e4,_0x1736bd){return _0x4a5740(_0x500be0,_0x3216c6,_0x817622,_0x451f32,_0x3c9a99,_0x4d66e4,_0x1736bd);},'QeQtr':function(_0x4bd30e,_0x38aef2,_0x1051d4,_0x5b3f02,_0xc6c5b2,_0x5cc923,_0x18f8ee,_0xa9a039){return _0x4bd30e(_0x38aef2,_0x1051d4,_0x5b3f02,_0xc6c5b2,_0x5cc923,_0x18f8ee,_0xa9a039);},'BZtFb':function(_0x3e81ae,_0x56f0e3,_0x4b972c,_0x2a98b1,_0x585172,_0x38d2a7,_0x3ceeec,_0x5184ed){return _0x3e81ae(_0x56f0e3,_0x4b972c,_0x2a98b1,_0x585172,_0x38d2a7,_0x3ceeec,_0x5184ed);},'oZbsr':function(_0x57ef1e,_0x9d1014,_0x559057,_0x3e08d0,_0x32a575,_0x414b4f,_0x32a2b0,_0x2d9a95){return _0x57ef1e(_0x9d1014,_0x559057,_0x3e08d0,_0x32a575,_0x414b4f,_0x32a2b0,_0x2d9a95);},'jMsHK':function(_0x4d46cc,_0x60df1,_0x37c84c,_0x353e60,_0x2b5495,_0x5ca38c,_0x565a50,_0x5e4ba2){return _0x4d46cc(_0x60df1,_0x37c84c,_0x353e60,_0x2b5495,_0x5ca38c,_0x565a50,_0x5e4ba2);},'MNjtw':function(_0xe65113,_0x2fdcef,_0x462cfe,_0x39154c,_0x35217c,_0xab3560,_0xe2a146,_0x1a9930){return _0xe65113(_0x2fdcef,_0x462cfe,_0x39154c,_0x35217c,_0xab3560,_0xe2a146,_0x1a9930);},'AMBrM':function(_0x12345d,_0x4f3a54,_0x313204,_0x85ff78,_0x373a81,_0x437d99,_0x2e5c06,_0x1e147a){return _0x12345d(_0x4f3a54,_0x313204,_0x85ff78,_0x373a81,_0x437d99,_0x2e5c06,_0x1e147a);},'tVcZQ':function(_0x4dd4d1,_0x44f62d,_0x58441c,_0xe9b1a1,_0x3a16d9,_0x537270,_0x69d447,_0x3de791){return _0x4dd4d1(_0x44f62d,_0x58441c,_0xe9b1a1,_0x3a16d9,_0x537270,_0x69d447,_0x3de791);},'ZPGwE':function(_0x26bf0e,_0x1c4ae3,_0x1b8704,_0x51f8e2,_0x135659,_0x315cf6,_0x264a9d,_0x378f2b){return _0x26bf0e(_0x1c4ae3,_0x1b8704,_0x51f8e2,_0x135659,_0x315cf6,_0x264a9d,_0x378f2b);},'pehSB':function(_0x183d83,_0x2c5fda,_0x2a84cc,_0x10be0b,_0x1bc6e7,_0x543549,_0x18f102,_0x159698){return _0x183d83(_0x2c5fda,_0x2a84cc,_0x10be0b,_0x1bc6e7,_0x543549,_0x18f102,_0x159698);},'AmSXg':function(_0x4a381c,_0x5129d1,_0x14a007,_0x3ca192,_0x46c8ce,_0x4089b9,_0x10b954,_0xabcef4){return _0x4a381c(_0x5129d1,_0x14a007,_0x3ca192,_0x46c8ce,_0x4089b9,_0x10b954,_0xabcef4);},'jnqlG':function(_0x4a10a5,_0x2f2308,_0x2f7e46,_0x440fa3,_0x517d42,_0x14e57f,_0x287a51,_0x569798){return _0x4a10a5(_0x2f2308,_0x2f7e46,_0x440fa3,_0x517d42,_0x14e57f,_0x287a51,_0x569798);},'NSZSK':function(_0x544c49,_0x26ccbd,_0x7f7b07,_0x4ab0de,_0x5ed5e8,_0x5ae0fe,_0x2ad628,_0x25edaf){return _0x544c49(_0x26ccbd,_0x7f7b07,_0x4ab0de,_0x5ed5e8,_0x5ae0fe,_0x2ad628,_0x25edaf);},'marRt':function(_0x518b7c,_0x413cdb,_0x2d3fdc,_0x3a32ac,_0x34d8d4,_0x5257d1,_0x15e9d6,_0x1277ab){return _0x518b7c(_0x413cdb,_0x2d3fdc,_0x3a32ac,_0x34d8d4,_0x5257d1,_0x15e9d6,_0x1277ab);},'fiUqW':function(_0x2568af,_0x272103,_0x2ca6f9,_0x32e1d8,_0x2426bb,_0x2eb004,_0x34c0c9,_0x3e533e){return _0x2568af(_0x272103,_0x2ca6f9,_0x32e1d8,_0x2426bb,_0x2eb004,_0x34c0c9,_0x3e533e);},'GYrOB':function(_0x1b37c5,_0x256a3d,_0x124b22,_0x9cec7b,_0x48a6fb,_0x190305,_0x4caca7,_0x5914a1){return _0x1b37c5(_0x256a3d,_0x124b22,_0x9cec7b,_0x48a6fb,_0x190305,_0x4caca7,_0x5914a1);},'DMZvd':function(_0xa001cc,_0x100112,_0x375627,_0x4a417d,_0x2cfa31,_0x281b53,_0x1f2936,_0x222508){return _0xa001cc(_0x100112,_0x375627,_0x4a417d,_0x2cfa31,_0x281b53,_0x1f2936,_0x222508);},'idtrw':function(_0x4e9833,_0x45e638,_0x3a00bc,_0xdd511c,_0x33582e,_0x16d3a5,_0x30ace1,_0x333386){return _0x4e9833(_0x45e638,_0x3a00bc,_0xdd511c,_0x33582e,_0x16d3a5,_0x30ace1,_0x333386);},'VtZQD':function(_0x3c7cad,_0x4ed6ef,_0x5c5780,_0x5a94fb,_0x35a0e8,_0x2836a6,_0x54e15b,_0xf346ef){return _0x3c7cad(_0x4ed6ef,_0x5c5780,_0x5a94fb,_0x35a0e8,_0x2836a6,_0x54e15b,_0xf346ef);},'DCoZJ':function(_0x554e2d,_0x43529a){return _0x554e2d+_0x43529a;},'UVfJN':function(_0x3ae841,_0x38f1ea){return _0x3ae841!==_0x38f1ea;},'olRAN':_0x2be4df('0x44c'),'rYKkx':_0x2be4df('0x203'),'YPZzs':'0|2|1|4|3','SmpzZ':function(_0x2e1cbf,_0x1517ee){return _0x2e1cbf==_0x1517ee;},'vdlBV':_0x2be4df('0x24e'),'ooEWF':'pKXPW','LlmUI':_0x2be4df('0x2f5'),'VyMpc':_0x2be4df('0xf0'),'pmpcm':function(_0x184801,_0x6a856e){return _0x184801==_0x6a856e;},'RVghb':function(_0xbb0067,_0x1baf8e){return _0xbb0067!==_0x1baf8e;},'UWTrG':_0x2be4df('0x47c'),'bFzFP':_0x2be4df('0x129'),'fVSeH':_0x2be4df('0xc1'),'DDzdf':function(_0x3fcc8b,_0x15a044){return _0x3fcc8b+_0x15a044;},'EKOMe':function(_0x1df811,_0x512ae6){return _0x1df811*_0x512ae6;},'rpEHM':function(_0x567cf6,_0x18e3ba){return _0x567cf6*_0x18e3ba;},'kEWkw':function(_0x493ee7,_0x544597){return _0x493ee7==_0x544597;},'pzbjm':function(_0x3dd5ea,_0x44a73e){return _0x3dd5ea!==_0x44a73e;},'Ykmkq':_0x2be4df('0x13f'),'QraSt':_0x2be4df('0x47a'),'JsUuJ':_0x2be4df('0x249'),'lWgHb':function(_0xfc814e,_0x5b744c){return _0xfc814e===_0x5b744c;},'MkHTk':_0x2be4df('0x3eb'),'Eaant':_0x2be4df('0x3ca'),'oXvdJ':'2|3|4|0|1'},_0x3c9886=CryptoJS,_0x114fca=_0x3c9886[_0x2be4df('0x246')],_0x4b9014=_0x114fca[_0x2be4df('0xff')],_0x1f6dde=_0x114fca['WordArray'],_0x47dbc8=_0x114fca[_0x2be4df('0x3ed')],_0x4616d8=_0x3c9886['enc'][_0x2be4df('0x450')],_0x2c9441=_0x3c9886[_0x2be4df('0x329')][_0x2be4df('0x40b')],_0x2d9d24=_0x114fca[_0x2be4df('0x2e3')]=_0x47dbc8[_0x2be4df('0x3ad')]({'cfg':_0x4b9014['extend'](),'createEncryptor':function(_0x387a58,_0x281f28){var _0x283456=_0x2be4df;if(_0x25416c[_0x283456('0xac')](_0x25416c[_0x283456('0x22d')],_0x25416c['kyqRt']))return this[_0x283456('0x286')](this[_0x283456('0xb1')],_0x387a58,_0x281f28);else{function _0xef8ed8(){var _0x3fd0e3=_0x283456;_0x26df85[_0x3fd0e3('0xbf')][_0x3fd0e3('0x1e')](this),this[_0x3fd0e3('0x32d')]();}}},'createDecryptor':function(_0x3ba8b5,_0x516844){var _0x1bebba=_0x2be4df;if(_0x25416c['XkskD'](_0x25416c[_0x1bebba('0x16d')],_0x25416c[_0x1bebba('0x16d')])){function _0x340b85(){var _0x92195e=_0x1bebba;return(_0x96ffc4||this[_0x92195e('0x8d')])[_0x92195e('0x40e')](this);}}else return this[_0x1bebba('0x286')](this[_0x1bebba('0x15e')],_0x3ba8b5,_0x516844);},'init':function(_0x140167,_0x236249,_0x3717cb){var _0x3fb50a=_0x2be4df,_0x27a5bb={'XXTfu':function(_0x3523b7,_0x1e90e4){var _0x4d5708=_0x4528;return _0x25416c[_0x4d5708('0x23e')](_0x3523b7,_0x1e90e4);},'digYZ':_0x25416c['MzqcH'],'sXEYl':function(_0x2a5715,_0x2eacfe){var _0xc61590=_0x4528;return _0x25416c[_0xc61590('0x23e')](_0x2a5715,_0x2eacfe);},'bDqre':function(_0x18a95e,_0x10947e){return _0x25416c['SzOAC'](_0x18a95e,_0x10947e);}};if(_0x25416c[_0x3fb50a('0x3c3')](_0x25416c[_0x3fb50a('0x16f')],_0x25416c[_0x3fb50a('0x2a0')]))this[_0x3fb50a('0x15c')]=this[_0x3fb50a('0x15c')][_0x3fb50a('0x3ad')](_0x3717cb),this['_xformMode']=_0x140167,this[_0x3fb50a('0x1cf')]=_0x236249,this[_0x3fb50a('0xbf')]();else{function _0x1cbd1d(){var _0x4f8dd7=_0x3fb50a;for(var _0xba9624=this[_0x4f8dd7('0x15c')],_0x19df34=_0xba9624[_0x4f8dd7('0x2ed')]['create'](),_0x4c40e5=_0x275d50[_0x4f8dd7('0x286')](),_0x551380=_0x4c40e5[_0x4f8dd7('0x431')],_0x26e4d4=_0xba9624[_0x4f8dd7('0x464')],_0xba9624=_0xba9624[_0x4f8dd7('0x3cc')];_0x27a5bb['XXTfu'](_0x551380[_0x4f8dd7('0x47d')],_0x26e4d4);){var _0x48f4a1=_0x27a5bb['digYZ'][_0x4f8dd7('0x2f8')]('|'),_0x8ebea6=0x0;while(!![]){switch(_0x48f4a1[_0x8ebea6++]){case'0':for(var _0x2015a8=0x1;_0x27a5bb[_0x4f8dd7('0x3cd')](_0x2015a8,_0xba9624);_0x2015a8++)_0x114a93=_0x19df34[_0x4f8dd7('0x68')](_0x114a93),_0x19df34[_0x4f8dd7('0xbf')]();continue;case'1':_0x114a93&&_0x19df34[_0x4f8dd7('0x3f5')](_0x114a93);continue;case'2':var _0x114a93=_0x19df34[_0x4f8dd7('0x3f5')](_0x44b74e)[_0x4f8dd7('0x68')](_0x4db8ea);continue;case'3':_0x19df34[_0x4f8dd7('0xbf')]();continue;case'4':_0x4c40e5['concat'](_0x114a93);continue;}break;}}return _0x4c40e5[_0x4f8dd7('0xbe')]=_0x27a5bb[_0x4f8dd7('0x3c9')](0x4,_0x26e4d4),_0x4c40e5;}}},'reset':function(){var _0x1dc31e=_0x2be4df,_0x1989ed={'rvMwT':function(_0x595687,_0x286220){var _0x116d57=_0x4528;return _0x25416c[_0x116d57('0x210')](_0x595687,_0x286220);},'YiWfc':function(_0x3535eb,_0x4ffa3f){return _0x25416c['etmEn'](_0x3535eb,_0x4ffa3f);},'kfRbJ':function(_0x8383c0,_0x5bec77){var _0x9c9590=_0x4528;return _0x25416c[_0x9c9590('0x210')](_0x8383c0,_0x5bec77);},'ewgar':function(_0x2514cb,_0x238ad0){var _0x4e5a2e=_0x4528;return _0x25416c[_0x4e5a2e('0xf1')](_0x2514cb,_0x238ad0);},'TsjPu':function(_0x102e88,_0x3826ce){var _0x5cd0c2=_0x4528;return _0x25416c[_0x5cd0c2('0x240')](_0x102e88,_0x3826ce);},'DViHy':function(_0x5118d0,_0x380a5d){var _0x2823d7=_0x4528;return _0x25416c[_0x2823d7('0xcf')](_0x5118d0,_0x380a5d);},'OTYCy':function(_0x3eec7f,_0x8c29b1){var _0x2fca8e=_0x4528;return _0x25416c[_0x2fca8e('0x3b1')](_0x3eec7f,_0x8c29b1);},'EiyBD':function(_0x1ee6da,_0x1914e5){var _0x4649cd=_0x4528;return _0x25416c[_0x4649cd('0xf1')](_0x1ee6da,_0x1914e5);},'VJQcY':function(_0x3ef201,_0xeffdb8){var _0x4946ce=_0x4528;return _0x25416c[_0x4946ce('0xf2')](_0x3ef201,_0xeffdb8);},'YvcHR':function(_0xb059dd,_0x5f14e4){var _0x32be1c=_0x4528;return _0x25416c[_0x32be1c('0x369')](_0xb059dd,_0x5f14e4);},'EFEVK':function(_0x3fc894,_0x2bccad){var _0x406d02=_0x4528;return _0x25416c[_0x406d02('0x2a3')](_0x3fc894,_0x2bccad);}};if(_0x25416c[_0x1dc31e('0xa')](_0x25416c['bvpSG'],_0x25416c[_0x1dc31e('0x29e')])){function _0x18b3dc(){var _0x24d445=_0x1dc31e;return _0x3856e7=_0x1989ed[_0x24d445('0xae')](_0x1989ed[_0x24d445('0x130')](_0x1989ed[_0x24d445('0x2a8')](_0xa5c44,_0x1989ed['ewgar'](_0x1989ed[_0x24d445('0x454')](_0x43e8cb,_0x215aa3),_0x1989ed[_0x24d445('0x10')](~_0x9df4a6,_0x303765))),_0x6d1790),_0x43762e),_0x1989ed[_0x24d445('0x36')](_0x1989ed['EiyBD'](_0x1989ed[_0x24d445('0x14')](_0x4ac00c,_0x2692cc),_0x1989ed[_0x24d445('0x62')](_0x53686c,_0x1989ed['EFEVK'](0x20,_0x3169f5))),_0x44aa9c);}}else _0x47dbc8[_0x1dc31e('0xbf')][_0x1dc31e('0x1e')](this),this[_0x1dc31e('0x32d')]();},'process':function(_0x3e4aa2){var _0x4ba5c7=_0x2be4df,_0x3be5d0={'KijqX':function(_0x502679,_0x2459bc){var _0x4fdb87=_0x4528;return _0x25416c[_0x4fdb87('0x3b1')](_0x502679,_0x2459bc);},'lhcsJ':function(_0x225821,_0x33f281){return _0x25416c['AJIbn'](_0x225821,_0x33f281);},'noKwJ':function(_0x69c94,_0x4c964e){var _0x469da8=_0x4528;return _0x25416c[_0x469da8('0x24')](_0x69c94,_0x4c964e);},'eJvTN':function(_0x54488e,_0x241a60){return _0x25416c['DbfFF'](_0x54488e,_0x241a60);},'WhNRG':function(_0x5bbc84,_0x5a109e){var _0x20f04f=_0x4528;return _0x25416c[_0x20f04f('0x3d4')](_0x5bbc84,_0x5a109e);},'kBurU':function(_0x56d0ad,_0x12e36b){var _0x29460a=_0x4528;return _0x25416c[_0x29460a('0x22e')](_0x56d0ad,_0x12e36b);},'FrBMn':function(_0x36124c,_0x28a703){var _0x2489c1=_0x4528;return _0x25416c[_0x2489c1('0x369')](_0x36124c,_0x28a703);},'jPXqT':function(_0x4b376d,_0x5643af){return _0x25416c['gUQlW'](_0x4b376d,_0x5643af);}};if(_0x25416c[_0x4ba5c7('0xa')](_0x25416c[_0x4ba5c7('0x244')],_0x25416c[_0x4ba5c7('0x244')]))return this[_0x4ba5c7('0x26')](_0x3e4aa2),this[_0x4ba5c7('0x26d')]();else{function _0x2cb202(){var _0xaa6703=_0x4ba5c7;return _0x5d23d9=_0x3be5d0[_0xaa6703('0x66')](_0x3be5d0[_0xaa6703('0x98')](_0x3be5d0[_0xaa6703('0x98')](_0x5bd989,_0x3be5d0[_0xaa6703('0x156')](_0x156e2f,_0x3be5d0[_0xaa6703('0x44b')](_0x203274,~_0x462e03))),_0x43fd09),_0xbd256f),_0x3be5d0[_0xaa6703('0xbc')](_0x3be5d0[_0xaa6703('0x44b')](_0x3be5d0['kBurU'](_0x261c81,_0x326f63),_0x3be5d0[_0xaa6703('0x38a')](_0x4068e6,_0x3be5d0[_0xaa6703('0x241')](0x20,_0x2b6128))),_0x141650);}}},'finalize':function(_0x573221){var _0x56cbd8=_0x2be4df;if(_0x25416c[_0x56cbd8('0xa')](_0x25416c[_0x56cbd8('0x163')],_0x25416c['WTsXj']))return _0x573221&&this[_0x56cbd8('0x26')](_0x573221),this[_0x56cbd8('0x89')]();else{function _0x259f37(){var _0x4f82cc=_0x56cbd8,_0x155c15=this[_0x4f82cc('0x431')],_0x57a700=this[_0x4f82cc('0xbe')];_0x155c15[_0x25416c[_0x4f82cc('0x369')](_0x57a700,0x2)]&=_0x25416c[_0x4f82cc('0x22e')](0xffffffff,_0x25416c[_0x4f82cc('0xfa')](0x20,_0x25416c[_0x4f82cc('0xe7')](0x8,_0x25416c['ygoaM'](_0x57a700,0x4)))),_0x155c15[_0x4f82cc('0x47d')]=_0x1aee34[_0x4f82cc('0x107')](_0x25416c[_0x4f82cc('0x484')](_0x57a700,0x4));}}},'keySize':0x4,'ivSize':0x4,'_ENC_XFORM_MODE':0x1,'_DEC_XFORM_MODE':0x2,'_createHelper':function(_0x40e24c){var _0x120fd2=_0x2be4df,_0x435fe0={'ztAVP':_0x25416c[_0x120fd2('0x25b')]};if(_0x25416c[_0x120fd2('0xa')](_0x25416c['CJSwo'],_0x25416c['CJSwo']))return{'encrypt':function(_0xae2f5c,_0x500f87,_0x14ef89){var _0x2795c7=_0x120fd2;if(_0x25416c[_0x2795c7('0xa')](_0x25416c[_0x2795c7('0x32a')],_0x25416c['soAjx'])){function _0x46bd57(){var _0x84fa43=_0x2795c7;this[_0x84fa43('0x387')](_0x4ae5cc,_0x5c19fd,this[_0x84fa43('0x2bc')],_0x56f723,_0x3b7330,_0x17ce5d,_0x316e96,_0x5ba072);}}else return(_0x25416c[_0x2795c7('0x391')](_0x25416c[_0x2795c7('0x1a1')],typeof _0x500f87)?_0x27ed10:_0x3aaab9)['encrypt'](_0x40e24c,_0xae2f5c,_0x500f87,_0x14ef89);},'decrypt':function(_0x3af644,_0x3bfa33,_0x3dfa09){var _0x5c3d07=_0x120fd2;if(_0x25416c['YlysY'](_0x25416c[_0x5c3d07('0x2')],_0x25416c[_0x5c3d07('0x2')]))return(_0x25416c['DoZhJ'](_0x25416c[_0x5c3d07('0x1a1')],typeof _0x3bfa33)?_0x27ed10:_0x3aaab9)[_0x5c3d07('0x313')](_0x40e24c,_0x3af644,_0x3bfa33,_0x3dfa09);else{function _0x163227(){var _0x120b4f=_0x5c3d07,_0x4219cc=_0x435fe0['ztAVP']['split']('|'),_0x3c8b68=0x0;while(!![]){switch(_0x4219cc[_0x3c8b68++]){case'0':_0xf8644c=this[_0x120b4f('0x15c')][_0x120b4f('0x3ad')](_0x1e2ae5);continue;case'1':var _0x317f42=_0x5b1cd2[_0x120b4f('0x449')](_0x41a467,_0x1a51fb);continue;case'2':_0x2e4361=_0x317f42[_0x120b4f('0x68')](_0x395457);continue;case'3':_0x317f42=_0x317f42[_0x120b4f('0x15c')];continue;case'4':return _0x4b1eaf[_0x120b4f('0x286')]({'ciphertext':_0x5b3596,'key':_0x31678b,'iv':_0x317f42['iv'],'algorithm':_0x2fdd7b,'mode':_0x317f42[_0x120b4f('0x193')],'padding':_0x317f42[_0x120b4f('0x25d')],'blockSize':_0x41c3f3[_0x120b4f('0x85')],'formatter':_0x38b422[_0x120b4f('0x192')]});}break;}}}}};else{function _0xca09d(){var _0xeabce4=_0x120fd2,_0x35a39a=_0x5e7dfb[_0xeabce4('0x3db')];return _0x5e1d03=_0x16692f['salt'],(_0x2897a9?_0x2c4cb7[_0xeabce4('0x286')]([0x53616c74,0x65645f5f])[_0xeabce4('0x3b2')](_0x478fcc)[_0xeabce4('0x3b2')](_0x35a39a):_0x35a39a)['toString'](_0x162498);}}}});_0x114fca[_0x2be4df('0x30a')]=_0x2d9d24['extend']({'_doFinalize':function(){var _0x5a9041=_0x2be4df;if(_0x25416c[_0x5a9041('0x3c3')](_0x25416c[_0x5a9041('0x151')],_0x25416c[_0x5a9041('0x151')])){function _0x5efe5f(){var _0x4978f9=_0x5a9041;return _0x181030&&this[_0x4978f9('0x26')](_0xf66d49),this[_0x4978f9('0x89')]();}}else return this[_0x5a9041('0x26d')](!0x0);},'blockSize':0x1});var _0x46ce9c=_0x3c9886[_0x2be4df('0x193')]={},_0x1e2a44=function(_0x1fc909,_0x424707,_0x10cc88){var _0x467144=_0x2be4df,_0x4fe0bf={'UIHMn':function(_0x32c5a3,_0x577316){return _0x25416c['UZaor'](_0x32c5a3,_0x577316);},'XYgeR':function(_0x1e91ae,_0x4775cc){var _0x3f7a92=_0x4528;return _0x25416c[_0x3f7a92('0x481')](_0x1e91ae,_0x4775cc);},'TgGNW':function(_0x4b8d22,_0x472de2){return _0x25416c['zhDlf'](_0x4b8d22,_0x472de2);},'xRpXY':function(_0x18bd80,_0x1c44f2){var _0x22c11f=_0x4528;return _0x25416c[_0x22c11f('0x427')](_0x18bd80,_0x1c44f2);},'zJGYX':function(_0x2bf00e,_0x15b07c){return _0x25416c['FrPGS'](_0x2bf00e,_0x15b07c);},'zOqMa':function(_0xdc3ff6,_0x444b4d){var _0x366b1f=_0x4528;return _0x25416c[_0x366b1f('0x41f')](_0xdc3ff6,_0x444b4d);},'hcMMN':function(_0x4e1cf8,_0x39e536){return _0x25416c['sXlZy'](_0x4e1cf8,_0x39e536);},'ireGz':function(_0xc1e0e0,_0x2a19f0){var _0x259ba5=_0x4528;return _0x25416c[_0x259ba5('0x334')](_0xc1e0e0,_0x2a19f0);}};if(_0x25416c[_0x467144('0x3c3')](_0x25416c[_0x467144('0x153')],_0x25416c[_0x467144('0x153')])){function _0x18c8c0(){var _0x5c356c=_0x467144;return _0x4e2ced=_0x4fe0bf[_0x5c356c('0x433')](_0x4fe0bf[_0x5c356c('0x433')](_0x4fe0bf['XYgeR'](_0x273a3,_0x4fe0bf[_0x5c356c('0xe0')](_0x4fe0bf[_0x5c356c('0x461')](_0x4784a5,_0x329d09),_0x3bc437)),_0xa1cca6),_0x44cce0),_0x4fe0bf[_0x5c356c('0x3bb')](_0x4fe0bf[_0x5c356c('0x1ed')](_0x4fe0bf[_0x5c356c('0x3')](_0x10d287,_0x537230),_0x4fe0bf['hcMMN'](_0x337f10,_0x4fe0bf[_0x5c356c('0x18d')](0x20,_0x3cb92a))),_0x23fea3);}}else{var _0x4c8bb4=this[_0x467144('0x1e7')];_0x4c8bb4?this[_0x467144('0x1e7')]=_0x51792d:_0x4c8bb4=this[_0x467144('0x1f6')];for(var _0x22115a=0x0;_0x25416c[_0x467144('0x86')](_0x22115a,_0x10cc88);_0x22115a++)_0x1fc909[_0x25416c[_0x467144('0x11b')](_0x424707,_0x22115a)]^=_0x4c8bb4[_0x22115a];}},_0x2e31c8=(_0x114fca['BlockCipherMode']=_0x4b9014[_0x2be4df('0x3ad')]({'createEncryptor':function(_0x107788,_0x209da9){var _0x70c1c0=_0x2be4df;if(_0x25416c['IEnOy'](_0x25416c['foUqK'],_0x25416c[_0x70c1c0('0x1d0')])){function _0x33633b(){var _0x4d3853=_0x70c1c0,_0x551566=_0x25416c[_0x4d3853('0x1ec')][_0x4d3853('0x2f8')]('|'),_0x1be50a=0x0;while(!![]){switch(_0x551566[_0x1be50a++]){case'0':_0x40a84a=_0x25416c[_0x4d3853('0x1b8')](_0x25416c[_0x4d3853('0xbb')](_0x25416c[_0x4d3853('0xbb')](_0x25416c[_0x4d3853('0xbb')](_0x25416c[_0x4d3853('0x1f2')](_0x5623c9[_0x25416c[_0x4d3853('0x61')](_0x2113e0,0x18)],0x18),_0x25416c['psjjq'](_0x20c38e[_0x25416c[_0x4d3853('0xea')](_0x25416c[_0x4d3853('0x46b')](_0x51c391,0x10),0xff)],0x10)),_0x25416c[_0x4d3853('0x2e4')](_0x248686[_0x25416c[_0x4d3853('0xea')](_0x25416c[_0x4d3853('0x46b')](_0x462b74,0x8),0xff)],0x8)),_0x84f2a5[_0x25416c[_0x4d3853('0xea')](_0x4e3d06,0xff)]),_0x594690[_0x4f44f3++]);continue;case'1':_0x3a9924=_0x25416c[_0x4d3853('0x45c')](_0x25416c[_0x4d3853('0xbb')](_0x25416c[_0x4d3853('0xbb')](_0x25416c[_0x4d3853('0xbb')](_0x25416c['QZVoQ'](_0x307760[_0x25416c[_0x4d3853('0x144')](_0x462b74,0x18)],0x18),_0x25416c[_0x4d3853('0x14c')](_0x5189cf[_0x25416c[_0x4d3853('0xea')](_0x25416c['ndrRK'](_0x4e3d06,0x10),0xff)],0x10)),_0x25416c[_0x4d3853('0x14c')](_0x386df6[_0x25416c['zMUYC'](_0x25416c[_0x4d3853('0x144')](_0x2113e0,0x8),0xff)],0x8)),_0x3db5fa[_0x25416c['zMUYC'](_0x51c391,0xff)]),_0x5a0a50[_0x4f44f3++]);continue;case'2':_0x31d2df=_0x25416c[_0x4d3853('0x45c')](_0x25416c['FrPGS'](_0x25416c[_0x4d3853('0x11a')](_0x25416c[_0x4d3853('0x3e5')](_0x25416c['iEUHd'](_0x28aed6[_0x25416c['vRPpv'](_0x51c391,0x18)],0x18),_0x25416c['iEUHd'](_0x315bb8[_0x25416c[_0x4d3853('0x3d')](_0x25416c[_0x4d3853('0x275')](_0x462b74,0x10),0xff)],0x10)),_0x25416c[_0x4d3853('0x34d')](_0x29b0aa[_0x25416c['PSVQV'](_0x25416c['vRPpv'](_0x4e3d06,0x8),0xff)],0x8)),_0x61fc19[_0x25416c['XMOcF'](_0x2113e0,0xff)]),_0x130ee2[_0x4f44f3++]);continue;case'3':_0x4f4817[_0x25416c[_0x4d3853('0x11b')](_0x1be25e,0x2)]=_0x3a9924;continue;case'4':_0xc0fb9b[_0x25416c[_0x4d3853('0x11f')](_0x39fe68,0x3)]=_0x4e3d06;continue;case'5':for(var _0x51275a=this[_0x4d3853('0x3ff')],_0x2113e0=_0x25416c[_0x4d3853('0x45c')](_0x9d02e4[_0x118dc1],_0xa4b82f[0x0]),_0x51c391=_0x25416c[_0x4d3853('0x273')](_0x3da1f7[_0x25416c['EfznE'](_0x14627d,0x1)],_0x44f69e[0x1]),_0x462b74=_0x25416c[_0x4d3853('0x1c5')](_0x1e4ba8[_0x25416c[_0x4d3853('0x12')](_0x25bba6,0x2)],_0x5ee8d8[0x2]),_0x4e3d06=_0x25416c[_0x4d3853('0x1c5')](_0x4d1b58[_0x25416c[_0x4d3853('0x12')](_0x1a852e,0x3)],_0x12d376[0x3]),_0x4f44f3=0x4,_0x4c6621=0x1;_0x25416c['iTsdB'](_0x4c6621,_0x51275a);_0x4c6621++)var _0x40a84a=_0x25416c[_0x4d3853('0x262')](_0x25416c[_0x4d3853('0x341')](_0x25416c[_0x4d3853('0x341')](_0x25416c[_0x4d3853('0x21')](_0x5a5ade[_0x25416c[_0x4d3853('0x106')](_0x2113e0,0x18)],_0x5eb148[_0x25416c[_0x4d3853('0x42f')](_0x25416c[_0x4d3853('0x1b1')](_0x51c391,0x10),0xff)]),_0x15f6d3[_0x25416c[_0x4d3853('0x42f')](_0x25416c[_0x4d3853('0x352')](_0x462b74,0x8),0xff)]),_0x197505[_0x25416c[_0x4d3853('0x42f')](_0x4e3d06,0xff)]),_0xfd39f0[_0x4f44f3++]),_0x31d2df=_0x25416c[_0x4d3853('0x2f1')](_0x25416c[_0x4d3853('0x2f1')](_0x25416c[_0x4d3853('0x2f1')](_0x25416c[_0x4d3853('0x6b')](_0x4e065f[_0x25416c[_0x4d3853('0x375')](_0x51c391,0x18)],_0x248cf3[_0x25416c['xGiqz'](_0x25416c['nxDgY'](_0x462b74,0x10),0xff)]),_0x5b6f0e[_0x25416c['rRqZe'](_0x25416c[_0x4d3853('0xfe')](_0x4e3d06,0x8),0xff)]),_0x5040c6[_0x25416c[_0x4d3853('0x463')](_0x2113e0,0xff)]),_0x320e04[_0x4f44f3++]),_0x3a9924=_0x25416c['NHsUz'](_0x25416c[_0x4d3853('0x6b')](_0x25416c[_0x4d3853('0x3b3')](_0x25416c['tFftb'](_0x2594e7[_0x25416c[_0x4d3853('0xfe')](_0x462b74,0x18)],_0x23bda6[_0x25416c[_0x4d3853('0x13b')](_0x25416c[_0x4d3853('0x3e1')](_0x4e3d06,0x10),0xff)]),_0x2b0310[_0x25416c[_0x4d3853('0x13b')](_0x25416c['TLUkG'](_0x2113e0,0x8),0xff)]),_0x1bbf30[_0x25416c[_0x4d3853('0x13b')](_0x51c391,0xff)]),_0x26ad97[_0x4f44f3++]),_0x4e3d06=_0x25416c['YlCga'](_0x25416c[_0x4d3853('0x2a6')](_0x25416c[_0x4d3853('0x2a6')](_0x25416c[_0x4d3853('0x117')](_0x4ea410[_0x25416c['TLUkG'](_0x4e3d06,0x18)],_0x2e60e0[_0x25416c[_0x4d3853('0x13b')](_0x25416c[_0x4d3853('0xb9')](_0x2113e0,0x10),0xff)]),_0x26147b[_0x25416c['YrUyp'](_0x25416c[_0x4d3853('0xb9')](_0x51c391,0x8),0xff)]),_0x46221a[_0x25416c[_0x4d3853('0x3b0')](_0x462b74,0xff)]),_0x9466ee[_0x4f44f3++]),_0x2113e0=_0x40a84a,_0x51c391=_0x31d2df,_0x462b74=_0x3a9924;continue;case'6':_0x1dff2d[_0x2f636f]=_0x40a84a;continue;case'7':_0xee6b04[_0x25416c[_0x4d3853('0x2a')](_0x168ce2,0x1)]=_0x31d2df;continue;case'8':_0x4e3d06=_0x25416c[_0x4d3853('0x7d')](_0x25416c[_0x4d3853('0x3e5')](_0x25416c[_0x4d3853('0x3e5')](_0x25416c[_0x4d3853('0x3e5')](_0x25416c[_0x4d3853('0x105')](_0x573463[_0x25416c[_0x4d3853('0xb9')](_0x4e3d06,0x18)],0x18),_0x25416c[_0x4d3853('0x105')](_0x21587f[_0x25416c[_0x4d3853('0x131')](_0x25416c[_0x4d3853('0x79')](_0x2113e0,0x10),0xff)],0x10)),_0x25416c[_0x4d3853('0x10a')](_0x4065cd[_0x25416c[_0x4d3853('0x34e')](_0x25416c[_0x4d3853('0x37a')](_0x51c391,0x8),0xff)],0x8)),_0x2826a9[_0x25416c[_0x4d3853('0x34e')](_0x462b74,0xff)]),_0x81afdf[_0x4f44f3++]);continue;}break;}}}else return this[_0x70c1c0('0x3d2')]['create'](_0x107788,_0x209da9);},'createDecryptor':function(_0x583384,_0x35e73b){var _0x33db7c=_0x2be4df,_0x6701cb={'WrNrU':function(_0x2c1d23,_0x3a2309){var _0x144973=_0x4528;return _0x25416c[_0x144973('0x38')](_0x2c1d23,_0x3a2309);}};if(_0x25416c[_0x33db7c('0x2c')](_0x25416c[_0x33db7c('0x182')],_0x25416c[_0x33db7c('0x96')])){function _0x4ade5d(){var _0x32e164=_0x33db7c;_0x5115df['reset'][_0x32e164('0x1e')](this);var _0x5cd3b6=this[_0x32e164('0x15c')],_0x5cd642=_0x5cd3b6['iv'],_0x5cd3b6=_0x5cd3b6[_0x32e164('0x193')];if(_0x6701cb[_0x32e164('0x2b5')](this[_0x32e164('0x16')],this[_0x32e164('0xb1')]))var _0x4f4805=_0x5cd3b6[_0x32e164('0x449')];else _0x4f4805=_0x5cd3b6[_0x32e164('0x4a')],this[_0x32e164('0x134')]=0x1;this[_0x32e164('0x245')]=_0x4f4805[_0x32e164('0x1e')](_0x5cd3b6,this,_0x5cd642&&_0x5cd642['words']);}}else return this[_0x33db7c('0x16a')]['create'](_0x583384,_0x35e73b);},'init':function(_0x4b31fa,_0x355383){var _0x25526b=_0x2be4df;if(_0x25416c[_0x25526b('0x3c3')](_0x25416c[_0x25526b('0x468')],_0x25416c[_0x25526b('0x468')])){function _0x250c3b(){return function(_0x89d386,_0x32edca){return new _0x2c730e['init'](_0x32edca)['finalize'](_0x89d386);};}}else this[_0x25526b('0x373')]=_0x4b31fa,this[_0x25526b('0x1e7')]=_0x355383;}}))[_0x2be4df('0x3ad')]();_0x2e31c8['Encryptor']=_0x2e31c8[_0x2be4df('0x3ad')]({'processBlock':function(_0x4803ce,_0x5544e7){var _0x2faf7b=_0x2be4df,_0x5013f9={'vFkWx':function(_0x2bdf7f,_0xf74a4b){var _0x30c9a4=_0x4528;return _0x25416c[_0x30c9a4('0x12e')](_0x2bdf7f,_0xf74a4b);},'CwHXB':function(_0x28ac7c,_0x5145f7){return _0x25416c['ugfbc'](_0x28ac7c,_0x5145f7);}};if(_0x25416c['XkskD'](_0x25416c[_0x2faf7b('0x3da')],_0x25416c[_0x2faf7b('0x3e6')])){var _0x40206e=this[_0x2faf7b('0x373')],_0x36b8d4=_0x40206e[_0x2faf7b('0x85')];_0x1e2a44[_0x2faf7b('0x1e')](this,_0x4803ce,_0x5544e7,_0x36b8d4),_0x40206e[_0x2faf7b('0x26a')](_0x4803ce,_0x5544e7),this[_0x2faf7b('0x1f6')]=_0x4803ce[_0x2faf7b('0x408')](_0x5544e7,_0x25416c[_0x2faf7b('0x2a')](_0x5544e7,_0x36b8d4));}else{function _0x2f0f43(){var _0x54f447=_0x2faf7b;_0x3768f2=_0x4f816b[_0x54f447('0x316')](_0x36aba9);var _0x21ee1c=_0x31bfd5[_0x54f447('0x431')];if(_0x5013f9[_0x54f447('0x74')](0x53616c74,_0x21ee1c[0x0])&&_0x5013f9['CwHXB'](0x65645f5f,_0x21ee1c[0x1])){var _0x4ddec2=_0x23a534[_0x54f447('0x286')](_0x21ee1c['slice'](0x2,0x4));_0x21ee1c['splice'](0x0,0x4),_0x31894b[_0x54f447('0xbe')]-=0x10;}return _0x28687e[_0x54f447('0x286')]({'ciphertext':_0x50e85c,'salt':_0x4ddec2});}}}}),_0x2e31c8[_0x2be4df('0x16a')]=_0x2e31c8['extend']({'processBlock':function(_0x3efa49,_0x55f68a){var _0x166ac2=_0x2be4df;if(_0x25416c['ynhHn'](_0x25416c[_0x166ac2('0x37c')],_0x25416c[_0x166ac2('0xd4')])){var _0x4f6806=this['_cipher'],_0x3ea846=_0x4f6806[_0x166ac2('0x85')],_0xc407e7=_0x3efa49[_0x166ac2('0x408')](_0x55f68a,_0x25416c['MKWqG'](_0x55f68a,_0x3ea846));_0x4f6806['decryptBlock'](_0x3efa49,_0x55f68a),_0x1e2a44['call'](this,_0x3efa49,_0x55f68a,_0x3ea846),this[_0x166ac2('0x1f6')]=_0xc407e7;}else{function _0x3dab97(){var _0x31244d=_0x166ac2,_0x1bbe9f=_0x16edd3[_0x31244d('0x431')];_0x48ac10=_0x47a186[_0x31244d('0xbe')];for(var _0x471ea4=[],_0x12a014=0x0;_0x25416c[_0x31244d('0x86')](_0x12a014,_0x3a1b66);_0x12a014++)_0x471ea4[_0x31244d('0x36d')](_0x5b00b6[_0x31244d('0x46d')](_0x25416c['rjOhl'](_0x25416c['Tdjed'](_0x1bbe9f[_0x25416c[_0x31244d('0x260')](_0x12a014,0x2)],_0x25416c[_0x31244d('0x334')](0x18,_0x25416c[_0x31244d('0xe7')](0x8,_0x25416c[_0x31244d('0x41a')](_0x12a014,0x4)))),0xff)));return _0x471ea4[_0x31244d('0xcd')]('');}}}}),_0x46ce9c=_0x46ce9c[_0x2be4df('0x321')]=_0x2e31c8,_0x2e31c8=(_0x3c9886[_0x2be4df('0x2ec')]={})[_0x2be4df('0x1e5')]={'pad':function(_0x409bb0,_0x2e2e0e){var _0x247094=_0x2be4df;if(_0x25416c[_0x247094('0x28d')](_0x25416c['erCLJ'],_0x25416c[_0x247094('0x24a')])){for(var _0x1fd620=_0x25416c[_0x247094('0xe7')](0x4,_0x2e2e0e),_0x1fd620=_0x25416c[_0x247094('0x4f')](_0x1fd620,_0x25416c[_0x247094('0x88')](_0x409bb0[_0x247094('0xbe')],_0x1fd620)),_0x15f33b=_0x25416c[_0x247094('0x3e5')](_0x25416c[_0x247094('0x2aa')](_0x25416c['Bbpdm'](_0x25416c[_0x247094('0x10a')](_0x1fd620,0x18),_0x25416c[_0x247094('0x10a')](_0x1fd620,0x10)),_0x25416c[_0x247094('0x39')](_0x1fd620,0x8)),_0x1fd620),_0x348392=[],_0x443f36=0x0;_0x25416c[_0x247094('0x2d7')](_0x443f36,_0x1fd620);_0x443f36+=0x4)_0x348392[_0x247094('0x36d')](_0x15f33b);_0x1fd620=_0x1f6dde[_0x247094('0x286')](_0x348392,_0x1fd620),_0x409bb0[_0x247094('0x3b2')](_0x1fd620);}else{function _0x152f83(){var _0x34e188=_0x247094;for(var _0x42f46b in _0x542a72)_0x4f764f[_0x34e188('0x22f')](_0x42f46b)&&(this[_0x42f46b]=_0x50b464[_0x42f46b]);_0x9d4d6c['hasOwnProperty'](_0x25416c[_0x34e188('0x268')])&&(this[_0x34e188('0x1ef')]=_0x35a4e4['toString']);}}},'unpad':function(_0x5bc2fb){var _0x54554c=_0x2be4df;if(_0x25416c['WTjIE'](_0x25416c[_0x54554c('0x40c')],_0x25416c[_0x54554c('0x94')]))_0x5bc2fb[_0x54554c('0xbe')]-=_0x25416c[_0x54554c('0x1fd')](_0x5bc2fb[_0x54554c('0x431')][_0x25416c[_0x54554c('0x260')](_0x25416c['SrQVS'](_0x5bc2fb[_0x54554c('0xbe')],0x1),0x2)],0xff);else{function _0x5f20f2(){var _0x248c4a=_0x54554c;throw _0x25416c['HacPv'](_0x4650f3,_0x25416c[_0x248c4a('0x421')]);}}}},_0x114fca[_0x2be4df('0x8a')]=_0x2d9d24[_0x2be4df('0x3ad')]({'cfg':_0x2d9d24[_0x2be4df('0x15c')]['extend']({'mode':_0x46ce9c,'padding':_0x2e31c8}),'reset':function(){var _0x332774=_0x2be4df;if(_0x25416c[_0x332774('0x357')](_0x25416c[_0x332774('0x3e3')],_0x25416c['JTIKq'])){function _0x510a86(){var _0x16128a=_0x332774;_0x40cf01[_0x16128a('0x2ec')](this['_data'],this[_0x16128a('0x85')]);var _0x13d380=this[_0x16128a('0x26d')](!0x0);}}else{_0x2d9d24['reset']['call'](this);var _0x489317=this[_0x332774('0x15c')],_0x5505a2=_0x489317['iv'],_0x489317=_0x489317[_0x332774('0x193')];if(_0x25416c[_0x332774('0x1e2')](this[_0x332774('0x16')],this[_0x332774('0xb1')]))var _0x9647bd=_0x489317[_0x332774('0x449')];else _0x9647bd=_0x489317[_0x332774('0x4a')],this[_0x332774('0x134')]=0x1;this[_0x332774('0x245')]=_0x9647bd[_0x332774('0x1e')](_0x489317,this,_0x5505a2&&_0x5505a2[_0x332774('0x431')]);}},'_doProcessBlock':function(_0x374efa,_0x439269){var _0x1a8b01=_0x2be4df;if(_0x25416c['WTjIE'](_0x25416c['eKoor'],_0x25416c[_0x1a8b01('0xf7')])){function _0x13d5d1(){var _0x16295f=_0x1a8b01,_0x47fcea=_0x25416c[_0x16295f('0x2cf')][_0x16295f('0x2f8')]('|'),_0x1cf267=0x0;while(!![]){switch(_0x47fcea[_0x1cf267++]){case'0':_0x22de13=_0x8ab0e3['kdf'][_0x16295f('0x1ca')](_0x2b2400,_0x4d436c['keySize'],_0x35c214[_0x16295f('0x22b')],_0x68c840[_0x16295f('0x13a')]);continue;case'1':_0x20c957['iv']=_0x3ac102['iv'];continue;case'2':_0x1cfce3=this[_0x16295f('0x2eb')](_0x24abd9,_0x1ce37f[_0x16295f('0x192')]);continue;case'3':return _0x30ad6c[_0x16295f('0x313')][_0x16295f('0x1e')](this,_0xe4c3fb,_0x4812a6,_0x138f08[_0x16295f('0x219')],_0x41f39b);case'4':_0x5017c8=this[_0x16295f('0x15c')][_0x16295f('0x3ad')](_0x315530);continue;}break;}}}else this[_0x1a8b01('0x245')][_0x1a8b01('0x48')](_0x374efa,_0x439269);},'_doFinalize':function(){var _0x2e6426=_0x2be4df;if(_0x25416c[_0x2e6426('0x2c')](_0x25416c[_0x2e6426('0x162')],_0x25416c[_0x2e6426('0x162')])){var _0x3b769a=this[_0x2e6426('0x15c')][_0x2e6426('0x25d')];if(_0x25416c['jblqE'](this[_0x2e6426('0x16')],this[_0x2e6426('0xb1')])){if(_0x25416c[_0x2e6426('0x2c')](_0x25416c[_0x2e6426('0x135')],_0x25416c[_0x2e6426('0x135')])){_0x3b769a[_0x2e6426('0x2ec')](this[_0x2e6426('0xe8')],this[_0x2e6426('0x85')]);var _0x2ee1b8=this[_0x2e6426('0x26d')](!0x0);}else{function _0x3503cf(){var _0x487900=_0x2e6426,_0x2561a4=_0x59c6b8[_0x487900('0x431')];_0x3c5a00=_0x1d8380[_0x487900('0xbe')];for(var _0x3553ef=[],_0x551828=0x0;_0x25416c[_0x487900('0x177')](_0x551828,_0x1ae486);_0x551828++){var _0x4f67e5=_0x25416c['AlooV'](_0x25416c[_0x487900('0x260')](_0x2561a4[_0x25416c[_0x487900('0xe1')](_0x551828,0x2)],_0x25416c[_0x487900('0x4f')](0x18,_0x25416c['SzOAC'](0x8,_0x25416c[_0x487900('0x97')](_0x551828,0x4)))),0xff);_0x3553ef[_0x487900('0x36d')](_0x25416c[_0x487900('0xe1')](_0x4f67e5,0x4)[_0x487900('0x1ef')](0x10)),_0x3553ef[_0x487900('0x36d')](_0x25416c[_0x487900('0x1fd')](_0x4f67e5,0xf)['toString'](0x10));}return _0x3553ef[_0x487900('0xcd')]('');}}}else _0x2ee1b8=this[_0x2e6426('0x26d')](!0x0),_0x3b769a[_0x2e6426('0x379')](_0x2ee1b8);return _0x2ee1b8;}else{function _0x1b28a8(){var _0x9a9d1=_0x2e6426,_0x5bf374=_0x25416c['Jtrxn']['split']('|'),_0x51d9cc=0x0;while(!![]){switch(_0x5bf374[_0x51d9cc++]){case'0':_0x139f1b=_0x25416c[_0x9a9d1('0x7d')](_0x25416c[_0x9a9d1('0x127')](_0x25416c['ALaRd'](_0x25416c[_0x9a9d1('0x1db')](0x1010101,_0x3f3d2a),_0x25416c['GdhAu'](0x10001,_0x5959c1)),_0x25416c[_0x9a9d1('0x1db')](0x101,_0x33ad85)),_0x25416c[_0x9a9d1('0x49')](0x1010100,_0x375118));continue;case'1':_0x29a5f9[_0x1a75ea]=_0x25416c['Bbpdm'](_0x25416c[_0x9a9d1('0x3f8')](_0x139f1b,0x8),_0x25416c['XvIbV'](_0x139f1b,0x18));continue;case'2':_0x6dc59[_0x2f382d]=_0x25416c[_0x9a9d1('0x2aa')](_0x25416c['tBtHH'](_0x139f1b,0x18),_0x25416c[_0x9a9d1('0x91')](_0x139f1b,0x8));continue;case'3':_0xd0e66a[_0x4f7215]=_0x2f382d;continue;case'4':_0x1f7b42[_0x2f382d]=_0x25416c[_0x9a9d1('0x5a')](_0x25416c['JrydO'](_0x139f1b,0x10),_0x25416c[_0x9a9d1('0xa4')](_0x139f1b,0x10));continue;case'5':_0x9d502[_0x2f382d]=_0x25416c[_0x9a9d1('0x446')](_0x25416c[_0x9a9d1('0x1ab')](_0x139f1b,0x8),_0x25416c[_0x9a9d1('0x147')](_0x139f1b,0x18));continue;case'6':_0x24a3eb[_0x2f382d]=_0x4d56bd;continue;case'7':var _0x2f382d=_0x25416c['ALaRd'](_0x25416c['ALaRd'](_0x25416c[_0x9a9d1('0x202')](_0x25416c['klhzI'](_0x4caaae,_0x25416c[_0x9a9d1('0x38e')](_0x334578,0x1)),_0x25416c[_0x9a9d1('0x38e')](_0x252bde,0x2)),_0x25416c[_0x9a9d1('0x38e')](_0xd886f6,0x3)),_0x25416c[_0x9a9d1('0x277')](_0x1b4fba,0x4)),_0x2f382d=_0x25416c[_0x9a9d1('0x202')](_0x25416c[_0x9a9d1('0x202')](_0x25416c['IdSJY'](_0x2f382d,0x8),_0x25416c['AlooV'](_0x2f382d,0xff)),0x63);continue;case'8':_0x4035bb[_0x3b964e]=_0x25416c[_0x9a9d1('0x446')](_0x25416c[_0x9a9d1('0x11')](_0x139f1b,0x10),_0x25416c[_0x9a9d1('0xc4')](_0x139f1b,0x10));continue;case'9':_0x1ef6cf[_0x2f382d]=_0x139f1b;continue;case'10':var _0x33ad85=_0x38188a[_0x1ac24f],_0x5959c1=_0x5e1011[_0x33ad85],_0x3f3d2a=_0x4aa272[_0x5959c1],_0x139f1b=_0x25416c['knHjX'](_0x25416c[_0x9a9d1('0x42d')](0x101,_0x4055bd[_0x2f382d]),_0x25416c[_0x9a9d1('0xf3')](0x1010100,_0x2f382d));continue;case'11':_0x3724ed?(_0x29929b=_0x25416c['knHjX'](_0x33ad85,_0x1ce40c[_0x461a1f[_0x5f54ee[_0x25416c[_0x9a9d1('0x1f5')](_0x3f3d2a,_0x33ad85)]]]),_0x462b9b^=_0x452c2f[_0x1c22c2[_0x2ade1d]]):_0x49cb13=_0xe633c8=0x1;continue;case'12':_0x105c74[_0x58d3fe]=_0x139f1b;continue;case'13':_0x50e7fd[_0x126f34]=_0x25416c[_0x9a9d1('0x446')](_0x25416c[_0x9a9d1('0x25e')](_0x139f1b,0x18),_0x25416c[_0x9a9d1('0x291')](_0x139f1b,0x8));continue;}break;}}}},'blockSize':0x4});var _0x438f09=_0x114fca[_0x2be4df('0x297')]=_0x4b9014[_0x2be4df('0x3ad')]({'init':function(_0xf73037){var _0x18fd51=_0x2be4df;if(_0x25416c['MCkeB'](_0x25416c[_0x18fd51('0x17d')],_0x25416c[_0x18fd51('0x1a')])){function _0x24cc58(){var _0x549c74=_0x18fd51;return _0x26754f[_0x549c74('0x286')](_0x570919)['compute'](_0x367d6c,_0x41295e);}}else this[_0x18fd51('0x46')](_0xf73037);},'toString':function(_0xe2576e){var _0x48edfc=_0x2be4df,_0x1208a7={'sdKqh':function(_0x501089,_0x1afd9b){var _0x240364=_0x4528;return _0x25416c[_0x240364('0x17a')](_0x501089,_0x1afd9b);}};if(_0x25416c[_0x48edfc('0x336')](_0x25416c['evmpZ'],_0x25416c[_0x48edfc('0x2fd')]))return(_0xe2576e||this[_0x48edfc('0x8d')])[_0x48edfc('0x40e')](this);else{function _0x397aff(){var _0x336b61=_0x48edfc;return _0x3f9b6a[_0x336b61('0x316')](_0x1208a7[_0x336b61('0x45d')](_0xb98b25,_0x1208a7[_0x336b61('0x45d')](_0x11790c,_0x55dc00)));}}}}),_0x46ce9c=(_0x3c9886[_0x2be4df('0x192')]={})[_0x2be4df('0xf4')]={'stringify':function(_0x57b865){var _0x2d8694=_0x2be4df;if(_0x25416c[_0x2d8694('0x404')](_0x25416c['lvwEy'],_0x25416c[_0x2d8694('0x2bf')])){var _0x963b0=_0x57b865['ciphertext'];return _0x57b865=_0x57b865['salt'],(_0x57b865?_0x1f6dde[_0x2d8694('0x286')]([0x53616c74,0x65645f5f])[_0x2d8694('0x3b2')](_0x57b865)[_0x2d8694('0x3b2')](_0x963b0):_0x963b0)[_0x2d8694('0x1ef')](_0x4616d8);}else{function _0xb06ac8(){this['_hash']=new _0xb6c6d0['init']([0x67452301,0xefcdab89,0x98badcfe,0x10325476]);}}},'parse':function(_0xd8b470){var _0x1447a0=_0x2be4df,_0x541262={'wFqhM':_0x25416c['kgKIC'],'YZGUq':function(_0x5a906e,_0x4ab75d){var _0x33629c=_0x4528;return _0x25416c[_0x33629c('0x2a')](_0x5a906e,_0x4ab75d);}};if(_0x25416c[_0x1447a0('0x295')](_0x25416c[_0x1447a0('0xd6')],_0x25416c[_0x1447a0('0x2f3')])){function _0xbdbd84(){var _0x2c93bd=_0x1447a0,_0x2df16a=_0x541262[_0x2c93bd('0x11c')][_0x2c93bd('0x2f8')]('|'),_0x46e49c=0x0;while(!![]){switch(_0x2df16a[_0x46e49c++]){case'0':_0x262cfc=_0x472e28[_0x541262[_0x2c93bd('0x92')](_0x126a78,0x1)];continue;case'1':_0x269080[_0x541262['YZGUq'](_0x45adea,0x3)]=_0x262cfc;continue;case'2':var _0x262cfc=_0xf93bff[_0x541262['YZGUq'](_0x4ea281,0x1)];continue;case'3':_0x490613[_0x541262[_0x2c93bd('0x92')](_0x5d98e4,0x1)]=_0x1da52d[_0x541262['YZGUq'](_0x59df7c,0x3)];continue;case'4':this['_doCryptBlock'](_0x57e954,_0xf8f95a,this[_0x2c93bd('0x410')],_0x224dd0,_0x2200d3,_0x572e05,_0x2f4044,_0x5a887c);continue;case'5':_0x3b2be1[_0x541262[_0x2c93bd('0x92')](_0x44a558,0x1)]=_0x528118[_0x541262[_0x2c93bd('0x92')](_0x1b0a36,0x3)];continue;case'6':_0x15c958[_0x541262[_0x2c93bd('0x92')](_0x573e85,0x3)]=_0x262cfc;continue;}break;}}}else{_0xd8b470=_0x4616d8[_0x1447a0('0x316')](_0xd8b470);var _0x15ea81=_0xd8b470[_0x1447a0('0x431')];if(_0x25416c['pyTDF'](0x53616c74,_0x15ea81[0x0])&&_0x25416c[_0x1447a0('0x6e')](0x65645f5f,_0x15ea81[0x1])){if(_0x25416c['EWCdn'](_0x25416c[_0x1447a0('0x9a')],_0x25416c[_0x1447a0('0x9a')])){var _0x5029bc=_0x1f6dde[_0x1447a0('0x286')](_0x15ea81[_0x1447a0('0x408')](0x2,0x4));_0x15ea81['splice'](0x0,0x4),_0xd8b470['sigBytes']-=0x10;}else{function _0x291131(){this['_mode']['processBlock'](_0x41c487,_0x46c0da);}}}return _0x438f09['create']({'ciphertext':_0xd8b470,'salt':_0x5029bc});}}},_0x3aaab9=_0x114fca[_0x2be4df('0x196')]=_0x4b9014[_0x2be4df('0x3ad')]({'cfg':_0x4b9014[_0x2be4df('0x3ad')]({'format':_0x46ce9c}),'encrypt':function(_0x4f97d3,_0x1bb769,_0x438d55,_0x329ab9){var _0x5baa61=_0x2be4df,_0xd35357={'cOyah':_0x25416c[_0x5baa61('0x55')],'JTJPH':function(_0x2789e3,_0x5044e6){return _0x25416c['cElkn'](_0x2789e3,_0x5044e6);},'NPBPS':function(_0x15c1cb,_0x57cd97){return _0x25416c['Lrnkx'](_0x15c1cb,_0x57cd97);},'Yutfc':function(_0x4ce9ae,_0x2fd79a){var _0x241ad4=_0x5baa61;return _0x25416c[_0x241ad4('0x44d')](_0x4ce9ae,_0x2fd79a);},'MnEyd':function(_0x4bfada,_0xc41022){var _0xd36d6a=_0x5baa61;return _0x25416c[_0xd36d6a('0x45e')](_0x4bfada,_0xc41022);},'zirfi':function(_0x3c1421,_0xd6b31f){var _0x35fec7=_0x5baa61;return _0x25416c[_0x35fec7('0x44d')](_0x3c1421,_0xd6b31f);},'hQrgQ':function(_0x2f4a9a,_0x48a69d){var _0x41a956=_0x5baa61;return _0x25416c[_0x41a956('0x1c')](_0x2f4a9a,_0x48a69d);},'KibWi':function(_0x22e762,_0x131d3a){var _0x3efdfc=_0x5baa61;return _0x25416c[_0x3efdfc('0x265')](_0x22e762,_0x131d3a);},'uFcqJ':function(_0x16161b,_0x559af9){return _0x25416c['NOiWP'](_0x16161b,_0x559af9);},'BXaaT':function(_0x418b46,_0x16625d){return _0x25416c['iYrLG'](_0x418b46,_0x16625d);},'KOTBp':function(_0x2c89be,_0x37db8c){var _0x21057e=_0x5baa61;return _0x25416c[_0x21057e('0x424')](_0x2c89be,_0x37db8c);},'kggUb':function(_0x2e0866,_0x10956e){var _0x180304=_0x5baa61;return _0x25416c[_0x180304('0x283')](_0x2e0866,_0x10956e);},'xziyu':function(_0x704ac4,_0x182e2d){var _0x3aa092=_0x5baa61;return _0x25416c[_0x3aa092('0x8c')](_0x704ac4,_0x182e2d);},'ujJGW':function(_0xd1442,_0x12f3d1){var _0x138e10=_0x5baa61;return _0x25416c[_0x138e10('0xc5')](_0xd1442,_0x12f3d1);},'SbRwV':function(_0x4a15bc,_0x5d06a2){var _0x42b615=_0x5baa61;return _0x25416c[_0x42b615('0xc5')](_0x4a15bc,_0x5d06a2);},'hAYuu':function(_0x59b4c3,_0xac5666){var _0x22a45c=_0x5baa61;return _0x25416c[_0x22a45c('0x120')](_0x59b4c3,_0xac5666);},'MPOfZ':function(_0x4a06f4,_0x2d531e){var _0x507af4=_0x5baa61;return _0x25416c[_0x507af4('0x23a')](_0x4a06f4,_0x2d531e);},'syzGB':function(_0x2f5924,_0x5f18d5){var _0x1798d3=_0x5baa61;return _0x25416c[_0x1798d3('0x3ac')](_0x2f5924,_0x5f18d5);},'ajZfG':function(_0x291ce1,_0xce2f20){var _0x57810f=_0x5baa61;return _0x25416c[_0x57810f('0x3ac')](_0x291ce1,_0xce2f20);},'OCIus':function(_0x2337ac,_0x8cf63b){var _0x1484a5=_0x5baa61;return _0x25416c[_0x1484a5('0x471')](_0x2337ac,_0x8cf63b);},'GaCkY':function(_0x190304,_0x5817f8){var _0x12a814=_0x5baa61;return _0x25416c[_0x12a814('0x471')](_0x190304,_0x5817f8);},'IXFtG':function(_0x3d8787,_0x443fa8,_0x44f58f,_0x522526,_0x514af7,_0x48ae25,_0x3ee373,_0x64fd3){var _0x4b29c9=_0x5baa61;return _0x25416c[_0x4b29c9('0x34')](_0x3d8787,_0x443fa8,_0x44f58f,_0x522526,_0x514af7,_0x48ae25,_0x3ee373,_0x64fd3);},'FRqsr':function(_0x1a94d4,_0x1fc084,_0x262c20,_0x556304,_0x3d851c,_0x5caefd,_0x445b2b,_0x3410af){var _0x3183d5=_0x5baa61;return _0x25416c[_0x3183d5('0x137')](_0x1a94d4,_0x1fc084,_0x262c20,_0x556304,_0x3d851c,_0x5caefd,_0x445b2b,_0x3410af);},'HVTgg':function(_0x2780f8,_0x499be3,_0x5936b6,_0x38c3f9,_0x2b474c,_0x3d5547,_0x53fa07,_0x5d8c87){return _0x25416c['QeQtr'](_0x2780f8,_0x499be3,_0x5936b6,_0x38c3f9,_0x2b474c,_0x3d5547,_0x53fa07,_0x5d8c87);},'hGjaj':function(_0x15106d,_0x11bad6,_0x4d8c59,_0x2b28ab,_0x465682,_0x4f18f5,_0xdcf4,_0x5b0c5c){return _0x25416c['BZtFb'](_0x15106d,_0x11bad6,_0x4d8c59,_0x2b28ab,_0x465682,_0x4f18f5,_0xdcf4,_0x5b0c5c);},'kjWDs':function(_0x201a00,_0x2b050f,_0x4457ca,_0x12cd6e,_0x24ba57,_0x2d29e1,_0x271f40,_0x5b8316){return _0x25416c['oZbsr'](_0x201a00,_0x2b050f,_0x4457ca,_0x12cd6e,_0x24ba57,_0x2d29e1,_0x271f40,_0x5b8316);},'YDJFH':function(_0x31db91,_0x1af311,_0x3fc12c,_0x2c1df9,_0x2246a8,_0x2691dc,_0x41054d,_0x2e099f){return _0x25416c['oZbsr'](_0x31db91,_0x1af311,_0x3fc12c,_0x2c1df9,_0x2246a8,_0x2691dc,_0x41054d,_0x2e099f);},'hsZDJ':function(_0xb1b5e3,_0xa0ed37,_0xb6d3d5,_0x463f02,_0x5b84bc,_0x1f8dcc,_0x37cb81,_0x1bd8a0){var _0x299529=_0x5baa61;return _0x25416c[_0x299529('0x1a9')](_0xb1b5e3,_0xa0ed37,_0xb6d3d5,_0x463f02,_0x5b84bc,_0x1f8dcc,_0x37cb81,_0x1bd8a0);},'slORt':function(_0x10613e,_0x1f21bf,_0x34e18d,_0x51f827,_0x108db5,_0xf32ffe,_0xb03216,_0x3c5976){return _0x25416c['MNjtw'](_0x10613e,_0x1f21bf,_0x34e18d,_0x51f827,_0x108db5,_0xf32ffe,_0xb03216,_0x3c5976);},'acjLy':function(_0x3ad3cc,_0x511add,_0x355b36,_0x4b69a7,_0x1b3148,_0x301de6,_0x7d4579,_0x17303d){var _0x278d60=_0x5baa61;return _0x25416c[_0x278d60('0x472')](_0x3ad3cc,_0x511add,_0x355b36,_0x4b69a7,_0x1b3148,_0x301de6,_0x7d4579,_0x17303d);},'xzIce':function(_0x76d03d,_0xc1767b,_0x55c6f0,_0x4e1abf,_0x4066ef,_0x518001,_0x90ebe3,_0x3a1260){var _0x209f46=_0x5baa61;return _0x25416c[_0x209f46('0x472')](_0x76d03d,_0xc1767b,_0x55c6f0,_0x4e1abf,_0x4066ef,_0x518001,_0x90ebe3,_0x3a1260);},'CSwgt':function(_0x24835c,_0xc70f9a,_0x4fe2fc,_0x2263fd,_0xfd884e,_0x49b8d3,_0x1605d6,_0x38e478){var _0x1f6bb8=_0x5baa61;return _0x25416c[_0x1f6bb8('0x257')](_0x24835c,_0xc70f9a,_0x4fe2fc,_0x2263fd,_0xfd884e,_0x49b8d3,_0x1605d6,_0x38e478);},'lGTEg':function(_0x91805a,_0x76364f,_0x4c461a,_0x55aa4b,_0x9a52c,_0x198b15,_0x580b86,_0x437700){var _0x56aefe=_0x5baa61;return _0x25416c[_0x56aefe('0x7b')](_0x91805a,_0x76364f,_0x4c461a,_0x55aa4b,_0x9a52c,_0x198b15,_0x580b86,_0x437700);},'UZUQM':function(_0x3af521,_0x38b85d,_0x2876b8,_0x338eff,_0x2ff8e6,_0x2936d0,_0x4084a4,_0x3cdff3){var _0x120fc3=_0x5baa61;return _0x25416c[_0x120fc3('0x267')](_0x3af521,_0x38b85d,_0x2876b8,_0x338eff,_0x2ff8e6,_0x2936d0,_0x4084a4,_0x3cdff3);},'mYiKm':function(_0x22b4b6,_0x3e94c4,_0x27b4b7,_0x1dfabe,_0x521735,_0x79023,_0x32b8b9,_0x147fd5){return _0x25416c['pehSB'](_0x22b4b6,_0x3e94c4,_0x27b4b7,_0x1dfabe,_0x521735,_0x79023,_0x32b8b9,_0x147fd5);},'DtobO':function(_0x21058b,_0xf26adc,_0x597548,_0x4478dc,_0x25b8fe,_0x284478,_0x1d9761,_0x13eb56){return _0x25416c['pehSB'](_0x21058b,_0xf26adc,_0x597548,_0x4478dc,_0x25b8fe,_0x284478,_0x1d9761,_0x13eb56);},'oWOtw':function(_0x5f0c2e,_0x5f062b,_0x5809de,_0x30b11b,_0xec1a2a,_0x5600de,_0x4a8dbe,_0x2aa17e){var _0x9601f=_0x5baa61;return _0x25416c[_0x9601f('0xa8')](_0x5f0c2e,_0x5f062b,_0x5809de,_0x30b11b,_0xec1a2a,_0x5600de,_0x4a8dbe,_0x2aa17e);},'hOGAF':function(_0x379bb3,_0x42f9eb,_0xd23ef2,_0x27d381,_0x23e030,_0x10b406,_0x426df1,_0x451464){var _0x271921=_0x5baa61;return _0x25416c[_0x271921('0x243')](_0x379bb3,_0x42f9eb,_0xd23ef2,_0x27d381,_0x23e030,_0x10b406,_0x426df1,_0x451464);},'puBmQ':function(_0x1f683a,_0x31155d,_0x41cae6,_0x1c8420,_0x1a5eed,_0x134b8a,_0x4b06e2,_0x1b3348){var _0x1d4b35=_0x5baa61;return _0x25416c[_0x1d4b35('0x243')](_0x1f683a,_0x31155d,_0x41cae6,_0x1c8420,_0x1a5eed,_0x134b8a,_0x4b06e2,_0x1b3348);},'CEkPx':function(_0x1513f1,_0x6c56e5,_0x276f65,_0x30f105,_0x54e94e,_0x36a9d4,_0x5e3577,_0x51e606){return _0x25416c['NSZSK'](_0x1513f1,_0x6c56e5,_0x276f65,_0x30f105,_0x54e94e,_0x36a9d4,_0x5e3577,_0x51e606);},'yxIsp':function(_0x171b7d,_0xf403ac,_0x24e382,_0x544953,_0x5f5a80,_0x382d26,_0x5eccdf,_0x2fa8cf){var _0x58ad40=_0x5baa61;return _0x25416c[_0x58ad40('0x377')](_0x171b7d,_0xf403ac,_0x24e382,_0x544953,_0x5f5a80,_0x382d26,_0x5eccdf,_0x2fa8cf);},'NdSse':function(_0xf5d305,_0x12eace,_0x2d6a71,_0x4a29c3,_0x16b27a,_0x352e7f,_0x3c79d7,_0x328d65){return _0x25416c['marRt'](_0xf5d305,_0x12eace,_0x2d6a71,_0x4a29c3,_0x16b27a,_0x352e7f,_0x3c79d7,_0x328d65);},'OtBSl':function(_0x4cee6a,_0x41178e,_0x5b92c5,_0x41987d,_0x50be34,_0x428d05,_0x11150d,_0x11ede2){var _0x17bb14=_0x5baa61;return _0x25416c[_0x17bb14('0x331')](_0x4cee6a,_0x41178e,_0x5b92c5,_0x41987d,_0x50be34,_0x428d05,_0x11150d,_0x11ede2);},'NhnrI':function(_0x5b5791,_0x194936,_0x144fb4,_0x50863a,_0x11a0bd,_0x285c1a,_0x5cad05,_0x1c34a0){var _0x30ab31=_0x5baa61;return _0x25416c[_0x30ab31('0x331')](_0x5b5791,_0x194936,_0x144fb4,_0x50863a,_0x11a0bd,_0x285c1a,_0x5cad05,_0x1c34a0);},'rdUDA':function(_0x4ac0ab,_0x16b809,_0x49085b,_0x2b2bc2,_0x13ff65,_0x33fdd5,_0x88835a,_0xea68b6){var _0x3bf14e=_0x5baa61;return _0x25416c[_0x3bf14e('0x331')](_0x4ac0ab,_0x16b809,_0x49085b,_0x2b2bc2,_0x13ff65,_0x33fdd5,_0x88835a,_0xea68b6);},'XbsWj':function(_0x3dcbc5,_0x1eacbc,_0x3ae9ef,_0x4c3f4a,_0x420fbc,_0x5e7778,_0x526a12,_0x2053f6){var _0x3184ed=_0x5baa61;return _0x25416c[_0x3184ed('0x331')](_0x3dcbc5,_0x1eacbc,_0x3ae9ef,_0x4c3f4a,_0x420fbc,_0x5e7778,_0x526a12,_0x2053f6);},'OovDx':function(_0x109c30,_0x1dbd41,_0x459f17,_0x3d2105,_0x50a8ba,_0x219873,_0x4de37c,_0x521868){var _0xe6c11b=_0x5baa61;return _0x25416c[_0xe6c11b('0x1a0')](_0x109c30,_0x1dbd41,_0x459f17,_0x3d2105,_0x50a8ba,_0x219873,_0x4de37c,_0x521868);},'aqiAp':function(_0x5841bd,_0x45da61,_0x25ca5a,_0x307a22,_0x365bdd,_0x6c3d9f,_0x1f7069,_0xf83c75){var _0x2ed70c=_0x5baa61;return _0x25416c[_0x2ed70c('0x41e')](_0x5841bd,_0x45da61,_0x25ca5a,_0x307a22,_0x365bdd,_0x6c3d9f,_0x1f7069,_0xf83c75);},'CiWPQ':function(_0x5eabba,_0x2e8d90,_0x319cd0,_0x4ac7a8,_0x4a41ba,_0x364a1e,_0x58fba0,_0xf5614a){var _0x42ece2=_0x5baa61;return _0x25416c[_0x42ece2('0x41e')](_0x5eabba,_0x2e8d90,_0x319cd0,_0x4ac7a8,_0x4a41ba,_0x364a1e,_0x58fba0,_0xf5614a);},'QRYpM':function(_0x27c4f1,_0x573d84,_0x2f2db3,_0x1ce93d,_0x3ff5a4,_0x1de50a,_0x165b82,_0x5e44ea){var _0x2512f1=_0x5baa61;return _0x25416c[_0x2512f1('0xb5')](_0x27c4f1,_0x573d84,_0x2f2db3,_0x1ce93d,_0x3ff5a4,_0x1de50a,_0x165b82,_0x5e44ea);},'XKDuE':function(_0x2e5f1f,_0x30984d,_0xf4c010,_0x183d8f,_0x53c175,_0x4695d9,_0x4181b9,_0x49983b){var _0x1e0c12=_0x5baa61;return _0x25416c[_0x1e0c12('0xb5')](_0x2e5f1f,_0x30984d,_0xf4c010,_0x183d8f,_0x53c175,_0x4695d9,_0x4181b9,_0x49983b);},'rIJuX':function(_0x58d2c0,_0x2655a7,_0x36f2dd,_0x3a2c85,_0x319009,_0x2fdee5,_0xc9f75d,_0x2b5ecc){return _0x25416c['idtrw'](_0x58d2c0,_0x2655a7,_0x36f2dd,_0x3a2c85,_0x319009,_0x2fdee5,_0xc9f75d,_0x2b5ecc);},'LVLIm':function(_0x1e4afa,_0x300632,_0x438702,_0x53dec3,_0x3dba38,_0x251c95,_0x315310,_0x116d07){var _0x26891e=_0x5baa61;return _0x25416c[_0x26891e('0x407')](_0x1e4afa,_0x300632,_0x438702,_0x53dec3,_0x3dba38,_0x251c95,_0x315310,_0x116d07);},'mFKRP':function(_0x5d5faa,_0x10ddf3,_0x11e073,_0x12d81b,_0x1a6014,_0x160625,_0x5963e0,_0x11addd){var _0x13c473=_0x5baa61;return _0x25416c[_0x13c473('0x407')](_0x5d5faa,_0x10ddf3,_0x11e073,_0x12d81b,_0x1a6014,_0x160625,_0x5963e0,_0x11addd);},'orQET':function(_0x5c529c,_0xad7c4a){var _0x5048ce=_0x5baa61;return _0x25416c[_0x5048ce('0x44d')](_0x5c529c,_0xad7c4a);},'zKkFb':function(_0x1a2263,_0x2ceaf3){return _0x25416c['vlfxr'](_0x1a2263,_0x2ceaf3);},'kWfAg':function(_0x294fd7,_0x23b901){return _0x25416c['DCoZJ'](_0x294fd7,_0x23b901);}};if(_0x25416c['UVfJN'](_0x25416c['olRAN'],_0x25416c['rYKkx'])){var _0x2fb656=_0x25416c[_0x5baa61('0x402')][_0x5baa61('0x2f8')]('|'),_0x25c6ed=0x0;while(!![]){switch(_0x2fb656[_0x25c6ed++]){case'0':_0x329ab9=this[_0x5baa61('0x15c')][_0x5baa61('0x3ad')](_0x329ab9);continue;case'1':_0x1bb769=_0x1a45cd[_0x5baa61('0x68')](_0x1bb769);continue;case'2':var _0x1a45cd=_0x4f97d3[_0x5baa61('0x449')](_0x438d55,_0x329ab9);continue;case'3':return _0x438f09[_0x5baa61('0x286')]({'ciphertext':_0x1bb769,'key':_0x438d55,'iv':_0x1a45cd['iv'],'algorithm':_0x4f97d3,'mode':_0x1a45cd['mode'],'padding':_0x1a45cd[_0x5baa61('0x25d')],'blockSize':_0x4f97d3['blockSize'],'formatter':_0x329ab9[_0x5baa61('0x192')]});case'4':_0x1a45cd=_0x1a45cd[_0x5baa61('0x15c')];continue;}break;}}else{function _0x491a01(){var _0x3ef1c5=_0x5baa61,_0x3bf316=_0xd35357[_0x3ef1c5('0x473')][_0x3ef1c5('0x2f8')]('|'),_0xde6dad=0x0;while(!![]){switch(_0x3bf316[_0xde6dad++]){case'0':for(var _0x2c7e83=0x0;_0xd35357[_0x3ef1c5('0x3f2')](0x10,_0x2c7e83);_0x2c7e83++){var _0x590fcf=_0xd35357[_0x3ef1c5('0x1bd')](_0x3aa37b,_0x2c7e83),_0x246da2=_0x30d68c[_0x590fcf];_0x1e3f1b[_0x590fcf]=_0xd35357[_0x3ef1c5('0x9c')](_0xd35357['MnEyd'](_0xd35357[_0x3ef1c5('0x1e0')](_0xd35357[_0x3ef1c5('0x184')](_0x246da2,0x8),_0xd35357['KibWi'](_0x246da2,0x18)),0xff00ff),_0xd35357[_0x3ef1c5('0x335')](_0xd35357[_0x3ef1c5('0x1e0')](_0xd35357[_0x3ef1c5('0x184')](_0x246da2,0x18),_0xd35357['uFcqJ'](_0x246da2,0x8)),0xff00ff00));}continue;case'1':_0x2c7e83[0x3]=_0xd35357[_0x3ef1c5('0x1e0')](_0xd35357[_0x3ef1c5('0x1bd')](_0x2c7e83[0x3],_0x8e9c56),0x0);continue;case'2':_0x2c7e83[0x1]=_0xd35357[_0x3ef1c5('0x292')](_0xd35357[_0x3ef1c5('0x298')](_0x2c7e83[0x1],_0x4a0cd9),0x0);continue;case'3':var _0x2c7e83=this[_0x3ef1c5('0x363')][_0x3ef1c5('0x431')],_0x590fcf=_0x595f63[_0xd35357[_0x3ef1c5('0x298')](_0x54019d,0x0)],_0x246da2=_0xd94398[_0xd35357['kggUb'](_0x50271f,0x1)],_0x28c79e=_0x2cad56[_0xd35357[_0x3ef1c5('0x293')](_0x7bf3bb,0x2)],_0x500e45=_0x2f09bf[_0xd35357[_0x3ef1c5('0x293')](_0x38927f,0x3)],_0xb892ee=_0x73be91[_0xd35357[_0x3ef1c5('0x293')](_0x24a583,0x4)],_0x161ca4=_0x55cf96[_0xd35357[_0x3ef1c5('0x3fc')](_0x1ef383,0x5)],_0x45304e=_0x252907[_0xd35357['SbRwV'](_0x56a0b6,0x6)],_0x1fa187=_0x21bce0[_0xd35357[_0x3ef1c5('0x414')](_0x567f9c,0x7)],_0x287c02=_0x23f86e[_0xd35357[_0x3ef1c5('0xde')](_0xff1036,0x8)],_0x14765b=_0x172b72[_0xd35357[_0x3ef1c5('0x384')](_0x3bede6,0x9)],_0x540540=_0x553ca4[_0xd35357[_0x3ef1c5('0x1f8')](_0x65ce52,0xa)],_0x27dd6a=_0x56a7fb[_0xd35357[_0x3ef1c5('0x3cf')](_0x31e0d7,0xb)],_0x243fdd=_0x23db0a[_0xd35357[_0x3ef1c5('0x52')](_0x3363db,0xc)],_0x3563d4=_0xc31119[_0xd35357[_0x3ef1c5('0x52')](_0x138d92,0xd)],_0x180156=_0x58c2e9[_0xd35357[_0x3ef1c5('0x52')](_0x5b3e59,0xe)],_0x2cdf19=_0x2bf1a4[_0xd35357[_0x3ef1c5('0x3e9')](_0x17053e,0xf)],_0x476cf3=_0x2c7e83[0x0],_0x4a0cd9=_0x2c7e83[0x1],_0x259d30=_0x2c7e83[0x2],_0x8e9c56=_0x2c7e83[0x3],_0x476cf3=_0xd35357['IXFtG'](_0x4759e7,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x590fcf,0x7,_0x204a3f[0x0]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x45a')](_0x45f1f4,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x246da2,0xc,_0x173389[0x1]),_0x259d30=_0xd35357[_0x3ef1c5('0x45a')](_0x5c8c41,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x28c79e,0x11,_0x4d9c00[0x2]),_0x4a0cd9=_0xd35357['FRqsr'](_0x5f0b53,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x500e45,0x16,_0x2f6296[0x3]),_0x476cf3=_0xd35357['FRqsr'](_0x33a918,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0xb892ee,0x7,_0x3c74d3[0x4]),_0x8e9c56=_0xd35357[_0x3ef1c5('0xfc')](_0x372ca1,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x161ca4,0xc,_0x57c56b[0x5]),_0x259d30=_0xd35357['hGjaj'](_0x3f8c38,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x45304e,0x11,_0x5899de[0x6]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x38c')](_0x23f18c,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x1fa187,0x16,_0x4ce735[0x7]),_0x476cf3=_0xd35357[_0x3ef1c5('0xb')](_0x4fee14,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x287c02,0x7,_0x300c0e[0x8]),_0x8e9c56=_0xd35357[_0x3ef1c5('0xb')](_0xce22c4,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x14765b,0xc,_0x110283[0x9]),_0x259d30=_0xd35357[_0x3ef1c5('0x65')](_0x1f4eaa,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x540540,0x11,_0x357915[0xa]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x12a')](_0x3b3727,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x27dd6a,0x16,_0x2782dc[0xb]),_0x476cf3=_0xd35357[_0x3ef1c5('0x12a')](_0xe6fec9,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x243fdd,0x7,_0x2aed82[0xc]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x12a')](_0x540d32,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x3563d4,0xc,_0x482c9a[0xd]),_0x259d30=_0xd35357[_0x3ef1c5('0x351')](_0x613705,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x180156,0x11,_0x3dd9fb[0xe]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x351')](_0x40fe2c,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x2cdf19,0x16,_0x5d4b21[0xf]),_0x476cf3=_0xd35357[_0x3ef1c5('0x2ca')](_0x19c3ad,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x246da2,0x5,_0x1a0ac3[0x10]),_0x8e9c56=_0xd35357['acjLy'](_0x48d5ee,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x45304e,0x9,_0x55a991[0x11]),_0x259d30=_0xd35357[_0x3ef1c5('0x2ca')](_0x212cc0,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x27dd6a,0xe,_0x309035[0x12]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x409')](_0x3b66ac,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x590fcf,0x14,_0x5e422e[0x13]),_0x476cf3=_0xd35357[_0x3ef1c5('0x155')](_0x41122d,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x161ca4,0x5,_0xbd9f2a[0x14]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x1e4')](_0x43b6b2,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x540540,0x9,_0x4f6d87[0x15]),_0x259d30=_0xd35357[_0x3ef1c5('0x1e4')](_0xe57502,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x2cdf19,0xe,_0x39c72a[0x16]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x1e4')](_0x383d0e,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0xb892ee,0x14,_0x1f9c4b[0x17]),_0x476cf3=_0xd35357[_0x3ef1c5('0x253')](_0x419c02,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x14765b,0x5,_0x254dea[0x18]),_0x8e9c56=_0xd35357['mYiKm'](_0xb5c2e2,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x180156,0x9,_0x4a128e[0x19]),_0x259d30=_0xd35357[_0x3ef1c5('0x2e2')](_0x59a35e,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x500e45,0xe,_0x5df542[0x1a]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x34c')](_0xce79d1,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x287c02,0x14,_0x49f803[0x1b]),_0x476cf3=_0xd35357[_0x3ef1c5('0x224')](_0x32c4d5,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x3563d4,0x5,_0x4f71d5[0x1c]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x1d5')](_0x44c4b9,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x28c79e,0x9,_0x3ebd0a[0x1d]),_0x259d30=_0xd35357['puBmQ'](_0x3560d5,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x1fa187,0xe,_0x420a93[0x1e]),_0x4a0cd9=_0xd35357['CEkPx'](_0x460e6d,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x243fdd,0x14,_0x160f01[0x1f]),_0x476cf3=_0xd35357['CEkPx'](_0x190521,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x161ca4,0x4,_0x4041f7[0x20]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x248')](_0x158d20,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x287c02,0xb,_0x4cc62f[0x21]),_0x259d30=_0xd35357[_0x3ef1c5('0x248')](_0x3b4432,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x27dd6a,0x10,_0x4d3025[0x22]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x248')](_0x44b2be,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x180156,0x17,_0x419712[0x23]),_0x476cf3=_0xd35357[_0x3ef1c5('0x37b')](_0x49eb55,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x246da2,0x4,_0x4549a0[0x24]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x430')](_0xcb644e,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0xb892ee,0xb,_0x15bd98[0x25]),_0x259d30=_0xd35357[_0x3ef1c5('0x30c')](_0xa6c442,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x1fa187,0x10,_0x3ec645[0x26]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x30c')](_0x492215,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x540540,0x17,_0x15b384[0x27]),_0x476cf3=_0xd35357['NhnrI'](_0x25061b,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x3563d4,0x4,_0x233e75[0x28]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x30f')](_0x51f69b,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x590fcf,0xb,_0x191b48[0x29]),_0x259d30=_0xd35357[_0x3ef1c5('0x30f')](_0xc63212,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x500e45,0x10,_0x22175a[0x2a]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x477')](_0x56f772,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x45304e,0x17,_0x46ff31[0x2b]),_0x476cf3=_0xd35357[_0x3ef1c5('0x477')](_0x3e5f20,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x14765b,0x4,_0x3831de[0x2c]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x101')](_0x7ad931,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x243fdd,0xb,_0x46099e[0x2d]),_0x259d30=_0xd35357['OovDx'](_0x4098a1,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x2cdf19,0x10,_0x1cda08[0x2e]),_0x4a0cd9=_0xd35357['aqiAp'](_0x2c01d1,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x28c79e,0x17,_0x1baab8[0x2f]),_0x476cf3=_0xd35357[_0x3ef1c5('0xb3')](_0x438a97,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x590fcf,0x6,_0x4bfc6c[0x30]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x3d6')](_0x3f2a20,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x1fa187,0xa,_0x141061[0x31]),_0x259d30=_0xd35357[_0x3ef1c5('0x3d6')](_0x4d8875,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x180156,0xf,_0x2d28f5[0x32]),_0x4a0cd9=_0xd35357['QRYpM'](_0x40d716,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x161ca4,0x15,_0x20f0cd[0x33]),_0x476cf3=_0xd35357[_0x3ef1c5('0x3b4')](_0x165823,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x243fdd,0x6,_0x182d32[0x34]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x37f')](_0x58625c,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x500e45,0xa,_0x865c24[0x35]),_0x259d30=_0xd35357[_0x3ef1c5('0x30e')](_0x3aa4a7,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x540540,0xf,_0x357375[0x36]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x30e')](_0xb76d4b,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x246da2,0x15,_0x51ebc5[0x37]),_0x476cf3=_0xd35357[_0x3ef1c5('0x30e')](_0x369b69,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x287c02,0x6,_0x108294[0x38]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x30e')](_0x1d01e8,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x2cdf19,0xa,_0x40a686[0x39]),_0x259d30=_0xd35357[_0x3ef1c5('0x30e')](_0x183bc3,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x45304e,0xf,_0x50e851[0x3a]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x30e')](_0xa09b79,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x3563d4,0x15,_0x41ac47[0x3b]),_0x476cf3=_0xd35357['LVLIm'](_0x223af3,_0x476cf3,_0x4a0cd9,_0x259d30,_0x8e9c56,_0xb892ee,0x6,_0xdf5605[0x3c]),_0x8e9c56=_0xd35357[_0x3ef1c5('0x30e')](_0x5da559,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x259d30,_0x27dd6a,0xa,_0x45a186[0x3d]),_0x259d30=_0xd35357[_0x3ef1c5('0x43a')](_0x18824e,_0x259d30,_0x8e9c56,_0x476cf3,_0x4a0cd9,_0x28c79e,0xf,_0x20277b[0x3e]),_0x4a0cd9=_0xd35357[_0x3ef1c5('0x43a')](_0x1c024f,_0x4a0cd9,_0x259d30,_0x8e9c56,_0x476cf3,_0x14765b,0x15,_0x1c2654[0x3f]);continue;case'4':_0x2c7e83[0x2]=_0xd35357['orQET'](_0xd35357[_0x3ef1c5('0x46a')](_0x2c7e83[0x2],_0x259d30),0x0);continue;case'5':_0x2c7e83[0x0]=_0xd35357[_0x3ef1c5('0x7c')](_0xd35357['kWfAg'](_0x2c7e83[0x0],_0x476cf3),0x0);continue;}break;}}}},'decrypt':function(_0x34a2b3,_0x40d073,_0x1f24d5,_0x530747){var _0x1216f1=_0x2be4df,_0x5684e0={'Bfzug':function(_0x97dbdd,_0x5a236a){return _0x25416c['SmpzZ'](_0x97dbdd,_0x5a236a);},'sCtjp':_0x25416c['PAkMF']};if(_0x25416c['UVfJN'](_0x25416c[_0x1216f1('0x15')],_0x25416c[_0x1216f1('0x126')]))return _0x530747=this[_0x1216f1('0x15c')][_0x1216f1('0x3ad')](_0x530747),_0x40d073=this[_0x1216f1('0x2eb')](_0x40d073,_0x530747['format']),_0x34a2b3[_0x1216f1('0x4a')](_0x1f24d5,_0x530747)[_0x1216f1('0x68')](_0x40d073[_0x1216f1('0x3db')]);else{function _0x3cafff(){var _0x166a3e=_0x1216f1,_0x3b9764={'rnlEN':function(_0x54b104,_0x466a24){var _0x517d4e=_0x4528;return _0x25416c[_0x517d4e('0xb6')](_0x54b104,_0x466a24);},'QvVjq':_0x25416c[_0x166a3e('0x1a1')]};return{'encrypt':function(_0xa4db7e,_0x5dd89f,_0x5eb1d7){var _0x13348d=_0x166a3e;return(_0x3b9764[_0x13348d('0x3b6')](_0x3b9764[_0x13348d('0x1bb')],typeof _0x5dd89f)?_0x528122:_0x4eb84a)[_0x13348d('0x276')](_0x109050,_0xa4db7e,_0x5dd89f,_0x5eb1d7);},'decrypt':function(_0x787fe5,_0x1b1e9c,_0xe61dd8){var _0x14b627=_0x166a3e;return(_0x5684e0['Bfzug'](_0x5684e0[_0x14b627('0x16b')],typeof _0x1b1e9c)?_0x59b689:_0x193ab0)[_0x14b627('0x313')](_0x2793ab,_0x787fe5,_0x1b1e9c,_0xe61dd8);}};}}},'_parse':function(_0x5e3899,_0x157073){var _0x3dc602=_0x2be4df,_0x55c4f4={'zNOiX':function(_0x2e9ae2,_0x2833fa){var _0x3e54d9=_0x4528;return _0x25416c[_0x3e54d9('0xb6')](_0x2e9ae2,_0x2833fa);},'ROufJ':_0x25416c[_0x3dc602('0x1a1')]};if(_0x25416c[_0x3dc602('0x8')](_0x25416c[_0x3dc602('0x2d3')],_0x25416c[_0x3dc602('0xc0')]))return _0x25416c[_0x3dc602('0xdd')](_0x25416c[_0x3dc602('0x1a1')],typeof _0x5e3899)?_0x157073[_0x3dc602('0x316')](_0x5e3899,this):_0x5e3899;else{function _0x492542(){var _0x1b3888=_0x3dc602;return(_0x55c4f4['zNOiX'](_0x55c4f4['ROufJ'],typeof _0x21db9d)?_0x4f8c04:_0x357bb5)[_0x1b3888('0x276')](_0x124e00,_0x155d9f,_0x3ad509,_0x769589);}}}}),_0x3c9886=(_0x3c9886[_0x2be4df('0x1ff')]={})[_0x2be4df('0xf4')]={'execute':function(_0x3c1613,_0x11fb23,_0x12ef08,_0x28f744){var _0x594eee=_0x2be4df;if(_0x25416c[_0x594eee('0x444')](_0x25416c[_0x594eee('0x3f1')],_0x25416c['bFzFP'])){var _0x3878dc=_0x25416c[_0x594eee('0x51')]['split']('|'),_0x579202=0x0;while(!![]){switch(_0x3878dc[_0x579202++]){case'0':_0x3c1613=_0x2c9441[_0x594eee('0x286')]({'keySize':_0x25416c[_0x594eee('0x2c2')](_0x11fb23,_0x12ef08)})[_0x594eee('0x3a7')](_0x3c1613,_0x28f744);continue;case'1':_0x12ef08=_0x1f6dde[_0x594eee('0x286')](_0x3c1613['words']['slice'](_0x11fb23),_0x25416c[_0x594eee('0x1b4')](0x4,_0x12ef08));continue;case'2':return _0x438f09[_0x594eee('0x286')]({'key':_0x3c1613,'iv':_0x12ef08,'salt':_0x28f744});case'3':_0x3c1613[_0x594eee('0xbe')]=_0x25416c[_0x594eee('0x299')](0x4,_0x11fb23);continue;case'4':_0x28f744||(_0x28f744=_0x1f6dde[_0x594eee('0x7f')](0x8));continue;}break;}}else{function _0x4eb33e(){var _0x240a60=_0x594eee;this[_0x240a60('0xe8')]=new _0x296a09[(_0x240a60('0x300'))](),this[_0x240a60('0x73')]=0x0;}}}},_0x27ed10=_0x114fca['PasswordBasedCipher']=_0x3aaab9[_0x2be4df('0x3ad')]({'cfg':_0x3aaab9[_0x2be4df('0x15c')][_0x2be4df('0x3ad')]({'kdf':_0x3c9886}),'encrypt':function(_0x33de76,_0x336a7e,_0x3d2551,_0x1f68cd){var _0x2c861b=_0x2be4df;if(_0x25416c['pzbjm'](_0x25416c[_0x2c861b('0x139')],_0x25416c[_0x2c861b('0x143')])){var _0x5b1580=_0x25416c[_0x2c861b('0x114')][_0x2c861b('0x2f8')]('|'),_0x1000ab=0x0;while(!![]){switch(_0x5b1580[_0x1000ab++]){case'0':_0x33de76[_0x2c861b('0x46')](_0x3d2551);continue;case'1':_0x1f68cd['iv']=_0x3d2551['iv'];continue;case'2':_0x33de76=_0x3aaab9[_0x2c861b('0x276')]['call'](this,_0x33de76,_0x336a7e,_0x3d2551['key'],_0x1f68cd);continue;case'3':return _0x33de76;case'4':_0x3d2551=_0x1f68cd['kdf'][_0x2c861b('0x1ca')](_0x3d2551,_0x33de76['keySize'],_0x33de76['ivSize']);continue;case'5':_0x1f68cd=this[_0x2c861b('0x15c')]['extend'](_0x1f68cd);continue;}break;}}else{function _0x5d7205(){var _0x19593d=_0x2c861b;_0x25416c[_0x19593d('0xc8')](_0x25416c[_0x19593d('0x1a1')],typeof _0x5cfa4a)&&(_0x3b834a=_0x2563c2['parse'](_0x23c65c)),this['_data'][_0x19593d('0x3b2')](_0x318701),this[_0x19593d('0x73')]+=_0x41519f[_0x19593d('0xbe')];}}},'decrypt':function(_0x509924,_0x406841,_0x3c5496,_0x1e5363){var _0x29c6b4=_0x2be4df;if(_0x25416c[_0x29c6b4('0x76')](_0x25416c['MkHTk'],_0x25416c[_0x29c6b4('0x18e')])){function _0x28fa9c(){var _0x2a85c2=_0x29c6b4;return this['Decryptor'][_0x2a85c2('0x286')](_0x300f04,_0xe131de);}}else{var _0xe3ba37=_0x25416c[_0x29c6b4('0x1b')][_0x29c6b4('0x2f8')]('|'),_0x5208c2=0x0;while(!![]){switch(_0xe3ba37[_0x5208c2++]){case'0':_0x1e5363['iv']=_0x3c5496['iv'];continue;case'1':return _0x3aaab9[_0x29c6b4('0x313')][_0x29c6b4('0x1e')](this,_0x509924,_0x406841,_0x3c5496[_0x29c6b4('0x219')],_0x1e5363);case'2':_0x1e5363=this[_0x29c6b4('0x15c')][_0x29c6b4('0x3ad')](_0x1e5363);continue;case'3':_0x406841=this[_0x29c6b4('0x2eb')](_0x406841,_0x1e5363[_0x29c6b4('0x192')]);continue;case'4':_0x3c5496=_0x1e5363[_0x29c6b4('0x1ff')]['execute'](_0x3c5496,_0x509924[_0x29c6b4('0x464')],_0x509924[_0x29c6b4('0x22b')],_0x406841['salt']);continue;}break;}}}});}(),function(){var _0x112bc9=_0xe45236,_0x21040b={'YQDHQ':function(_0x22f822,_0x488f36){return _0x22f822===_0x488f36;},'fKQzx':_0x112bc9('0x343'),'fIEAV':_0x112bc9('0x1b0'),'RrpAE':function(_0x46c720,_0x3f9019){return _0x46c720/_0x3f9019;},'xqDZh':function(_0x452e23,_0x162bf8){return _0x452e23*_0x162bf8;},'SbzJL':function(_0x6b3066,_0x338656){return _0x6b3066+_0x338656;},'zOyQK':function(_0x48aba6,_0x4e57cd){return _0x48aba6+_0x4e57cd;},'PjPWv':function(_0x229aa1,_0x48b916){return _0x229aa1<_0x48b916;},'wTulx':function(_0x810c96,_0xcdfa1a){return _0x810c96!==_0xcdfa1a;},'vxByO':'ovemP','YQfZY':_0x112bc9('0x35e'),'WhPoL':function(_0x5341cc,_0x426091){return _0x5341cc-_0x426091;},'gDvSS':function(_0x1f4acd,_0x5a12b6){return _0x1f4acd%_0x5a12b6;},'FhaYK':function(_0x2eb347,_0x5b29b2){return _0x2eb347==_0x5b29b2;},'fYrFE':function(_0x465608,_0x51385c){return _0x465608%_0x51385c;},'VghEw':function(_0x19350d,_0x124fa2){return _0x19350d|_0x124fa2;},'NtPvX':function(_0x474ca2,_0x1dc1f4){return _0x474ca2|_0x1dc1f4;},'xwlAH':function(_0x4de084,_0x394518){return _0x4de084|_0x394518;},'RyfUC':function(_0x3d971e,_0x2ef7fc){return _0x3d971e<<_0x2ef7fc;},'tbVmm':function(_0x50ae78,_0x19265b){return _0x50ae78>>>_0x19265b;},'evLLm':function(_0x4c82da,_0x3eaa81){return _0x4c82da<<_0x3eaa81;},'kPhjx':function(_0x1dd4fa,_0x9301e0){return _0x1dd4fa&_0x9301e0;},'jlpmn':function(_0x4273a0,_0x192e14){return _0x4273a0>>>_0x192e14;},'aWJcY':function(_0x1be116,_0x1b7576){return _0x1be116<<_0x1b7576;},'oyCFv':function(_0x52e9de,_0xb77240){return _0x52e9de&_0xb77240;},'enDzi':function(_0x46a00d,_0x3d6e96){return _0x46a00d&_0x3d6e96;},'VYQPL':function(_0x4bf738,_0x2c519f){return _0x4bf738|_0x2c519f;},'MlEJM':function(_0x1738f3,_0x3c4141){return _0x1738f3<<_0x3c4141;},'GjVgk':function(_0xb8c7b6,_0x2a0ba9){return _0xb8c7b6|_0x2a0ba9;},'kClzy':function(_0x4b326d,_0x63ef3c){return _0x4b326d>>>_0x63ef3c;},'EgaJR':function(_0x1c75eb,_0x2240b9){return _0x1c75eb>>>_0x2240b9;},'cAduK':function(_0x48990e,_0x424c5c){return _0x48990e&_0x424c5c;},'kaCWk':function(_0x52fe8e,_0x1111c9){return _0x52fe8e|_0x1111c9;},'omAyC':function(_0x4a5e28,_0x773713){return _0x4a5e28/_0x773713;},'WNjnC':function(_0x2924b7,_0x5e3cda){return _0x2924b7^_0x5e3cda;},'OuLFK':function(_0x42170b,_0x171f6c){return _0x42170b-_0x171f6c;},'zziuE':function(_0x35ea97,_0x2f6208){return _0x35ea97-_0x2f6208;},'YpuUw':function(_0x257217,_0x4ae654){return _0x257217-_0x4ae654;},'zKVIY':function(_0x52f11e,_0x4e2282){return _0x52f11e>_0x4e2282;},'XIhPa':function(_0x166c02,_0x1f342d){return _0x166c02>=_0x1f342d;},'WDKfM':function(_0x1441b9,_0x4b52eb){return _0x1441b9^_0x4b52eb;},'AIGVE':function(_0x480076,_0x3190da){return _0x480076&_0x3190da;},'LslSL':function(_0x51adf2,_0x5c24b7){return _0x51adf2&_0x5c24b7;},'rFheW':function(_0x13683f,_0x1679d0){return _0x13683f(_0x1679d0);},'REbih':function(_0x52f370,_0x303fe6){return _0x52f370(_0x303fe6);},'evRWz':function(_0x13088d,_0x51baef){return _0x13088d===_0x51baef;},'sNruo':'sFbKz','KAfyk':function(_0x3cff4c,_0x59a77a){return _0x3cff4c-_0x59a77a;},'cXXmR':function(_0x5ea3ba,_0x47001d){return _0x5ea3ba%_0x47001d;},'SVFgg':function(_0x41554d,_0x55ab27){return _0x41554d<_0x55ab27;},'IwWcY':function(_0xf5815b,_0x4dc2da){return _0xf5815b==_0x4dc2da;},'rBIul':function(_0x28f97d,_0x310770){return _0x28f97d%_0x310770;},'lgjlL':function(_0x396e30,_0x413049){return _0x396e30<<_0x413049;},'hOuXQ':function(_0x640cf9,_0x4c176f){return _0x640cf9&_0x4c176f;},'goEZd':function(_0x150701,_0x2f28a4){return _0x150701|_0x2f28a4;},'pqsrq':function(_0x54e09e,_0x351ebb){return _0x54e09e<<_0x351ebb;},'wOAkW':function(_0x398138,_0x36ed24){return _0x398138|_0x36ed24;},'ndDGf':function(_0x28cdc1,_0x1aa773){return _0x28cdc1|_0x1aa773;},'BBtVu':function(_0x53a533,_0x34d4db){return _0x53a533<<_0x34d4db;},'jIJYj':function(_0x4f398f,_0x55f2da){return _0x4f398f>>>_0x55f2da;},'ezjFY':function(_0x258a31,_0x1138cf){return _0x258a31<<_0x1138cf;},'aXRWj':function(_0x2221f2,_0x317043){return _0x2221f2>>>_0x317043;},'vjzji':function(_0x32a806,_0x3c2388){return _0x32a806^_0x3c2388;},'cpgQJ':function(_0x12b4e4,_0x501dff){return _0x12b4e4-_0x501dff;},'tJzAo':function(_0x3a6c9b,_0x413d4e){return _0x3a6c9b!==_0x413d4e;},'mcdvE':'GHVop','CtmJn':'3|2|4|0|6|1|5','KasfC':function(_0x1dfdbe,_0x26ae4c){return _0x1dfdbe+_0x26ae4c;},'BTPju':function(_0x4dc5ec,_0x4e648c){return _0x4dc5ec+_0x4e648c;},'QRdqD':function(_0x5d3ab7,_0x40ab74){return _0x5d3ab7+_0x40ab74;},'tpXpB':function(_0x1edde7,_0x1a7899){return _0x1edde7+_0x1a7899;},'wGkCu':function(_0x57d04c,_0x2027b2){return _0x57d04c&_0x2027b2;},'BjjvI':function(_0x56e52a,_0x5a8a1a){return _0x56e52a|_0x5a8a1a;},'CSGZd':function(_0x4f5a4e,_0x2e0706){return _0x4f5a4e<<_0x2e0706;},'AmodD':function(_0x34d734,_0x2d2384){return _0x34d734>>>_0x2d2384;},'WSero':function(_0x10c6f9,_0x47e6b5){return _0x10c6f9>>>_0x47e6b5;},'ibzMk':function(_0x5a68de,_0x3d1144){return _0x5a68de===_0x3d1144;},'PHqEZ':_0x112bc9('0x2b9'),'BtYMH':_0x112bc9('0x220'),'qSNNN':function(_0x404b36,_0x310a6c){return _0x404b36^_0x310a6c;},'dHgsN':function(_0x10eda7,_0x3c950b){return _0x10eda7^_0x3c950b;},'MkTCS':function(_0x9b5da,_0x348469){return _0x9b5da^_0x348469;},'ZXLxQ':function(_0x5a47d7,_0x2f53f6){return _0x5a47d7+_0x2f53f6;},'EuVhy':function(_0x49e9a2,_0x39c91d){return _0x49e9a2^_0x39c91d;},'qKTwt':function(_0x5d347d,_0x38bc28){return _0x5d347d^_0x38bc28;},'aKFSi':function(_0x5a8bae,_0x2c04da){return _0x5a8bae&_0x2c04da;},'XlfQC':function(_0x417b3b,_0x4c987b){return _0x417b3b>>>_0x4c987b;},'BnlVl':function(_0x592af2,_0x320acd){return _0x592af2^_0x320acd;},'ngAaw':function(_0xafa44f,_0x5078e6){return _0xafa44f^_0x5078e6;},'bZipH':function(_0x1a1844,_0xa19177){return _0x1a1844>>>_0xa19177;},'aGuXf':function(_0x6cbe4e,_0x2d4986){return _0x6cbe4e>>>_0x2d4986;},'zTsat':function(_0x180193,_0x548f77){return _0x180193&_0x548f77;},'KSuaQ':function(_0x34c233,_0x16d916){return _0x34c233^_0x16d916;},'oiVou':function(_0x38e737,_0x4e4302){return _0x38e737^_0x4e4302;},'Ezpup':function(_0x40b74e,_0x203c1a){return _0x40b74e>>>_0x203c1a;},'uLMdA':function(_0x3606e6,_0x3e302c){return _0x3606e6^_0x3e302c;},'rxkim':function(_0x3310ee,_0x3810e6){return _0x3310ee^_0x3810e6;},'MhSrN':function(_0x62b545,_0x3024e0){return _0x62b545&_0x3024e0;},'xgWWx':function(_0x26bace,_0x537c54){return _0x26bace>>>_0x537c54;},'sLSyP':function(_0x3fa685,_0x4f2653){return _0x3fa685&_0x4f2653;},'Ihpik':function(_0x4135c6,_0x28eff4){return _0x4135c6>>>_0x28eff4;},'EIaJi':function(_0x2de329,_0x17530d){return _0x2de329|_0x17530d;},'WDCII':function(_0x162d64,_0x351d4c){return _0x162d64<<_0x351d4c;},'RcZrS':function(_0x27dd34,_0x3e7613){return _0x27dd34>>>_0x3e7613;},'GPZoL':function(_0x533ae5,_0x1759a4){return _0x533ae5>>>_0x1759a4;},'SvoxG':function(_0x1508fc,_0x30a0ad){return _0x1508fc^_0x30a0ad;},'zDkOr':function(_0xa3e309,_0x816272){return _0xa3e309|_0x816272;},'bIbrk':function(_0x38ab71,_0x5eb820){return _0x38ab71|_0x5eb820;},'dOdEU':function(_0x44d9ed,_0x2a795e){return _0x44d9ed<<_0x2a795e;},'nEunB':function(_0x4c6ec9,_0x53de5e){return _0x4c6ec9>>>_0x53de5e;},'WZLkp':function(_0x263432,_0x2f12bd){return _0x263432+_0x2f12bd;},'ryNDd':function(_0x16256c,_0x1d7108){return _0x16256c^_0x1d7108;},'IppVj':function(_0x5b8c41,_0x38a3f6){return _0x5b8c41|_0x38a3f6;},'GHtOI':function(_0x5558b2,_0x1a64df){return _0x5558b2|_0x1a64df;},'bvhZN':function(_0x513f35,_0x1d0d89){return _0x513f35<<_0x1d0d89;},'jxfpd':function(_0x321b92,_0x361e31){return _0x321b92>>>_0x361e31;},'lDGXH':function(_0xb69cda,_0x3851f2){return _0xb69cda&_0x3851f2;},'yOTLd':function(_0xa510f,_0xec5ea0){return _0xa510f>>>_0xec5ea0;},'bpoNj':function(_0x15dcd4,_0xc2f969){return _0x15dcd4>>>_0xc2f969;},'UOCRz':function(_0x325d56,_0xaa5b3a){return _0x325d56&_0xaa5b3a;},'CRnnh':function(_0x480017,_0x3b470a){return _0x480017|_0x3b470a;},'AKOvc':function(_0x10e5db,_0x14411f){return _0x10e5db|_0x14411f;},'wnQPo':function(_0x2def13,_0x4ae789){return _0x2def13>>>_0x4ae789;},'PQken':function(_0x9f52d5,_0x1aea2b){return _0x9f52d5>>>_0x1aea2b;},'DHHst':function(_0x14f5eb,_0x3ad64a){return _0x14f5eb>>>_0x3ad64a;},'Ekssh':function(_0x407165,_0x28349d){return _0x407165&_0x28349d;},'uTirf':function(_0x3f2c08,_0x21bd3d){return _0x3f2c08>_0x21bd3d;},'MZLnz':_0x112bc9('0x318'),'OwIfH':_0x112bc9('0x6f'),'FtfKx':_0x112bc9('0x429'),'kVvjS':function(_0x36a5b9,_0x53c0cd){return _0x36a5b9^_0x53c0cd;},'aqKMs':function(_0x4205b7,_0x4e8732){return _0x4205b7^_0x4e8732;},'GiKpN':function(_0x155641,_0x300c46){return _0x155641*_0x300c46;},'Yqafm':function(_0x3d4038,_0x37bdc0){return _0x3d4038*_0x37bdc0;},'qHgzA':function(_0x5ab2c3,_0x31a6de){return _0x5ab2c3*_0x31a6de;},'xdyZM':function(_0x218eba,_0x29c299){return _0x218eba*_0x29c299;},'ZFdgr':function(_0x339e91,_0x48ed1b){return _0x339e91|_0x48ed1b;},'nToph':function(_0x49a6f9,_0x5238be){return _0x49a6f9<<_0x5238be;},'GonOL':function(_0x24aebd,_0x2d8a85){return _0x24aebd>>>_0x2d8a85;},'Jpcca':function(_0x58aab1,_0x8b8ff2){return _0x58aab1|_0x8b8ff2;},'Ijqli':function(_0x190f15,_0x30c8c9){return _0x190f15<<_0x30c8c9;},'QxKBj':function(_0x1af1ab,_0x5f2513){return _0x1af1ab>>>_0x5f2513;},'eUnWK':function(_0x4be822,_0x2cbaea){return _0x4be822^_0x2cbaea;},'wanij':function(_0x509260,_0x5269e6){return _0x509260<<_0x5269e6;},'BcPqz':function(_0x294bae,_0x2a3de0){return _0x294bae<<_0x2a3de0;},'aYcqa':function(_0x1c5c53,_0x3a13d5){return _0x1c5c53^_0x3a13d5;},'HMpPA':function(_0x20c089,_0x50feaf){return _0x20c089^_0x50feaf;},'ApHFS':function(_0x4d338c,_0x21da3c){return _0x4d338c&_0x21da3c;},'ruNsI':function(_0x1adf42,_0x4d494e){return _0x1adf42^_0x4d494e;},'ukKyz':function(_0xe34834,_0x286c14){return _0xe34834^_0x286c14;},'iWXzr':function(_0x5ad17f,_0x86f663){return _0x5ad17f|_0x86f663;},'mblYk':function(_0x549dc2,_0x1a33e7){return _0x549dc2<<_0x1a33e7;},'ETEel':function(_0xce76ed,_0x6b4f03){return _0xce76ed>>>_0x6b4f03;},'IorKy':function(_0x2a3ad7,_0x5d9668){return _0x2a3ad7<<_0x5d9668;}};for(var _0x3a91c3=CryptoJS,_0x28f1fa=_0x3a91c3[_0x112bc9('0x246')][_0x112bc9('0x8a')],_0x1bc1cf=_0x3a91c3[_0x112bc9('0x329')],_0x3530cf=[],_0x52ddeb=[],_0xcc7656=[],_0x13a6be=[],_0x147c55=[],_0x4b6b6e=[],_0xdc2330=[],_0x5f399c=[],_0x45e9e8=[],_0x1a8d1e=[],_0x59de18=[],_0x7b4d37=0x0;_0x21040b[_0x112bc9('0x19f')](0x100,_0x7b4d37);_0x7b4d37++)_0x59de18[_0x7b4d37]=_0x21040b['uTirf'](0x80,_0x7b4d37)?_0x21040b['bvhZN'](_0x7b4d37,0x1):_0x21040b[_0x112bc9('0x2c1')](_0x21040b['bvhZN'](_0x7b4d37,0x1),0x11b);for(var _0x5b0b15=0x0,_0xf539cb=0x0,_0x7b4d37=0x0;_0x21040b[_0x112bc9('0x180')](0x100,_0x7b4d37);_0x7b4d37++){if(_0x21040b[_0x112bc9('0x32f')](_0x21040b[_0x112bc9('0x2ff')],_0x21040b[_0x112bc9('0x3bf')])){function _0x1285f9(){var _0xe45a16=_0x112bc9;return new _0x173a3e[(_0xe45a16('0x338'))]['init'](_0x5c8fe6,_0x135a7e)[_0xe45a16('0x68')](_0x49a715);}}else{var _0x3b8e1f=_0x21040b[_0x112bc9('0x1a3')][_0x112bc9('0x2f8')]('|'),_0x1cb3f0=0x0;while(!![]){switch(_0x3b8e1f[_0x1cb3f0++]){case'0':_0x4b6b6e[_0x5b0b15]=_0x9d8e51;continue;case'1':_0x3530cf[_0x5b0b15]=_0x38f269;continue;case'2':_0x9d8e51=_0x21040b['ryNDd'](_0x21040b[_0x112bc9('0x232')](_0x21040b[_0x112bc9('0x60')](_0x21040b[_0x112bc9('0x1c2')](0x1010101,_0x52f2d8),_0x21040b[_0x112bc9('0x364')](0x10001,_0x3d40e5)),_0x21040b[_0x112bc9('0x364')](0x101,_0x1e39e5)),_0x21040b[_0x112bc9('0x2c4')](0x1010100,_0x5b0b15));continue;case'3':_0xdc2330[_0x38f269]=_0x21040b[_0x112bc9('0x2ce')](_0x21040b[_0x112bc9('0x18b')](_0x9d8e51,0x18),_0x21040b['DHHst'](_0x9d8e51,0x8));continue;case'4':var _0x1e39e5=_0x59de18[_0x5b0b15],_0x3d40e5=_0x59de18[_0x1e39e5],_0x52f2d8=_0x59de18[_0x3d40e5],_0x9d8e51=_0x21040b['aqKMs'](_0x21040b[_0x112bc9('0x1c1')](0x101,_0x59de18[_0x38f269]),_0x21040b[_0x112bc9('0x3c1')](0x1010100,_0x38f269));continue;case'5':_0x5f399c[_0x38f269]=_0x21040b[_0x112bc9('0x103')](_0x21040b[_0x112bc9('0x327')](_0x9d8e51,0x10),_0x21040b[_0x112bc9('0x2b4')](_0x9d8e51,0x10));continue;case'6':_0xcc7656[_0x5b0b15]=_0x21040b[_0x112bc9('0x103')](_0x21040b['nToph'](_0x9d8e51,0x18),_0x21040b[_0x112bc9('0x2b4')](_0x9d8e51,0x8));continue;case'7':_0x45e9e8[_0x38f269]=_0x21040b[_0x112bc9('0x27b')](_0x21040b['Ijqli'](_0x9d8e51,0x8),_0x21040b[_0x112bc9('0x194')](_0x9d8e51,0x18));continue;case'8':var _0x38f269=_0x21040b[_0x112bc9('0x483')](_0x21040b[_0x112bc9('0x483')](_0x21040b['eUnWK'](_0x21040b[_0x112bc9('0x483')](_0xf539cb,_0x21040b[_0x112bc9('0x21f')](_0xf539cb,0x1)),_0x21040b['wanij'](_0xf539cb,0x2)),_0x21040b[_0x112bc9('0x27f')](_0xf539cb,0x3)),_0x21040b[_0x112bc9('0x27f')](_0xf539cb,0x4)),_0x38f269=_0x21040b[_0x112bc9('0x359')](_0x21040b[_0x112bc9('0x50')](_0x21040b[_0x112bc9('0x194')](_0x38f269,0x8),_0x21040b['ApHFS'](_0x38f269,0xff)),0x63);continue;case'9':_0x5b0b15?(_0x5b0b15=_0x21040b[_0x112bc9('0x1a6')](_0x1e39e5,_0x59de18[_0x59de18[_0x59de18[_0x21040b[_0x112bc9('0x2ab')](_0x52f2d8,_0x1e39e5)]]]),_0xf539cb^=_0x59de18[_0x59de18[_0xf539cb]]):_0x5b0b15=_0xf539cb=0x1;continue;case'10':_0x1a8d1e[_0x38f269]=_0x9d8e51;continue;case'11':_0x52ddeb[_0x38f269]=_0x5b0b15;continue;case'12':_0x147c55[_0x5b0b15]=_0x21040b['iWXzr'](_0x21040b[_0x112bc9('0x390')](_0x9d8e51,0x8),_0x21040b[_0x112bc9('0x453')](_0x9d8e51,0x18));continue;case'13':_0x13a6be[_0x5b0b15]=_0x21040b[_0x112bc9('0x1b6')](_0x21040b[_0x112bc9('0x434')](_0x9d8e51,0x10),_0x21040b[_0x112bc9('0x453')](_0x9d8e51,0x10));continue;}break;}}}var _0x535043=[0x0,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x1b,0x36],_0x1bc1cf=_0x1bc1cf['AES']=_0x28f1fa[_0x112bc9('0x3ad')]({'_doReset':function(){var _0x37dc8e=_0x112bc9;if(_0x21040b[_0x37dc8e('0x1d8')](_0x21040b['fKQzx'],_0x21040b[_0x37dc8e('0x7')])){function _0x3bd41d(){var _0x3a8c0d=_0x37dc8e;return this[_0x3a8c0d('0x286')](this[_0x3a8c0d('0xb1')],_0x6f5715,_0x3ce059);}}else{for(var _0x5e5112=this[_0x37dc8e('0x1cf')],_0x386868=_0x5e5112[_0x37dc8e('0x431')],_0x46bebe=_0x21040b[_0x37dc8e('0x142')](_0x5e5112[_0x37dc8e('0xbe')],0x4),_0x5e5112=_0x21040b[_0x37dc8e('0x1c2')](0x4,_0x21040b['SbzJL'](this[_0x37dc8e('0x3ff')]=_0x21040b['zOyQK'](_0x46bebe,0x6),0x1)),_0x24b7a0=this[_0x37dc8e('0x2bc')]=[],_0x760f8e=0x0;_0x21040b['PjPWv'](_0x760f8e,_0x5e5112);_0x760f8e++)if(_0x21040b[_0x37dc8e('0x411')](_0x760f8e,_0x46bebe))_0x24b7a0[_0x760f8e]=_0x386868[_0x760f8e];else{if(_0x21040b[_0x37dc8e('0x237')](_0x21040b[_0x37dc8e('0x5f')],_0x21040b[_0x37dc8e('0x1ae')])){var _0x3b9dee=_0x24b7a0[_0x21040b[_0x37dc8e('0x274')](_0x760f8e,0x1)];_0x21040b[_0x37dc8e('0x226')](_0x760f8e,_0x46bebe)?_0x21040b[_0x37dc8e('0x411')](0x6,_0x46bebe)&&_0x21040b[_0x37dc8e('0x475')](0x4,_0x21040b['fYrFE'](_0x760f8e,_0x46bebe))&&(_0x3b9dee=_0x21040b[_0x37dc8e('0x422')](_0x21040b[_0x37dc8e('0x41b')](_0x21040b[_0x37dc8e('0x2c7')](_0x21040b[_0x37dc8e('0x1cd')](_0x3530cf[_0x21040b[_0x37dc8e('0x349')](_0x3b9dee,0x18)],0x18),_0x21040b[_0x37dc8e('0x1c6')](_0x3530cf[_0x21040b[_0x37dc8e('0xd')](_0x21040b[_0x37dc8e('0x3d7')](_0x3b9dee,0x10),0xff)],0x10)),_0x21040b[_0x37dc8e('0x2dd')](_0x3530cf[_0x21040b[_0x37dc8e('0x2a9')](_0x21040b[_0x37dc8e('0x3d7')](_0x3b9dee,0x8),0xff)],0x8)),_0x3530cf[_0x21040b[_0x37dc8e('0x480')](_0x3b9dee,0xff)])):(_0x3b9dee=_0x21040b[_0x37dc8e('0x2ac')](_0x21040b[_0x37dc8e('0x2b2')](_0x3b9dee,0x8),_0x21040b[_0x37dc8e('0x3d7')](_0x3b9dee,0x18)),_0x3b9dee=_0x21040b['VYQPL'](_0x21040b[_0x37dc8e('0x3d5')](_0x21040b[_0x37dc8e('0x3d5')](_0x21040b['MlEJM'](_0x3530cf[_0x21040b['kClzy'](_0x3b9dee,0x18)],0x18),_0x21040b[_0x37dc8e('0x2b2')](_0x3530cf[_0x21040b[_0x37dc8e('0x480')](_0x21040b[_0x37dc8e('0x35f')](_0x3b9dee,0x10),0xff)],0x10)),_0x21040b['MlEJM'](_0x3530cf[_0x21040b[_0x37dc8e('0x378')](_0x21040b[_0x37dc8e('0x35f')](_0x3b9dee,0x8),0xff)],0x8)),_0x3530cf[_0x21040b[_0x37dc8e('0x378')](_0x3b9dee,0xff)]),_0x3b9dee^=_0x21040b[_0x37dc8e('0x2b2')](_0x535043[_0x21040b[_0x37dc8e('0x319')](_0x21040b[_0x37dc8e('0x448')](_0x760f8e,_0x46bebe),0x0)],0x18)),_0x24b7a0[_0x760f8e]=_0x21040b[_0x37dc8e('0x57')](_0x24b7a0[_0x21040b[_0x37dc8e('0xad')](_0x760f8e,_0x46bebe)],_0x3b9dee);}else{function _0x14944c(){var _0x3f42ce=_0x37dc8e;return this[_0x3f42ce('0x286')](this[_0x3f42ce('0x15e')],_0x35a440,_0x56fdf9);}}}_0x386868=this[_0x37dc8e('0x410')]=[];for(_0x46bebe=0x0;_0x21040b['PjPWv'](_0x46bebe,_0x5e5112);_0x46bebe++)_0x760f8e=_0x21040b['zziuE'](_0x5e5112,_0x46bebe),_0x3b9dee=_0x21040b['fYrFE'](_0x46bebe,0x4)?_0x24b7a0[_0x760f8e]:_0x24b7a0[_0x21040b['YpuUw'](_0x760f8e,0x4)],_0x386868[_0x46bebe]=_0x21040b[_0x37dc8e('0x19f')](0x4,_0x46bebe)||_0x21040b['XIhPa'](0x4,_0x760f8e)?_0x3b9dee:_0x21040b[_0x37dc8e('0x31')](_0x21040b['WDKfM'](_0x21040b['WDKfM'](_0xdc2330[_0x3530cf[_0x21040b[_0x37dc8e('0x35f')](_0x3b9dee,0x18)]],_0x5f399c[_0x3530cf[_0x21040b[_0x37dc8e('0x14f')](_0x21040b[_0x37dc8e('0x35f')](_0x3b9dee,0x10),0xff)]]),_0x45e9e8[_0x3530cf[_0x21040b[_0x37dc8e('0x3fe')](_0x21040b[_0x37dc8e('0x35f')](_0x3b9dee,0x8),0xff)]]),_0x1a8d1e[_0x3530cf[_0x21040b['LslSL'](_0x3b9dee,0xff)]]);}},'encryptBlock':function(_0x3d95ad,_0x25b68e){var _0x39e180=_0x112bc9;if(_0x21040b[_0x39e180('0x70')](_0x21040b[_0x39e180('0x255')],_0x21040b['sNruo']))this[_0x39e180('0x387')](_0x3d95ad,_0x25b68e,this[_0x39e180('0x2bc')],_0xcc7656,_0x13a6be,_0x147c55,_0x4b6b6e,_0x3530cf);else{function _0x5e98d3(){var _0x23d2d6=_0x39e180;return _0x21040b[_0x23d2d6('0x19a')](_0x332719,_0x21040b[_0x23d2d6('0x23c')](_0x8493e2,_0x2a19c7[_0x23d2d6('0x40e')](_0x58c6b8)));}}},'decryptBlock':function(_0x3e3908,_0x2d17ef){var _0x94b266=_0x112bc9;if(_0x21040b['tJzAo'](_0x21040b[_0x94b266('0x35a')],_0x21040b[_0x94b266('0x35a')])){function _0x444455(){var _0x226ea4=_0x94b266,_0x55b511=_0x484472[_0x21040b[_0x226ea4('0x10f')](_0x3d204b,0x1)];_0x21040b[_0x226ea4('0x1af')](_0xd9955b,_0x3b30ac)?_0x21040b[_0x226ea4('0x29f')](0x6,_0x59e58d)&&_0x21040b[_0x226ea4('0x1d2')](0x4,_0x21040b[_0x226ea4('0x1')](_0x56db0d,_0x173496))&&(_0x55b511=_0x21040b[_0x226ea4('0x319')](_0x21040b[_0x226ea4('0x319')](_0x21040b[_0x226ea4('0x319')](_0x21040b[_0x226ea4('0x2b2')](_0x1b0f53[_0x21040b[_0x226ea4('0x35f')](_0x55b511,0x18)],0x18),_0x21040b[_0x226ea4('0x2b2')](_0x192231[_0x21040b[_0x226ea4('0x3fe')](_0x21040b[_0x226ea4('0x35f')](_0x55b511,0x10),0xff)],0x10)),_0x21040b[_0x226ea4('0x398')](_0x4f75fe[_0x21040b[_0x226ea4('0x305')](_0x21040b[_0x226ea4('0x35f')](_0x55b511,0x8),0xff)],0x8)),_0x5859c3[_0x21040b[_0x226ea4('0x305')](_0x55b511,0xff)])):(_0x55b511=_0x21040b[_0x226ea4('0x370')](_0x21040b[_0x226ea4('0x445')](_0x55b511,0x8),_0x21040b[_0x226ea4('0x35f')](_0x55b511,0x18)),_0x55b511=_0x21040b[_0x226ea4('0x370')](_0x21040b[_0x226ea4('0x2e0')](_0x21040b[_0x226ea4('0x27')](_0x21040b[_0x226ea4('0x2e7')](_0x5b7115[_0x21040b[_0x226ea4('0x3c0')](_0x55b511,0x18)],0x18),_0x21040b[_0x226ea4('0x41c')](_0x19c0cc[_0x21040b[_0x226ea4('0x305')](_0x21040b[_0x226ea4('0x3c0')](_0x55b511,0x10),0xff)],0x10)),_0x21040b[_0x226ea4('0x41c')](_0x23171d[_0x21040b['hOuXQ'](_0x21040b[_0x226ea4('0x42e')](_0x55b511,0x8),0xff)],0x8)),_0x3b0b37[_0x21040b['hOuXQ'](_0x55b511,0xff)]),_0x55b511^=_0x21040b[_0x226ea4('0x41c')](_0x497a62[_0x21040b[_0x226ea4('0x27')](_0x21040b[_0x226ea4('0x448')](_0x4dac2a,_0xffc15d),0x0)],0x18)),_0x57b16e[_0x519e8f]=_0x21040b[_0x226ea4('0x2d4')](_0x5d6e27[_0x21040b['cpgQJ'](_0x447661,_0x4a37ef)],_0x55b511);}}else{var _0x493506=_0x21040b[_0x94b266('0xa3')][_0x94b266('0x2f8')]('|'),_0x1ef8c5=0x0;while(!![]){switch(_0x493506[_0x1ef8c5++]){case'0':this['_doCryptBlock'](_0x3e3908,_0x2d17ef,this[_0x94b266('0x410')],_0xdc2330,_0x5f399c,_0x45e9e8,_0x1a8d1e,_0x52ddeb);continue;case'1':_0x3e3908[_0x21040b[_0x94b266('0x367')](_0x2d17ef,0x1)]=_0x3e3908[_0x21040b['KasfC'](_0x2d17ef,0x3)];continue;case'2':_0x3e3908[_0x21040b[_0x94b266('0x3f9')](_0x2d17ef,0x1)]=_0x3e3908[_0x21040b['BTPju'](_0x2d17ef,0x3)];continue;case'3':var _0x32f052=_0x3e3908[_0x21040b['BTPju'](_0x2d17ef,0x1)];continue;case'4':_0x3e3908[_0x21040b['BTPju'](_0x2d17ef,0x3)]=_0x32f052;continue;case'5':_0x3e3908[_0x21040b[_0x94b266('0x3f9')](_0x2d17ef,0x3)]=_0x32f052;continue;case'6':_0x32f052=_0x3e3908[_0x21040b[_0x94b266('0x1aa')](_0x2d17ef,0x1)];continue;}break;}}},'_doCryptBlock':function(_0x30d277,_0x263a8f,_0xd79792,_0x2ccc2d,_0x3da125,_0x103482,_0x4748c5,_0x412d52){var _0x9dd105=_0x112bc9;if(_0x21040b[_0x9dd105('0x32f')](_0x21040b['PHqEZ'],_0x21040b[_0x9dd105('0x19c')])){var _0x191df2=_0x21040b[_0x9dd105('0xa9')]['split']('|'),_0x34fc2b=0x0;while(!![]){switch(_0x191df2[_0x34fc2b++]){case'0':for(var _0x15aa05=this[_0x9dd105('0x3ff')],_0x4aa919=_0x21040b[_0x9dd105('0x1d9')](_0x30d277[_0x263a8f],_0xd79792[0x0]),_0x279eb3=_0x21040b[_0x9dd105('0x1c0')](_0x30d277[_0x21040b[_0x9dd105('0x3ae')](_0x263a8f,0x1)],_0xd79792[0x1]),_0x583b10=_0x21040b[_0x9dd105('0x482')](_0x30d277[_0x21040b[_0x9dd105('0x3ae')](_0x263a8f,0x2)],_0xd79792[0x2]),_0x2dd0b1=_0x21040b[_0x9dd105('0x482')](_0x30d277[_0x21040b[_0x9dd105('0x99')](_0x263a8f,0x3)],_0xd79792[0x3]),_0x80410c=0x4,_0x5d7961=0x1;_0x21040b[_0x9dd105('0x29f')](_0x5d7961,_0x15aa05);_0x5d7961++)var _0x27156d=_0x21040b['MkTCS'](_0x21040b['MkTCS'](_0x21040b['EuVhy'](_0x21040b[_0x9dd105('0x3c2')](_0x2ccc2d[_0x21040b[_0x9dd105('0x1d4')](_0x4aa919,0x18)],_0x3da125[_0x21040b[_0x9dd105('0x3bd')](_0x21040b['WSero'](_0x279eb3,0x10),0xff)]),_0x103482[_0x21040b[_0x9dd105('0x3bd')](_0x21040b['XlfQC'](_0x583b10,0x8),0xff)]),_0x4748c5[_0x21040b[_0x9dd105('0x3bd')](_0x2dd0b1,0xff)]),_0xd79792[_0x80410c++]),_0x199a0e=_0x21040b[_0x9dd105('0x3c2')](_0x21040b[_0x9dd105('0x1ba')](_0x21040b['ngAaw'](_0x21040b[_0x9dd105('0x470')](_0x2ccc2d[_0x21040b['bZipH'](_0x279eb3,0x18)],_0x3da125[_0x21040b['aKFSi'](_0x21040b[_0x9dd105('0x12d')](_0x583b10,0x10),0xff)]),_0x103482[_0x21040b[_0x9dd105('0x3bd')](_0x21040b[_0x9dd105('0xc')](_0x2dd0b1,0x8),0xff)]),_0x4748c5[_0x21040b['zTsat'](_0x4aa919,0xff)]),_0xd79792[_0x80410c++]),_0x9b3eb1=_0x21040b[_0x9dd105('0x470')](_0x21040b[_0x9dd105('0x380')](_0x21040b[_0x9dd105('0x2be')](_0x21040b[_0x9dd105('0x2be')](_0x2ccc2d[_0x21040b[_0x9dd105('0xc')](_0x583b10,0x18)],_0x3da125[_0x21040b[_0x9dd105('0x326')](_0x21040b[_0x9dd105('0xc')](_0x2dd0b1,0x10),0xff)]),_0x103482[_0x21040b['zTsat'](_0x21040b[_0x9dd105('0x119')](_0x4aa919,0x8),0xff)]),_0x4748c5[_0x21040b[_0x9dd105('0x326')](_0x279eb3,0xff)]),_0xd79792[_0x80410c++]),_0x2dd0b1=_0x21040b['uLMdA'](_0x21040b[_0x9dd105('0xba')](_0x21040b[_0x9dd105('0xba')](_0x21040b[_0x9dd105('0xba')](_0x2ccc2d[_0x21040b[_0x9dd105('0x119')](_0x2dd0b1,0x18)],_0x3da125[_0x21040b[_0x9dd105('0x1e6')](_0x21040b[_0x9dd105('0x113')](_0x4aa919,0x10),0xff)]),_0x103482[_0x21040b[_0x9dd105('0xa7')](_0x21040b[_0x9dd105('0x344')](_0x279eb3,0x8),0xff)]),_0x4748c5[_0x21040b[_0x9dd105('0xa7')](_0x583b10,0xff)]),_0xd79792[_0x80410c++]),_0x4aa919=_0x27156d,_0x279eb3=_0x199a0e,_0x583b10=_0x9b3eb1;continue;case'1':_0x27156d=_0x21040b[_0x9dd105('0xba')](_0x21040b[_0x9dd105('0xd5')](_0x21040b[_0x9dd105('0xd5')](_0x21040b[_0x9dd105('0xd5')](_0x21040b[_0x9dd105('0x159')](_0x412d52[_0x21040b[_0x9dd105('0x344')](_0x4aa919,0x18)],0x18),_0x21040b[_0x9dd105('0x2c5')](_0x412d52[_0x21040b[_0x9dd105('0xa7')](_0x21040b['RcZrS'](_0x279eb3,0x10),0xff)],0x10)),_0x21040b['WDCII'](_0x412d52[_0x21040b[_0x9dd105('0xa7')](_0x21040b[_0x9dd105('0x385')](_0x583b10,0x8),0xff)],0x8)),_0x412d52[_0x21040b['sLSyP'](_0x2dd0b1,0xff)]),_0xd79792[_0x80410c++]);continue;case'2':_0x2dd0b1=_0x21040b[_0x9dd105('0x32')](_0x21040b[_0x9dd105('0x2dc')](_0x21040b['zDkOr'](_0x21040b[_0x9dd105('0x15d')](_0x21040b[_0x9dd105('0x3f7')](_0x412d52[_0x21040b[_0x9dd105('0x385')](_0x2dd0b1,0x18)],0x18),_0x21040b['dOdEU'](_0x412d52[_0x21040b[_0x9dd105('0xa7')](_0x21040b['nEunB'](_0x4aa919,0x10),0xff)],0x10)),_0x21040b['dOdEU'](_0x412d52[_0x21040b[_0x9dd105('0xa7')](_0x21040b[_0x9dd105('0x169')](_0x279eb3,0x8),0xff)],0x8)),_0x412d52[_0x21040b[_0x9dd105('0xa7')](_0x583b10,0xff)]),_0xd79792[_0x80410c++]);continue;case'3':_0x30d277[_0x21040b[_0x9dd105('0x3b')](_0x263a8f,0x1)]=_0x199a0e;continue;case'4':_0x30d277[_0x263a8f]=_0x27156d;continue;case'5':_0x30d277[_0x21040b[_0x9dd105('0x3b')](_0x263a8f,0x2)]=_0x9b3eb1;continue;case'6':_0x9b3eb1=_0x21040b[_0x9dd105('0x2c1')](_0x21040b['IppVj'](_0x21040b[_0x9dd105('0x21e')](_0x21040b[_0x9dd105('0x21e')](_0x21040b[_0x9dd105('0x18b')](_0x412d52[_0x21040b['jxfpd'](_0x583b10,0x18)],0x18),_0x21040b[_0x9dd105('0x18b')](_0x412d52[_0x21040b[_0x9dd105('0x2f0')](_0x21040b[_0x9dd105('0x19e')](_0x2dd0b1,0x10),0xff)],0x10)),_0x21040b['bvhZN'](_0x412d52[_0x21040b[_0x9dd105('0x2f0')](_0x21040b[_0x9dd105('0x1bc')](_0x4aa919,0x8),0xff)],0x8)),_0x412d52[_0x21040b[_0x9dd105('0x284')](_0x279eb3,0xff)]),_0xd79792[_0x80410c++]);continue;case'7':_0x199a0e=_0x21040b[_0x9dd105('0x2c1')](_0x21040b[_0x9dd105('0x3c7')](_0x21040b['CRnnh'](_0x21040b[_0x9dd105('0x2ce')](_0x21040b[_0x9dd105('0x18b')](_0x412d52[_0x21040b[_0x9dd105('0x287')](_0x279eb3,0x18)],0x18),_0x21040b['bvhZN'](_0x412d52[_0x21040b[_0x9dd105('0x284')](_0x21040b[_0x9dd105('0x3e7')](_0x583b10,0x10),0xff)],0x10)),_0x21040b['bvhZN'](_0x412d52[_0x21040b[_0x9dd105('0x284')](_0x21040b[_0x9dd105('0x109')](_0x2dd0b1,0x8),0xff)],0x8)),_0x412d52[_0x21040b[_0x9dd105('0x1a5')](_0x4aa919,0xff)]),_0xd79792[_0x80410c++]);continue;case'8':_0x30d277[_0x21040b['WZLkp'](_0x263a8f,0x3)]=_0x2dd0b1;continue;}break;}}else{function _0x5871df(){var _0x102ce2=_0x9dd105,_0x4c8488=_0x21040b[_0x102ce2('0x3ae')](_0x234d50,_0x32bf37),_0x563792=_0x5eec07[_0x4c8488];_0x37df9b[_0x4c8488]=_0x21040b[_0x102ce2('0x27')](_0x21040b[_0x102ce2('0x145')](_0x21040b[_0x102ce2('0x458')](_0x21040b[_0x102ce2('0x159')](_0x563792,0x8),_0x21040b[_0x102ce2('0x63')](_0x563792,0x18)),0xff00ff),_0x21040b[_0x102ce2('0x145')](_0x21040b[_0x102ce2('0x458')](_0x21040b[_0x102ce2('0x159')](_0x563792,0x18),_0x21040b['WSero'](_0x563792,0x8)),0xff00ff00));}}},'keySize':0x8});_0x3a91c3['AES']=_0x28f1fa[_0x112bc9('0x294')](_0x1bc1cf);}()); \ No newline at end of file diff --git a/html/production/fingerprint.js b/html/production/fingerprint.js new file mode 100644 index 0000000..bb4ce78 --- /dev/null +++ b/html/production/fingerprint.js @@ -0,0 +1,1407 @@ +(function (name, context, definition) { + 'use strict' + if (typeof window !== 'undefined' && typeof define === 'function' && define.amd) { define(definition) } else if (typeof module !== 'undefined' && module.exports) { module.exports = definition() } else if (context.exports) { context.exports = definition() } else { context[name] = definition() } +})('Fingerprint2', this, function () { + 'use strict' + + /// MurmurHash3 related functions + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // added together as a 64bit int (as an array of two 32bit ints). + // + var x64Add = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] + n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] + n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] + n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += m[0] + n[0] + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // multiplied together as a 64bit int (as an array of two 32bit ints). + // + var x64Multiply = function (m, n) { + m = [m[0] >>> 16, m[0] & 0xffff, m[1] >>> 16, m[1] & 0xffff] + n = [n[0] >>> 16, n[0] & 0xffff, n[1] >>> 16, n[1] & 0xffff] + var o = [0, 0, 0, 0] + o[3] += m[3] * n[3] + o[2] += o[3] >>> 16 + o[3] &= 0xffff + o[2] += m[2] * n[3] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[2] += m[3] * n[2] + o[1] += o[2] >>> 16 + o[2] &= 0xffff + o[1] += m[1] * n[3] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[2] * n[2] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[1] += m[3] * n[1] + o[0] += o[1] >>> 16 + o[1] &= 0xffff + o[0] += (m[0] * n[3]) + (m[1] * n[2]) + (m[2] * n[1]) + (m[3] * n[0]) + o[0] &= 0xffff + return [(o[0] << 16) | o[1], (o[2] << 16) | o[3]] + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) rotated left by that number of positions. + // + var x64Rotl = function (m, n) { + n %= 64 + if (n === 32) { + return [m[1], m[0]] + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), (m[1] << n) | (m[0] >>> (32 - n))] + } else { + n -= 32 + return [(m[1] << n) | (m[0] >>> (32 - n)), (m[0] << n) | (m[1] >>> (32 - n))] + } + } + // + // Given a 64bit int (as an array of two 32bit ints) and an int + // representing a number of bit positions, returns the 64bit int (as an + // array of two 32bit ints) shifted left by that number of positions. + // + var x64LeftShift = function (m, n) { + n %= 64 + if (n === 0) { + return m + } else if (n < 32) { + return [(m[0] << n) | (m[1] >>> (32 - n)), m[1] << n] + } else { + return [m[1] << (n - 32), 0] + } + } + // + // Given two 64bit ints (as an array of two 32bit ints) returns the two + // xored together as a 64bit int (as an array of two 32bit ints). + // + var x64Xor = function (m, n) { + return [m[0] ^ n[0], m[1] ^ n[1]] + } + // + // Given a block, returns murmurHash3's final x64 mix of that block. + // (`[0, h[0] >>> 1]` is a 33 bit unsigned right shift. This is the + // only place where we need to right shift 64bit ints.) + // + var x64Fmix = function (h) { + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xff51afd7, 0xed558ccd]) + h = x64Xor(h, [0, h[0] >>> 1]) + h = x64Multiply(h, [0xc4ceb9fe, 0x1a85ec53]) + h = x64Xor(h, [0, h[0] >>> 1]) + return h + } + + // + // Given a string and an optional seed as an int, returns a 128 bit + // hash using the x64 flavor of MurmurHash3, as an unsigned hex. + // + var x64hash128 = function (key, seed) { + key = key || '' + seed = seed || 0 + var remainder = key.length % 16 + var bytes = key.length - remainder + var h1 = [0, seed] + var h2 = [0, seed] + var k1 = [0, 0] + var k2 = [0, 0] + var c1 = [0x87c37b91, 0x114253d5] + var c2 = [0x4cf5ad43, 0x2745937f] + for (var i = 0; i < bytes; i = i + 16) { + k1 = [((key.charCodeAt(i + 4) & 0xff)) | ((key.charCodeAt(i + 5) & 0xff) << 8) | ((key.charCodeAt(i + 6) & 0xff) << 16) | ((key.charCodeAt(i + 7) & 0xff) << 24), ((key.charCodeAt(i) & 0xff)) | ((key.charCodeAt(i + 1) & 0xff) << 8) | ((key.charCodeAt(i + 2) & 0xff) << 16) | ((key.charCodeAt(i + 3) & 0xff) << 24)] + k2 = [((key.charCodeAt(i + 12) & 0xff)) | ((key.charCodeAt(i + 13) & 0xff) << 8) | ((key.charCodeAt(i + 14) & 0xff) << 16) | ((key.charCodeAt(i + 15) & 0xff) << 24), ((key.charCodeAt(i + 8) & 0xff)) | ((key.charCodeAt(i + 9) & 0xff) << 8) | ((key.charCodeAt(i + 10) & 0xff) << 16) | ((key.charCodeAt(i + 11) & 0xff) << 24)] + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + h1 = x64Rotl(h1, 27) + h1 = x64Add(h1, h2) + h1 = x64Add(x64Multiply(h1, [0, 5]), [0, 0x52dce729]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + h2 = x64Rotl(h2, 31) + h2 = x64Add(h2, h1) + h2 = x64Add(x64Multiply(h2, [0, 5]), [0, 0x38495ab5]) + } + k1 = [0, 0] + k2 = [0, 0] + switch (remainder) { + case 15: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 14)], 48)) + // fallthrough + case 14: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 13)], 40)) + // fallthrough + case 13: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 12)], 32)) + // fallthrough + case 12: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 11)], 24)) + // fallthrough + case 11: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 10)], 16)) + // fallthrough + case 10: + k2 = x64Xor(k2, x64LeftShift([0, key.charCodeAt(i + 9)], 8)) + // fallthrough + case 9: + k2 = x64Xor(k2, [0, key.charCodeAt(i + 8)]) + k2 = x64Multiply(k2, c2) + k2 = x64Rotl(k2, 33) + k2 = x64Multiply(k2, c1) + h2 = x64Xor(h2, k2) + // fallthrough + case 8: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 7)], 56)) + // fallthrough + case 7: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 6)], 48)) + // fallthrough + case 6: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 5)], 40)) + // fallthrough + case 5: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 4)], 32)) + // fallthrough + case 4: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 3)], 24)) + // fallthrough + case 3: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 2)], 16)) + // fallthrough + case 2: + k1 = x64Xor(k1, x64LeftShift([0, key.charCodeAt(i + 1)], 8)) + // fallthrough + case 1: + k1 = x64Xor(k1, [0, key.charCodeAt(i)]) + k1 = x64Multiply(k1, c1) + k1 = x64Rotl(k1, 31) + k1 = x64Multiply(k1, c2) + h1 = x64Xor(h1, k1) + // fallthrough + } + h1 = x64Xor(h1, [0, key.length]) + h2 = x64Xor(h2, [0, key.length]) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + h1 = x64Fmix(h1) + h2 = x64Fmix(h2) + h1 = x64Add(h1, h2) + h2 = x64Add(h2, h1) + return ('00000000' + (h1[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h1[1] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[0] >>> 0).toString(16)).slice(-8) + ('00000000' + (h2[1] >>> 0).toString(16)).slice(-8) + } + + var defaultOptions = { + preprocessor: null, + audio: { + timeout: 1000, + // On iOS 11, audio context can only be used in response to user interaction. + // We require users to explicitly enable audio fingerprinting on iOS 11. + // See https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + excludeIOS11: true + }, + fonts: { + swfContainerId: 'fingerprintjs2', + swfPath: 'flash/compiled/FontList.swf', + userDefinedFonts: [], + extendedJsFonts: false + }, + screen: { + // To ensure consistent fingerprints when users rotate their mobile devices + detectScreenOrientation: true + }, + plugins: { + sortPluginsFor: [/palemoon/i], + excludeIE: false + }, + extraComponents: [], + excludes: { + // Unreliable on Windows, see https://github.com/Valve/fingerprintjs2/issues/375 + 'enumerateDevices': true, + // devicePixelRatio depends on browser zoom, and it's impossible to detect browser zoom + 'pixelRatio': true, + // DNT depends on incognito mode for some browsers (Chrome) and it's impossible to detect incognito mode + 'doNotTrack': true, + // uses js fonts already + 'fontsFlash': true + }, + NOT_AVAILABLE: 'not available', + ERROR: 'error', + EXCLUDED: 'excluded' + } + + var each = function (obj, iterator) { + if (Array.prototype.forEach && obj.forEach === Array.prototype.forEach) { + obj.forEach(iterator) + } else if (obj.length === +obj.length) { + for (var i = 0, l = obj.length; i < l; i++) { + iterator(obj[i], i, obj) + } + } else { + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + iterator(obj[key], key, obj) + } + } + } + } + + var map = function (obj, iterator) { + var results = [] + // Not using strict equality so that this acts as a + // shortcut to checking for `null` and `undefined`. + if (obj == null) { + return results + } + if (Array.prototype.map && obj.map === Array.prototype.map) { return obj.map(iterator) } + each(obj, function (value, index, list) { + results.push(iterator(value, index, list)) + }) + return results + } + + var extendSoft = function (target, source) { + if (source == null) { return target } + var value + var key + for (key in source) { + value = source[key] + if (value != null && !(Object.prototype.hasOwnProperty.call(target, key))) { + target[key] = value + } + } + return target + } + + // https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/enumerateDevices + var enumerateDevicesKey = function (done, options) { + if (!isEnumerateDevicesSupported()) { + return done(options.NOT_AVAILABLE) + } + navigator.mediaDevices.enumerateDevices().then(function (devices) { + done(devices.map(function (device) { + return 'id=' + device.deviceId + ';gid=' + device.groupId + ';' + device.kind + ';' + device.label + })) + }) + .catch(function (error) { + done(error) + }) + } + + var isEnumerateDevicesSupported = function () { + return (navigator.mediaDevices && navigator.mediaDevices.enumerateDevices) + } + // Inspired by and based on https://github.com/cozylife/audio-fingerprint + var audioKey = function (done, options) { + var audioOptions = options.audio + if (audioOptions.excludeIOS11 && navigator.userAgent.match(/OS 11.+Version\/11.+Safari/)) { + // See comment for excludeUserAgent and https://stackoverflow.com/questions/46363048/onaudioprocess-not-called-on-ios11#46534088 + return done(options.EXCLUDED) + } + + var AudioContext = window.OfflineAudioContext || window.webkitOfflineAudioContext + + if (AudioContext == null) { + return done(options.NOT_AVAILABLE) + } + + var context = new AudioContext(1, 44100, 44100) + + var oscillator = context.createOscillator() + oscillator.type = 'triangle' + oscillator.frequency.setValueAtTime(10000, context.currentTime) + + var compressor = context.createDynamicsCompressor() + each([ + ['threshold', -50], + ['knee', 40], + ['ratio', 12], + ['reduction', -20], + ['attack', 0], + ['release', 0.25] + ], function (item) { + if (compressor[item[0]] !== undefined && typeof compressor[item[0]].setValueAtTime === 'function') { + compressor[item[0]].setValueAtTime(item[1], context.currentTime) + } + }) + + oscillator.connect(compressor) + compressor.connect(context.destination) + oscillator.start(0) + context.startRendering() + + var audioTimeoutId = setTimeout(function () { + console.warn('Audio fingerprint timed out. Please report bug at https://github.com/Valve/fingerprintjs2 with your user agent: "' + navigator.userAgent + '".') + context.oncomplete = function () { } + context = null + return done('audioTimeout') + }, audioOptions.timeout) + + context.oncomplete = function (event) { + var fingerprint + try { + clearTimeout(audioTimeoutId) + fingerprint = event.renderedBuffer.getChannelData(0) + .slice(4500, 5000) + .reduce(function (acc, val) { return acc + Math.abs(val) }, 0) + .toString() + oscillator.disconnect() + compressor.disconnect() + } catch (error) { + done(error) + return + } + done(fingerprint) + } + } + var UserAgent = function (done) { + done(navigator.userAgent) + } + var webdriver = function (done, options) { + done(navigator.webdriver == null ? options.NOT_AVAILABLE : navigator.webdriver) + } + var languageKey = function (done, options) { + done(navigator.language || navigator.userLanguage || navigator.browserLanguage || navigator.systemLanguage || options.NOT_AVAILABLE) + } + var colorDepthKey = function (done, options) { + done(window.screen.colorDepth || options.NOT_AVAILABLE) + } + var deviceMemoryKey = function (done, options) { + done(navigator.deviceMemory || options.NOT_AVAILABLE) + } + var pixelRatioKey = function (done, options) { + done(window.devicePixelRatio || options.NOT_AVAILABLE) + } + var screenResolutionKey = function (done, options) { + done(getScreenResolution(options)) + } + var getScreenResolution = function (options) { + var resolution = [window.screen.width, window.screen.height] + if (options.screen.detectScreenOrientation) { + resolution.sort().reverse() + } + return resolution + } + var availableScreenResolutionKey = function (done, options) { + done(getAvailableScreenResolution(options)) + } + var getAvailableScreenResolution = function (options) { + if (window.screen.availWidth && window.screen.availHeight) { + var available = [window.screen.availHeight, window.screen.availWidth] + if (options.screen.detectScreenOrientation) { + available.sort().reverse() + } + return available + } + // headless browsers + return options.NOT_AVAILABLE + } + var timezoneOffset = function (done) { + done(new Date().getTimezoneOffset()) + } + var timezone = function (done, options) { + if (window.Intl && window.Intl.DateTimeFormat) { + done(new window.Intl.DateTimeFormat().resolvedOptions().timeZone) + return + } + done(options.NOT_AVAILABLE) + } + var sessionStorageKey = function (done, options) { + done(hasSessionStorage(options)) + } + var localStorageKey = function (done, options) { + done(hasLocalStorage(options)) + } + var indexedDbKey = function (done, options) { + done(hasIndexedDB(options)) + } + var addBehaviorKey = function (done) { + // body might not be defined at this point or removed programmatically + done(!!(document.body && document.body.addBehavior)) + } + var openDatabaseKey = function (done) { + done(!!window.openDatabase) + } + var cpuClassKey = function (done, options) { + done(getNavigatorCpuClass(options)) + } + var platformKey = function (done, options) { + done(getNavigatorPlatform(options)) + } + var doNotTrackKey = function (done, options) { + done(getDoNotTrack(options)) + } + var canvasKey = function (done, options) { + if (isCanvasSupported()) { + done(getCanvasFp(options)) + return + } + done(options.NOT_AVAILABLE) + } + var webglKey = function (done, options) { + if (isWebGlSupported()) { + done(getWebglFp()) + return + } + done(options.NOT_AVAILABLE) + } + var webglVendorAndRendererKey = function (done) { + if (isWebGlSupported()) { + done(getWebglVendorAndRenderer()) + return + } + done() + } + var adBlockKey = function (done) { + done(getAdBlock()) + } + var hasLiedLanguagesKey = function (done) { + done(getHasLiedLanguages()) + } + var hasLiedResolutionKey = function (done) { + done(getHasLiedResolution()) + } + var hasLiedOsKey = function (done) { + done(getHasLiedOs()) + } + var hasLiedBrowserKey = function (done) { + done(getHasLiedBrowser()) + } + // flash fonts (will increase fingerprinting time 20X to ~ 130-150ms) + var flashFontsKey = function (done, options) { + // we do flash if swfobject is loaded + if (!hasSwfObjectLoaded()) { + return done('swf object not loaded') + } + if (!hasMinFlashInstalled()) { + return done('flash not installed') + } + if (!options.fonts.swfPath) { + return done('missing options.fonts.swfPath') + } + loadSwfAndDetectFonts(function (fonts) { + done(fonts) + }, options) + } + // kudos to http://www.lalit.org/lab/javascript-css-font-detect/ + var jsFontsKey = function (done, options) { + // a font will be compared against all the three default fonts. + // and if it doesn't match all 3 then that font is not available. + var baseFonts = ['monospace', 'sans-serif', 'serif'] + + var fontList = [ + 'Andale Mono', 'Arial', 'Arial Black', 'Arial Hebrew', 'Arial MT', 'Arial Narrow', 'Arial Rounded MT Bold', 'Arial Unicode MS', + 'Bitstream Vera Sans Mono', 'Book Antiqua', 'Bookman Old Style', + 'Calibri', 'Cambria', 'Cambria Math', 'Century', 'Century Gothic', 'Century Schoolbook', 'Comic Sans', 'Comic Sans MS', 'Consolas', 'Courier', 'Courier New', + 'Geneva', 'Georgia', + 'Helvetica', 'Helvetica Neue', + 'Impact', + 'Lucida Bright', 'Lucida Calligraphy', 'Lucida Console', 'Lucida Fax', 'LUCIDA GRANDE', 'Lucida Handwriting', 'Lucida Sans', 'Lucida Sans Typewriter', 'Lucida Sans Unicode', + 'Microsoft Sans Serif', 'Monaco', 'Monotype Corsiva', 'MS Gothic', 'MS Outlook', 'MS PGothic', 'MS Reference Sans Serif', 'MS Sans Serif', 'MS Serif', 'MYRIAD', 'MYRIAD PRO', + 'Palatino', 'Palatino Linotype', + 'Segoe Print', 'Segoe Script', 'Segoe UI', 'Segoe UI Light', 'Segoe UI Semibold', 'Segoe UI Symbol', + 'Tahoma', 'Times', 'Times New Roman', 'Times New Roman PS', 'Trebuchet MS', + 'Verdana', 'Wingdings', 'Wingdings 2', 'Wingdings 3' + ] + + if (options.fonts.extendedJsFonts) { + var extendedFontList = [ + 'Abadi MT Condensed Light', 'Academy Engraved LET', 'ADOBE CASLON PRO', 'Adobe Garamond', 'ADOBE GARAMOND PRO', 'Agency FB', 'Aharoni', 'Albertus Extra Bold', 'Albertus Medium', 'Algerian', 'Amazone BT', 'American Typewriter', + 'American Typewriter Condensed', 'AmerType Md BT', 'Andalus', 'Angsana New', 'AngsanaUPC', 'Antique Olive', 'Aparajita', 'Apple Chancery', 'Apple Color Emoji', 'Apple SD Gothic Neo', 'Arabic Typesetting', 'ARCHER', + 'ARNO PRO', 'Arrus BT', 'Aurora Cn BT', 'AvantGarde Bk BT', 'AvantGarde Md BT', 'AVENIR', 'Ayuthaya', 'Bandy', 'Bangla Sangam MN', 'Bank Gothic', 'BankGothic Md BT', 'Baskerville', + 'Baskerville Old Face', 'Batang', 'BatangChe', 'Bauer Bodoni', 'Bauhaus 93', 'Bazooka', 'Bell MT', 'Bembo', 'Benguiat Bk BT', 'Berlin Sans FB', 'Berlin Sans FB Demi', 'Bernard MT Condensed', 'BernhardFashion BT', 'BernhardMod BT', 'Big Caslon', 'BinnerD', + 'Blackadder ITC', 'BlairMdITC TT', 'Bodoni 72', 'Bodoni 72 Oldstyle', 'Bodoni 72 Smallcaps', 'Bodoni MT', 'Bodoni MT Black', 'Bodoni MT Condensed', 'Bodoni MT Poster Compressed', + 'Bookshelf Symbol 7', 'Boulder', 'Bradley Hand', 'Bradley Hand ITC', 'Bremen Bd BT', 'Britannic Bold', 'Broadway', 'Browallia New', 'BrowalliaUPC', 'Brush Script MT', 'Californian FB', 'Calisto MT', 'Calligrapher', 'Candara', + 'CaslonOpnface BT', 'Castellar', 'Centaur', 'Cezanne', 'CG Omega', 'CG Times', 'Chalkboard', 'Chalkboard SE', 'Chalkduster', 'Charlesworth', 'Charter Bd BT', 'Charter BT', 'Chaucer', + 'ChelthmITC Bk BT', 'Chiller', 'Clarendon', 'Clarendon Condensed', 'CloisterBlack BT', 'Cochin', 'Colonna MT', 'Constantia', 'Cooper Black', 'Copperplate', 'Copperplate Gothic', 'Copperplate Gothic Bold', + 'Copperplate Gothic Light', 'CopperplGoth Bd BT', 'Corbel', 'Cordia New', 'CordiaUPC', 'Cornerstone', 'Coronet', 'Cuckoo', 'Curlz MT', 'DaunPenh', 'Dauphin', 'David', 'DB LCD Temp', 'DELICIOUS', 'Denmark', + 'DFKai-SB', 'Didot', 'DilleniaUPC', 'DIN', 'DokChampa', 'Dotum', 'DotumChe', 'Ebrima', 'Edwardian Script ITC', 'Elephant', 'English 111 Vivace BT', 'Engravers MT', 'EngraversGothic BT', 'Eras Bold ITC', 'Eras Demi ITC', 'Eras Light ITC', 'Eras Medium ITC', + 'EucrosiaUPC', 'Euphemia', 'Euphemia UCAS', 'EUROSTILE', 'Exotc350 Bd BT', 'FangSong', 'Felix Titling', 'Fixedsys', 'FONTIN', 'Footlight MT Light', 'Forte', + 'FrankRuehl', 'Fransiscan', 'Freefrm721 Blk BT', 'FreesiaUPC', 'Freestyle Script', 'French Script MT', 'FrnkGothITC Bk BT', 'Fruitger', 'FRUTIGER', + 'Futura', 'Futura Bk BT', 'Futura Lt BT', 'Futura Md BT', 'Futura ZBlk BT', 'FuturaBlack BT', 'Gabriola', 'Galliard BT', 'Gautami', 'Geeza Pro', 'Geometr231 BT', 'Geometr231 Hv BT', 'Geometr231 Lt BT', 'GeoSlab 703 Lt BT', + 'GeoSlab 703 XBd BT', 'Gigi', 'Gill Sans', 'Gill Sans MT', 'Gill Sans MT Condensed', 'Gill Sans MT Ext Condensed Bold', 'Gill Sans Ultra Bold', 'Gill Sans Ultra Bold Condensed', 'Gisha', 'Gloucester MT Extra Condensed', 'GOTHAM', 'GOTHAM BOLD', + 'Goudy Old Style', 'Goudy Stout', 'GoudyHandtooled BT', 'GoudyOLSt BT', 'Gujarati Sangam MN', 'Gulim', 'GulimChe', 'Gungsuh', 'GungsuhChe', 'Gurmukhi MN', 'Haettenschweiler', 'Harlow Solid Italic', 'Harrington', 'Heather', 'Heiti SC', 'Heiti TC', 'HELV', + 'Herald', 'High Tower Text', 'Hiragino Kaku Gothic ProN', 'Hiragino Mincho ProN', 'Hoefler Text', 'Humanst 521 Cn BT', 'Humanst521 BT', 'Humanst521 Lt BT', 'Imprint MT Shadow', 'Incised901 Bd BT', 'Incised901 BT', + 'Incised901 Lt BT', 'INCONSOLATA', 'Informal Roman', 'Informal011 BT', 'INTERSTATE', 'IrisUPC', 'Iskoola Pota', 'JasmineUPC', 'Jazz LET', 'Jenson', 'Jester', 'Jokerman', 'Juice ITC', 'Kabel Bk BT', 'Kabel Ult BT', 'Kailasa', 'KaiTi', 'Kalinga', 'Kannada Sangam MN', + 'Kartika', 'Kaufmann Bd BT', 'Kaufmann BT', 'Khmer UI', 'KodchiangUPC', 'Kokila', 'Korinna BT', 'Kristen ITC', 'Krungthep', 'Kunstler Script', 'Lao UI', 'Latha', 'Leelawadee', 'Letter Gothic', 'Levenim MT', 'LilyUPC', 'Lithograph', 'Lithograph Light', 'Long Island', + 'Lydian BT', 'Magneto', 'Maiandra GD', 'Malayalam Sangam MN', 'Malgun Gothic', + 'Mangal', 'Marigold', 'Marion', 'Marker Felt', 'Market', 'Marlett', 'Matisse ITC', 'Matura MT Script Capitals', 'Meiryo', 'Meiryo UI', 'Microsoft Himalaya', 'Microsoft JhengHei', 'Microsoft New Tai Lue', 'Microsoft PhagsPa', 'Microsoft Tai Le', + 'Microsoft Uighur', 'Microsoft YaHei', 'Microsoft Yi Baiti', 'MingLiU', 'MingLiU_HKSCS', 'MingLiU_HKSCS-ExtB', 'MingLiU-ExtB', 'Minion', 'Minion Pro', 'Miriam', 'Miriam Fixed', 'Mistral', 'Modern', 'Modern No. 20', 'Mona Lisa Solid ITC TT', 'Mongolian Baiti', + 'MONO', 'MoolBoran', 'Mrs Eaves', 'MS LineDraw', 'MS Mincho', 'MS PMincho', 'MS Reference Specialty', 'MS UI Gothic', 'MT Extra', 'MUSEO', 'MV Boli', + 'Nadeem', 'Narkisim', 'NEVIS', 'News Gothic', 'News GothicMT', 'NewsGoth BT', 'Niagara Engraved', 'Niagara Solid', 'Noteworthy', 'NSimSun', 'Nyala', 'OCR A Extended', 'Old Century', 'Old English Text MT', 'Onyx', 'Onyx BT', 'OPTIMA', 'Oriya Sangam MN', + 'OSAKA', 'OzHandicraft BT', 'Palace Script MT', 'Papyrus', 'Parchment', 'Party LET', 'Pegasus', 'Perpetua', 'Perpetua Titling MT', 'PetitaBold', 'Pickwick', 'Plantagenet Cherokee', 'Playbill', 'PMingLiU', 'PMingLiU-ExtB', + 'Poor Richard', 'Poster', 'PosterBodoni BT', 'PRINCETOWN LET', 'Pristina', 'PTBarnum BT', 'Pythagoras', 'Raavi', 'Rage Italic', 'Ravie', 'Ribbon131 Bd BT', 'Rockwell', 'Rockwell Condensed', 'Rockwell Extra Bold', 'Rod', 'Roman', 'Sakkal Majalla', + 'Santa Fe LET', 'Savoye LET', 'Sceptre', 'Script', 'Script MT Bold', 'SCRIPTINA', 'Serifa', 'Serifa BT', 'Serifa Th BT', 'ShelleyVolante BT', 'Sherwood', + 'Shonar Bangla', 'Showcard Gothic', 'Shruti', 'Signboard', 'SILKSCREEN', 'SimHei', 'Simplified Arabic', 'Simplified Arabic Fixed', 'SimSun', 'SimSun-ExtB', 'Sinhala Sangam MN', 'Sketch Rockwell', 'Skia', 'Small Fonts', 'Snap ITC', 'Snell Roundhand', 'Socket', + 'Souvenir Lt BT', 'Staccato222 BT', 'Steamer', 'Stencil', 'Storybook', 'Styllo', 'Subway', 'Swis721 BlkEx BT', 'Swiss911 XCm BT', 'Sylfaen', 'Synchro LET', 'System', 'Tamil Sangam MN', 'Technical', 'Teletype', 'Telugu Sangam MN', 'Tempus Sans ITC', + 'Terminal', 'Thonburi', 'Traditional Arabic', 'Trajan', 'TRAJAN PRO', 'Tristan', 'Tubular', 'Tunga', 'Tw Cen MT', 'Tw Cen MT Condensed', 'Tw Cen MT Condensed Extra Bold', + 'TypoUpright BT', 'Unicorn', 'Univers', 'Univers CE 55 Medium', 'Univers Condensed', 'Utsaah', 'Vagabond', 'Vani', 'Vijaya', 'Viner Hand ITC', 'VisualUI', 'Vivaldi', 'Vladimir Script', 'Vrinda', 'Westminster', 'WHITNEY', 'Wide Latin', + 'ZapfEllipt BT', 'ZapfHumnst BT', 'ZapfHumnst Dm BT', 'Zapfino', 'Zurich BlkEx BT', 'Zurich Ex BT', 'ZWAdobeF'] + fontList = fontList.concat(extendedFontList) + } + + fontList = fontList.concat(options.fonts.userDefinedFonts) + + // remove duplicate fonts + fontList = fontList.filter(function (font, position) { + return fontList.indexOf(font) === position + }) + + // we use m or w because these two characters take up the maximum width. + // And we use a LLi so that the same matching fonts can get separated + var testString = 'mmmmmmmmmmlli' + + // we test using 72px font size, we may use any size. I guess larger the better. + var testSize = '72px' + + var h = document.getElementsByTagName('body')[0] + + // div to load spans for the base fonts + var baseFontsDiv = document.createElement('div') + + // div to load spans for the fonts to detect + var fontsDiv = document.createElement('div') + + var defaultWidth = {} + var defaultHeight = {} + + // creates a span where the fonts will be loaded + var createSpan = function () { + var s = document.createElement('span') + /* + * We need this css as in some weird browser this + * span elements shows up for a microSec which creates a + * bad user experience + */ + s.style.position = 'absolute' + s.style.left = '-9999px' + s.style.fontSize = testSize + + // css font reset to reset external styles + s.style.fontStyle = 'normal' + s.style.fontWeight = 'normal' + s.style.letterSpacing = 'normal' + s.style.lineBreak = 'auto' + s.style.lineHeight = 'normal' + s.style.textTransform = 'none' + s.style.textAlign = 'left' + s.style.textDecoration = 'none' + s.style.textShadow = 'none' + s.style.whiteSpace = 'normal' + s.style.wordBreak = 'normal' + s.style.wordSpacing = 'normal' + + s.innerHTML = testString + return s + } + + // creates a span and load the font to detect and a base font for fallback + var createSpanWithFonts = function (fontToDetect, baseFont) { + var s = createSpan() + s.style.fontFamily = "'" + fontToDetect + "'," + baseFont + return s + } + + // creates spans for the base fonts and adds them to baseFontsDiv + var initializeBaseFontsSpans = function () { + var spans = [] + for (var index = 0, length = baseFonts.length; index < length; index++) { + var s = createSpan() + s.style.fontFamily = baseFonts[index] + baseFontsDiv.appendChild(s) + spans.push(s) + } + return spans + } + + // creates spans for the fonts to detect and adds them to fontsDiv + var initializeFontsSpans = function () { + var spans = {} + for (var i = 0, l = fontList.length; i < l; i++) { + var fontSpans = [] + for (var j = 0, numDefaultFonts = baseFonts.length; j < numDefaultFonts; j++) { + var s = createSpanWithFonts(fontList[i], baseFonts[j]) + fontsDiv.appendChild(s) + fontSpans.push(s) + } + spans[fontList[i]] = fontSpans // Stores {fontName : [spans for that font]} + } + return spans + } + + // checks if a font is available + var isFontAvailable = function (fontSpans) { + var detected = false + for (var i = 0; i < baseFonts.length; i++) { + detected = (fontSpans[i].offsetWidth !== defaultWidth[baseFonts[i]] || fontSpans[i].offsetHeight !== defaultHeight[baseFonts[i]]) + if (detected) { + return detected + } + } + return detected + } + + // create spans for base fonts + var baseFontsSpans = initializeBaseFontsSpans() + + // add the spans to the DOM + h.appendChild(baseFontsDiv) + + // get the default width for the three base fonts + for (var index = 0, length = baseFonts.length; index < length; index++) { + defaultWidth[baseFonts[index]] = baseFontsSpans[index].offsetWidth // width for the default font + defaultHeight[baseFonts[index]] = baseFontsSpans[index].offsetHeight // height for the default font + } + + // create spans for fonts to detect + var fontsSpans = initializeFontsSpans() + + // add all the spans to the DOM + h.appendChild(fontsDiv) + + // check available fonts + var available = [] + for (var i = 0, l = fontList.length; i < l; i++) { + if (isFontAvailable(fontsSpans[fontList[i]])) { + available.push(fontList[i]) + } + } + + // remove spans from DOM + h.removeChild(fontsDiv) + h.removeChild(baseFontsDiv) + done(available) + } + var pluginsComponent = function (done, options) { + if (isIE()) { + if (!options.plugins.excludeIE) { + done(getIEPlugins(options)) + } else { + done(options.EXCLUDED) + } + } else { + done(getRegularPlugins(options)) + } + } + var getRegularPlugins = function (options) { + if (navigator.plugins == null) { + return options.NOT_AVAILABLE + } + + var plugins = [] + // plugins isn't defined in Node envs. + for (var i = 0, l = navigator.plugins.length; i < l; i++) { + if (navigator.plugins[i]) { plugins.push(navigator.plugins[i]) } + } + + // sorting plugins only for those user agents, that we know randomize the plugins + // every time we try to enumerate them + if (pluginsShouldBeSorted(options)) { + plugins = plugins.sort(function (a, b) { + if (a.name > b.name) { return 1 } + if (a.name < b.name) { return -1 } + return 0 + }) + } + return map(plugins, function (p) { + var mimeTypes = map(p, function (mt) { + return [mt.type, mt.suffixes] + }) + return [p.name, p.description, mimeTypes] + }) + } + var getIEPlugins = function (options) { + var result = [] + if ((Object.getOwnPropertyDescriptor && Object.getOwnPropertyDescriptor(window, 'ActiveXObject')) || ('ActiveXObject' in window)) { + var names = [ + 'AcroPDF.PDF', // Adobe PDF reader 7+ + 'Adodb.Stream', + 'AgControl.AgControl', // Silverlight + 'DevalVRXCtrl.DevalVRXCtrl.1', + 'MacromediaFlashPaper.MacromediaFlashPaper', + 'Msxml2.DOMDocument', + 'Msxml2.XMLHTTP', + 'PDF.PdfCtrl', // Adobe PDF reader 6 and earlier, brrr + 'QuickTime.QuickTime', // QuickTime + 'QuickTimeCheckObject.QuickTimeCheck.1', + 'RealPlayer', + 'RealPlayer.RealPlayer(tm) ActiveX Control (32-bit)', + 'RealVideo.RealVideo(tm) ActiveX Control (32-bit)', + 'Scripting.Dictionary', + 'SWCtl.SWCtl', // ShockWave player + 'Shell.UIHelper', + 'ShockwaveFlash.ShockwaveFlash', // flash plugin + 'Skype.Detection', + 'TDCCtl.TDCCtl', + 'WMPlayer.OCX', // Windows media player + 'rmocx.RealPlayer G2 Control', + 'rmocx.RealPlayer G2 Control.1' + ] + // starting to detect plugins in IE + result = map(names, function (name) { + try { + // eslint-disable-next-line no-new + new window.ActiveXObject(name) + return name + } catch (e) { + return options.ERROR + } + }) + } else { + result.push(options.NOT_AVAILABLE) + } + if (navigator.plugins) { + result = result.concat(getRegularPlugins(options)) + } + return result + } + var pluginsShouldBeSorted = function (options) { + var should = false + for (var i = 0, l = options.plugins.sortPluginsFor.length; i < l; i++) { + var re = options.plugins.sortPluginsFor[i] + if (navigator.userAgent.match(re)) { + should = true + break + } + } + return should + } + var touchSupportKey = function (done) { + done(getTouchSupport()) + } + var hardwareConcurrencyKey = function (done, options) { + done(getHardwareConcurrency(options)) + } + var hasSessionStorage = function (options) { + try { + return !!window.sessionStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + + // https://bugzilla.mozilla.org/show_bug.cgi?id=781447 + var hasLocalStorage = function (options) { + try { + return !!window.localStorage + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var hasIndexedDB = function (options) { + try { + return !!window.indexedDB + } catch (e) { + return options.ERROR // SecurityError when referencing it means it exists + } + } + var getHardwareConcurrency = function (options) { + if (navigator.hardwareConcurrency) { + return navigator.hardwareConcurrency + } + return options.NOT_AVAILABLE + } + var getNavigatorCpuClass = function (options) { + return navigator.cpuClass || options.NOT_AVAILABLE + } + var getNavigatorPlatform = function (options) { + if (navigator.platform) { + return navigator.platform + } else { + return options.NOT_AVAILABLE + } + } + var getDoNotTrack = function (options) { + if (navigator.doNotTrack) { + return navigator.doNotTrack + } else if (navigator.msDoNotTrack) { + return navigator.msDoNotTrack + } else if (window.doNotTrack) { + return window.doNotTrack + } else { + return options.NOT_AVAILABLE + } + } + // This is a crude and primitive touch screen detection. + // It's not possible to currently reliably detect the availability of a touch screen + // with a JS, without actually subscribing to a touch event. + // http://www.stucox.com/blog/you-cant-detect-a-touchscreen/ + // https://github.com/Modernizr/Modernizr/issues/548 + // method returns an array of 3 values: + // maxTouchPoints, the success or failure of creating a TouchEvent, + // and the availability of the 'ontouchstart' property + + var getTouchSupport = function () { + var maxTouchPoints = 0 + var touchEvent + if (typeof navigator.maxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.maxTouchPoints + } else if (typeof navigator.msMaxTouchPoints !== 'undefined') { + maxTouchPoints = navigator.msMaxTouchPoints + } + try { + document.createEvent('TouchEvent') + touchEvent = true + } catch (_) { + touchEvent = false + } + var touchStart = 'ontouchstart' in window + return [maxTouchPoints, touchEvent, touchStart] + } + // https://www.browserleaks.com/canvas#how-does-it-work + + var getCanvasFp = function (options) { + var result = [] + // Very simple now, need to make it more complex (geo shapes etc) + var canvas = document.createElement('canvas') + canvas.width = 2000 + canvas.height = 200 + canvas.style.display = 'inline' + var ctx = canvas.getContext('2d') + // detect browser support of canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // https://github.com/Modernizr/Modernizr/blob/master/feature-detects/canvas/winding.js + ctx.rect(0, 0, 10, 10) + ctx.rect(2, 2, 6, 6) + result.push('canvas winding:' + ((ctx.isPointInPath(5, 5, 'evenodd') === false) ? 'yes' : 'no')) + + ctx.textBaseline = 'alphabetic' + ctx.fillStyle = '#f60' + ctx.fillRect(125, 1, 62, 20) + ctx.fillStyle = '#069' + // https://github.com/Valve/fingerprintjs2/issues/66 + if (options.dontUseFakeFontInCanvas) { + ctx.font = '11pt Arial' + } else { + ctx.font = '11pt no-real-font-123' + } + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 2, 15) + ctx.fillStyle = 'rgba(102, 204, 0, 0.2)' + ctx.font = '18pt Arial' + ctx.fillText('Cwm fjordbank glyphs vext quiz, \ud83d\ude03', 4, 45) + + // canvas blending + // http://blogs.adobe.com/webplatform/2013/01/28/blending-features-in-canvas/ + // http://jsfiddle.net/NDYV8/16/ + ctx.globalCompositeOperation = 'multiply' + ctx.fillStyle = 'rgb(255,0,255)' + ctx.beginPath() + ctx.arc(50, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(0,255,255)' + ctx.beginPath() + ctx.arc(100, 50, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,255,0)' + ctx.beginPath() + ctx.arc(75, 100, 50, 0, Math.PI * 2, true) + ctx.closePath() + ctx.fill() + ctx.fillStyle = 'rgb(255,0,255)' + // canvas winding + // http://blogs.adobe.com/webplatform/2013/01/30/winding-rules-in-canvas/ + // http://jsfiddle.net/NDYV8/19/ + ctx.arc(75, 75, 75, 0, Math.PI * 2, true) + ctx.arc(75, 75, 25, 0, Math.PI * 2, true) + ctx.fill('evenodd') + + if (canvas.toDataURL) { result.push('canvas fp:' + canvas.toDataURL()) } + return result + } + var getWebglFp = function () { + var gl + var fa2s = function (fa) { + gl.clearColor(0.0, 0.0, 0.0, 1.0) + gl.enable(gl.DEPTH_TEST) + gl.depthFunc(gl.LEQUAL) + gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + return '[' + fa[0] + ', ' + fa[1] + ']' + } + var maxAnisotropy = function (gl) { + var ext = gl.getExtension('EXT_texture_filter_anisotropic') || gl.getExtension('WEBKIT_EXT_texture_filter_anisotropic') || gl.getExtension('MOZ_EXT_texture_filter_anisotropic') + if (ext) { + var anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY_EXT) + if (anisotropy === 0) { + anisotropy = 2 + } + return anisotropy + } else { + return null + } + } + + gl = getWebglCanvas() + if (!gl) { return null } + // WebGL fingerprinting is a combination of techniques, found in MaxMind antifraud script & Augur fingerprinting. + // First it draws a gradient object with shaders and convers the image to the Base64 string. + // Then it enumerates all WebGL extensions & capabilities and appends them to the Base64 string, resulting in a huge WebGL string, potentially very unique on each device + // Since iOS supports webgl starting from version 8.1 and 8.1 runs on several graphics chips, the results may be different across ios devices, but we need to verify it. + var result = [] + var vShaderTemplate = 'attribute vec2 attrVertex;varying vec2 varyinTexCoordinate;uniform vec2 uniformOffset;void main(){varyinTexCoordinate=attrVertex+uniformOffset;gl_Position=vec4(attrVertex,0,1);}' + var fShaderTemplate = 'precision mediump float;varying vec2 varyinTexCoordinate;void main() {gl_FragColor=vec4(varyinTexCoordinate,0,1);}' + var vertexPosBuffer = gl.createBuffer() + gl.bindBuffer(gl.ARRAY_BUFFER, vertexPosBuffer) + var vertices = new Float32Array([-0.2, -0.9, 0, 0.4, -0.26, 0, 0, 0.732134444, 0]) + gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW) + vertexPosBuffer.itemSize = 3 + vertexPosBuffer.numItems = 3 + var program = gl.createProgram() + var vshader = gl.createShader(gl.VERTEX_SHADER) + gl.shaderSource(vshader, vShaderTemplate) + gl.compileShader(vshader) + var fshader = gl.createShader(gl.FRAGMENT_SHADER) + gl.shaderSource(fshader, fShaderTemplate) + gl.compileShader(fshader) + gl.attachShader(program, vshader) + gl.attachShader(program, fshader) + gl.linkProgram(program) + gl.useProgram(program) + program.vertexPosAttrib = gl.getAttribLocation(program, 'attrVertex') + program.offsetUniform = gl.getUniformLocation(program, 'uniformOffset') + gl.enableVertexAttribArray(program.vertexPosArray) + gl.vertexAttribPointer(program.vertexPosAttrib, vertexPosBuffer.itemSize, gl.FLOAT, !1, 0, 0) + gl.uniform2f(program.offsetUniform, 1, 1) + gl.drawArrays(gl.TRIANGLE_STRIP, 0, vertexPosBuffer.numItems) + try { + result.push(gl.canvas.toDataURL()) + } catch (e) { + /* .toDataURL may be absent or broken (blocked by extension) */ + } + result.push('extensions:' + (gl.getSupportedExtensions() || []).join(';')) + result.push('webgl aliased line width range:' + fa2s(gl.getParameter(gl.ALIASED_LINE_WIDTH_RANGE))) + result.push('webgl aliased point size range:' + fa2s(gl.getParameter(gl.ALIASED_POINT_SIZE_RANGE))) + result.push('webgl alpha bits:' + gl.getParameter(gl.ALPHA_BITS)) + result.push('webgl antialiasing:' + (gl.getContextAttributes().antialias ? 'yes' : 'no')) + result.push('webgl blue bits:' + gl.getParameter(gl.BLUE_BITS)) + result.push('webgl depth bits:' + gl.getParameter(gl.DEPTH_BITS)) + result.push('webgl green bits:' + gl.getParameter(gl.GREEN_BITS)) + result.push('webgl max anisotropy:' + maxAnisotropy(gl)) + result.push('webgl max combined texture image units:' + gl.getParameter(gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS)) + result.push('webgl max cube map texture size:' + gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE)) + result.push('webgl max fragment uniform vectors:' + gl.getParameter(gl.MAX_FRAGMENT_UNIFORM_VECTORS)) + result.push('webgl max render buffer size:' + gl.getParameter(gl.MAX_RENDERBUFFER_SIZE)) + result.push('webgl max texture image units:' + gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max texture size:' + gl.getParameter(gl.MAX_TEXTURE_SIZE)) + result.push('webgl max varying vectors:' + gl.getParameter(gl.MAX_VARYING_VECTORS)) + result.push('webgl max vertex attribs:' + gl.getParameter(gl.MAX_VERTEX_ATTRIBS)) + result.push('webgl max vertex texture image units:' + gl.getParameter(gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS)) + result.push('webgl max vertex uniform vectors:' + gl.getParameter(gl.MAX_VERTEX_UNIFORM_VECTORS)) + result.push('webgl max viewport dims:' + fa2s(gl.getParameter(gl.MAX_VIEWPORT_DIMS))) + result.push('webgl red bits:' + gl.getParameter(gl.RED_BITS)) + result.push('webgl renderer:' + gl.getParameter(gl.RENDERER)) + result.push('webgl shading language version:' + gl.getParameter(gl.SHADING_LANGUAGE_VERSION)) + result.push('webgl stencil bits:' + gl.getParameter(gl.STENCIL_BITS)) + result.push('webgl vendor:' + gl.getParameter(gl.VENDOR)) + result.push('webgl version:' + gl.getParameter(gl.VERSION)) + + try { + // Add the unmasked vendor and unmasked renderer if the debug_renderer_info extension is available + var extensionDebugRendererInfo = gl.getExtension('WEBGL_debug_renderer_info') + if (extensionDebugRendererInfo) { + result.push('webgl unmasked vendor:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL)) + result.push('webgl unmasked renderer:' + gl.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL)) + } + } catch (e) { /* squelch */ } + + if (!gl.getShaderPrecisionFormat) { + return result + } + + each(['FLOAT', 'INT'], function (numType) { + each(['VERTEX', 'FRAGMENT'], function (shader) { + each(['HIGH', 'MEDIUM', 'LOW'], function (numSize) { + each(['precision', 'rangeMin', 'rangeMax'], function (key) { + var format = gl.getShaderPrecisionFormat(gl[shader + '_SHADER'], gl[numSize + '_' + numType])[key] + if (key !== 'precision') { + key = 'precision ' + key + } + var line = ['webgl ', shader.toLowerCase(), ' shader ', numSize.toLowerCase(), ' ', numType.toLowerCase(), ' ', key, ':', format].join('') + result.push(line) + }) + }) + }) + }) + return result + } + var getWebglVendorAndRenderer = function () { + /* This a subset of the WebGL fingerprint with a lot of entropy, while being reasonably browser-independent */ + try { + var glContext = getWebglCanvas() + var extensionDebugRendererInfo = glContext.getExtension('WEBGL_debug_renderer_info') + return glContext.getParameter(extensionDebugRendererInfo.UNMASKED_VENDOR_WEBGL) + '~' + glContext.getParameter(extensionDebugRendererInfo.UNMASKED_RENDERER_WEBGL) + } catch (e) { + return null + } + } + var getAdBlock = function () { + var ads = document.createElement('div') + ads.innerHTML = ' ' + ads.className = 'adsbox' + var result = false + try { + // body may not exist, that's why we need try/catch + document.body.appendChild(ads) + result = document.getElementsByClassName('adsbox')[0].offsetHeight === 0 + document.body.removeChild(ads) + } catch (e) { + result = false + } + return result + } + var getHasLiedLanguages = function () { + // We check if navigator.language is equal to the first language of navigator.languages + // navigator.languages is undefined on IE11 (and potentially older IEs) + if (typeof navigator.languages !== 'undefined') { + try { + var firstLanguages = navigator.languages[0].substr(0, 2) + if (firstLanguages !== navigator.language.substr(0, 2)) { + return true + } + } catch (err) { + return true + } + } + return false + } + var getHasLiedResolution = function () { + return window.screen.width < window.screen.availWidth || window.screen.height < window.screen.availHeight + } + var getHasLiedOs = function () { + var userAgent = navigator.userAgent.toLowerCase() + var oscpu = navigator.oscpu + var platform = navigator.platform.toLowerCase() + var os + // We extract the OS from the user agent (respect the order of the if else if statement) + if (userAgent.indexOf('windows phone') >= 0) { + os = 'Windows Phone' + } else if (userAgent.indexOf('win') >= 0) { + os = 'Windows' + } else if (userAgent.indexOf('android') >= 0) { + os = 'Android' + } else if (userAgent.indexOf('linux') >= 0 || userAgent.indexOf('cros') >= 0) { + os = 'Linux' + } else if (userAgent.indexOf('iphone') >= 0 || userAgent.indexOf('ipad') >= 0) { + os = 'iOS' + } else if (userAgent.indexOf('mac') >= 0) { + os = 'Mac' + } else { + os = 'Other' + } + // We detect if the person uses a mobile device + var mobileDevice = (('ontouchstart' in window) || + (navigator.maxTouchPoints > 0) || + (navigator.msMaxTouchPoints > 0)) + + if (mobileDevice && os !== 'Windows Phone' && os !== 'Android' && os !== 'iOS' && os !== 'Other') { + return true + } + + // We compare oscpu with the OS extracted from the UA + if (typeof oscpu !== 'undefined') { + oscpu = oscpu.toLowerCase() + if (oscpu.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if (oscpu.indexOf('linux') >= 0 && os !== 'Linux' && os !== 'Android') { + return true + } else if (oscpu.indexOf('mac') >= 0 && os !== 'Mac' && os !== 'iOS') { + return true + } else if ((oscpu.indexOf('win') === -1 && oscpu.indexOf('linux') === -1 && oscpu.indexOf('mac') === -1) !== (os === 'Other')) { + return true + } + } + + // We compare platform with the OS extracted from the UA + if (platform.indexOf('win') >= 0 && os !== 'Windows' && os !== 'Windows Phone') { + return true + } else if ((platform.indexOf('linux') >= 0 || platform.indexOf('android') >= 0 || platform.indexOf('pike') >= 0) && os !== 'Linux' && os !== 'Android') { + return true + } else if ((platform.indexOf('mac') >= 0 || platform.indexOf('ipad') >= 0 || platform.indexOf('ipod') >= 0 || platform.indexOf('iphone') >= 0) && os !== 'Mac' && os !== 'iOS') { + return true + } else { + var platformIsOther = platform.indexOf('win') < 0 && + platform.indexOf('linux') < 0 && + platform.indexOf('mac') < 0 && + platform.indexOf('iphone') < 0 && + platform.indexOf('ipad') < 0 + if (platformIsOther !== (os === 'Other')) { + return true + } + } + + return typeof navigator.plugins === 'undefined' && os !== 'Windows' && os !== 'Windows Phone' + } + var getHasLiedBrowser = function () { + var userAgent = navigator.userAgent.toLowerCase() + var productSub = navigator.productSub + + // we extract the browser from the user agent (respect the order of the tests) + var browser + if (userAgent.indexOf('firefox') >= 0) { + browser = 'Firefox' + } else if (userAgent.indexOf('opera') >= 0 || userAgent.indexOf('opr') >= 0) { + browser = 'Opera' + } else if (userAgent.indexOf('chrome') >= 0) { + browser = 'Chrome' + } else if (userAgent.indexOf('safari') >= 0) { + browser = 'Safari' + } else if (userAgent.indexOf('trident') >= 0) { + browser = 'Internet Explorer' + } else { + browser = 'Other' + } + + if ((browser === 'Chrome' || browser === 'Safari' || browser === 'Opera') && productSub !== '20030107') { + return true + } + + // eslint-disable-next-line no-eval + var tempRes = eval.toString().length + if (tempRes === 37 && browser !== 'Safari' && browser !== 'Firefox' && browser !== 'Other') { + return true + } else if (tempRes === 39 && browser !== 'Internet Explorer' && browser !== 'Other') { + return true + } else if (tempRes === 33 && browser !== 'Chrome' && browser !== 'Opera' && browser !== 'Other') { + return true + } + + // We create an error to see how it is handled + var errFirefox + try { + // eslint-disable-next-line no-throw-literal + throw 'a' + } catch (err) { + try { + err.toSource() + errFirefox = true + } catch (errOfErr) { + errFirefox = false + } + } + return errFirefox && browser !== 'Firefox' && browser !== 'Other' + } + var isCanvasSupported = function () { + var elem = document.createElement('canvas') + return !!(elem.getContext && elem.getContext('2d')) + } + var isWebGlSupported = function () { + // code taken from Modernizr + if (!isCanvasSupported()) { + return false + } + + var glContext = getWebglCanvas() + return !!window.WebGLRenderingContext && !!glContext + } + var isIE = function () { + if (navigator.appName === 'Microsoft Internet Explorer') { + return true + } else if (navigator.appName === 'Netscape' && /Trident/.test(navigator.userAgent)) { // IE 11 + return true + } + return false + } + var hasSwfObjectLoaded = function () { + return typeof window.swfobject !== 'undefined' + } + var hasMinFlashInstalled = function () { + return window.swfobject.hasFlashPlayerVersion('9.0.0') + } + var addFlashDivNode = function (options) { + var node = document.createElement('div') + node.setAttribute('id', options.fonts.swfContainerId) + document.body.appendChild(node) + } + var loadSwfAndDetectFonts = function (done, options) { + var hiddenCallback = '___fp_swf_loaded' + window[hiddenCallback] = function (fonts) { + done(fonts) + } + var id = options.fonts.swfContainerId + addFlashDivNode() + var flashvars = { onReady: hiddenCallback } + var flashparams = { allowScriptAccess: 'always', menu: 'false' } + window.swfobject.embedSWF(options.fonts.swfPath, id, '1', '1', '9.0.0', false, flashvars, flashparams, {}) + } + var getWebglCanvas = function () { + var canvas = document.createElement('canvas') + var gl = null + try { + gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') + } catch (e) { /* squelch */ } + if (!gl) { gl = null } + return gl + } + + var components = [ + { key: 'userAgent', getData: UserAgent }, + { key: 'webdriver', getData: webdriver }, + { key: 'language', getData: languageKey }, + { key: 'colorDepth', getData: colorDepthKey }, + { key: 'deviceMemory', getData: deviceMemoryKey }, + { key: 'pixelRatio', getData: pixelRatioKey }, + { key: 'hardwareConcurrency', getData: hardwareConcurrencyKey }, + { key: 'screenResolution', getData: screenResolutionKey }, + { key: 'availableScreenResolution', getData: availableScreenResolutionKey }, + { key: 'timezoneOffset', getData: timezoneOffset }, + { key: 'timezone', getData: timezone }, + { key: 'sessionStorage', getData: sessionStorageKey }, + { key: 'localStorage', getData: localStorageKey }, + { key: 'indexedDb', getData: indexedDbKey }, + { key: 'addBehavior', getData: addBehaviorKey }, + { key: 'openDatabase', getData: openDatabaseKey }, + { key: 'cpuClass', getData: cpuClassKey }, + { key: 'platform', getData: platformKey }, + { key: 'doNotTrack', getData: doNotTrackKey }, + { key: 'plugins', getData: pluginsComponent }, + { key: 'canvas', getData: canvasKey }, + { key: 'webgl', getData: webglKey }, + { key: 'webglVendorAndRenderer', getData: webglVendorAndRendererKey }, + { key: 'adBlock', getData: adBlockKey }, + { key: 'hasLiedLanguages', getData: hasLiedLanguagesKey }, + { key: 'hasLiedResolution', getData: hasLiedResolutionKey }, + { key: 'hasLiedOs', getData: hasLiedOsKey }, + { key: 'hasLiedBrowser', getData: hasLiedBrowserKey }, + { key: 'touchSupport', getData: touchSupportKey }, + { key: 'fonts', getData: jsFontsKey, pauseBefore: true }, + { key: 'fontsFlash', getData: flashFontsKey, pauseBefore: true }, + { key: 'audio', getData: audioKey }, + { key: 'enumerateDevices', getData: enumerateDevicesKey } + ] + + var Fingerprint2 = function (options) { + throw new Error("'new Fingerprint()' is deprecated, see https://github.com/Valve/fingerprintjs2#upgrade-guide-from-182-to-200") + } + + Fingerprint2.get = function (options, callback) { + if (!callback) { + callback = options + options = {} + } else if (!options) { + options = {} + } + extendSoft(options, defaultOptions) + options.components = options.extraComponents.concat(components) + + var keys = { + data: [], + addPreprocessedComponent: function (key, value) { + if (typeof options.preprocessor === 'function') { + value = options.preprocessor(key, value) + } + keys.data.push({ key: key, value: value }) + } + } + + var i = -1 + var chainComponents = function (alreadyWaited) { + i += 1 + if (i >= options.components.length) { // on finish + callback(keys.data) + return + } + var component = options.components[i] + + if (options.excludes[component.key]) { + chainComponents(false) // skip + return + } + + if (!alreadyWaited && component.pauseBefore) { + i -= 1 + setTimeout(function () { + chainComponents(true) + }, 1) + return + } + + try { + component.getData(function (value) { + keys.addPreprocessedComponent(component.key, value) + chainComponents(false) + }, options) + } catch (error) { + // main body error + keys.addPreprocessedComponent(component.key, String(error)) + chainComponents(false) + } + } + + chainComponents(false) + } + + Fingerprint2.getPromise = function (options) { + return new Promise(function (resolve, reject) { + Fingerprint2.get(options, resolve) + }) + } + + Fingerprint2.getV18 = function (options, callback) { + if (callback == null) { + callback = options + options = {} + } + return Fingerprint2.get(options, function (components) { + var newComponents = [] + for (var i = 0; i < components.length; i++) { + var component = components[i] + if (component.value === (options.NOT_AVAILABLE || 'not available')) { + newComponents.push({ key: component.key, value: 'unknown' }) + } else if (component.key === 'plugins') { + newComponents.push({ + key: 'plugins', + value: map(component.value, function (p) { + var mimeTypes = map(p[2], function (mt) { + if (mt.join) { return mt.join('~') } + return mt + }).join(',') + return [p[0], p[1], mimeTypes].join('::') + }) + }) + } else if (['canvas', 'webgl'].indexOf(component.key) !== -1) { + newComponents.push({ key: component.key, value: component.value.join('~') }) + } else if (['sessionStorage', 'localStorage', 'indexedDb', 'addBehavior', 'openDatabase'].indexOf(component.key) !== -1) { + if (component.value) { + newComponents.push({ key: component.key, value: 1 }) + } else { + // skip + continue + } + } else { + if (component.value) { + newComponents.push(component.value.join ? { key: component.key, value: component.value.join(';') } : component) + } else { + newComponents.push({ key: component.key, value: component.value }) + } + } + } + var murmur = x64hash128(map(newComponents, function (component) { return component.value }).join('~~~'), 31) + callback(murmur, newComponents) + }) + } + + Fingerprint2.x64hash128 = x64hash128 + Fingerprint2.VERSION = '2.1.0' + return Fingerprint2 +}) \ No newline at end of file diff --git a/html/production/hourglass.gif b/html/production/hourglass.gif new file mode 100644 index 0000000..645caeb Binary files /dev/null and b/html/production/hourglass.gif differ diff --git a/html/production/iron.js b/html/production/iron.js new file mode 100644 index 0000000..148572b --- /dev/null +++ b/html/production/iron.js @@ -0,0 +1 @@ +var _0x2241=['QsbrC','WnxbY','callback','CnOVo','ImmAe','fLkBP','DvDxN','itypF','Continue','JUHRP','vFakg','HHabC','lABPq','location','OHREX','AFmKs','fkHBg','tqDzP','EWFDC','xvBcN','encrypt','TWIdE','LFrjm','dMgum','klXXj','ghxxI','DEVICE_ORIENTATION','vWXqp','ONGum','HabvV','fjRQx','EBwbT','HozdT','ZwlAO','pEjin','dWzpQ','YuUeo','ozRni','swipe','ANxts','main','nmgNo','NZrkm','WXtKb','IoITl','YwfXG','DyvFl','CxSGD','SngRR','unbindEvent','ZAxZv','VqceB','QAdQO','WlXgs','dEaeB','XlqRL','gnNNj','QMdkk','Rcon','VzZIy','lOulc','mlxzv','RbQin','SPpiB','TuLHf','LUlGG','tYHyJ','HqqLw','touchstart','LtoOG','alpha','EZzEC','cDSuX','TkuLl','cSWSN','BpXeA','pgoEB','bBPBy','NdckG','cJlyY','JzGgg','xdPdx','pnZzI','ZEojI','kWChj','userAgent','toLowerCase','iv\x20length\x20must\x20be\x20128\x20bits.','UDyXL','SIZE_256','xXbgK','rbfUp','fWKpO','mnnxp','RjqCN','nJyUe','jPtrw','kjbpE','PMdYw','rOglE','BGSdn','attachEvent','gesture','MfkLP','eJrtR','kbdys','RUvlq','NZjmT','BMexY','CZQmT','zRQtN','mousemove','CqNbT','fdxxh','3|2|8|6|5|7|1|0|4','SCunj','getBlock','jZdMx','modeOfOperation','splice','jYtBc','yHnIJ','MmuMn','xBQZU','fYUAW','XNBfy','MSjfS','qDZZe','CeQxM','MMlSn','Zylfe','KJFHP','DEVICE_ORIENTATION_MOZ','uIDgo','dIMvT','PYgyU','4|5|1|0|2|3','update','WeAGr','YLdpK','tjDwH','ktQIZ','cwpdk','MlCHH','aDHUK','push','FeGVk','FCpTi','gfDzK','jsRGU','BNNfN','yvQQe','fQfQE','yBSHt','tpATS','fQeXs','oWrpy','VTBgW','jnWrE','EEwaj','QwKZA','jFFNX','get','nJoLg','YnjBQ','xZXMP','qkums','FHYQi','ubgLk','jukbO','FcgUR','pujAi','shiftRows','IcvZU','RANmv','yiyZi','vpFXw','wsIiH','KXDNm','pZYTC','fifMg','Kyrjq','HJpVI','ObroO','detachEvent','length','BqvJJ','ZiNvU','bZZxU','NZqAp','sxgiq','scroll','RJeOJ','TLzZX','uDXBC','mbAKo','XMMpG','bPVrG','ycOJz','success','OgCrF','iTXzW','nYVUo','MZsCy','zlnEB','lHByu','0|1|4|2|3','dlEqm','touchend','ntoTH','rsbox','VgARD','BXJYf','ecNKY','NDFMW','hwVJy','BPJes','href','hvQaK','OFYGV','SGrtc','CvSIA','oVYLo','DPpqZ','invRound','muKeK','keyup','mGBFb','HIAYk','indexOf','lExiy','UotXU','uxEDv','VXYdv','NvFFt','rCFfL','shiftRow','FVEYr','bTjBZ','iSvzT','Qbmnc','ZaCkN','BYwpI','NbzGv','fATgY','UYpNK','PjBGR','LSYqi','nJSdy','bOtgn','EETTk','4|1|2|0|3','tests','qwqHH','yPAKn','mgNtk','DoASJ','SgGxV','qVtnD','bugIN','Lugxx','wmFAJ','EwlNg','xxmrD','KDfsr','sbox','EiklJ','daQAb','RaawF','kVYwW','IiWtx','phoJs','pEjAL','Zvofz','ywCfp','SIZE_128','DmzsS','YyiQb','mLSSX','createRoundKey','kkDAo','DTLEQ','iuZju','KIyGs','PYxPV','CFB','vjCnn','dWdhu','Xanqy','qXVGl','NNsHy','GwGac','tclhJ','IwwSo','YOZOE','RYscN','MOUSE','wWbiJ','LKjIm','mvmtg','cwMRr','dwryw','TODyX','SWIPE_TOUCHSTART','JdzLc','0|8|4|6|10|2|3|5|7|1|9','mSgTj','CBC','nTkOt','removeEventListener','XMkLG','geIeu','kfuZf','oPRET','xgIOT','galois_multiplication','OFB','hrkjn','VQnEd','uVyKH','HqQVT','rfuDT','HfdyJ','MMIDo','pydjA','BgSGR','VfFvl','/captcha.html','UAHPL','snBfI','PuGNk','CumRn','OKcUs','auCrA','WRywP','undefined','jPMVT','fUvNV','getTime','ldEDb','wsQql','OZxEw','TbJHZ','sZPVv','xYVIQ','WCOMP','XHXDg','wrcAq','LbjYs','0|2|4|5|3|1','xMuMH','VGAGo','ZLXsA','expandKey','UHjrJ','Ioiui','mgufu','REczm','substring','yrDWW','moLuS','rgIAx','WSvtp','nTvpB','kyqjA','NwJdL','iGcZl','mKZzA','VfLIW','TDapZ','QDeeW','MshAQ','cookie','nufVI','ZTnLG','DOuPl','GvxVD','bindEvent','aSpqp','addRoundKey','DhIrF','LkRWS','MQqwL','CbQNI','mixColumns','WXZaL','HBdyC','numberOfRounds','MsXXB','SWIPE','DyCMM','ceil','SQwIX','sFGQm','VbIYa','NYXmp','EYnaf','ZBYaW','Oqmep','TPBVT','rwhNm','Ubepr','Uxzac','Ibasz','OFnBe','MzrLG','ujrtG','tsKzO','Jhdya','bxyxD','kZMIN','monitor','qYfVI','DEVICE_MOTION','ArDNm','OtxkM','gldDP','XOyZB','iHFMW','TAKkr','NwlIK','IMhLW','vgUcZ','iFOvo','EPUBS','jnqpr','fbUKY','caxYH','zYOWw','EMaRW','bHFIT','addEventListener','mAhqn','pZCoW','yLPhN','VZpLl','BTNCF','ZItEU','MmamI','mArhf','LWbFA','aKPGM','IMrQU','fcJtb','ZyntX','VFHSj','lastRotationData','qLSHS','pgMBY','Kbjcb','call','bBsiz','split','keySize','aicPF','pJBMh','allMatched','sNlbJ','uRXsB','replace','TlFsV','GxDce','hpZWe','Waqbe','NcjKp','iGldd','EhWdK','HGAcX','lfNCm','cases','tWgIp','qUwdc','izTmF','PwSUZ','APoDl','8|0|1|6|7|5|2|3|4','invMain','rotationRate','taFrI','Tests','ZBtRV','IFLHt','KLpew','boKks','oICqI','qvZKH','deviceorientation','EXitj','isKyV','KnAsJ','ryMUa','KEYUP','MozOrientation','VrVYF','HjHql','zTdsZ','dnGoy','KEnza','UDynn','7|6|5|8|1|2|0|4|3','vKRSX','gsNws','RIVbb','CZiOh','1|3|2|5|0|7|4|6','HgQJH','XQCBd','YCOwt','SBdPQ','BjyQC','RayJM','rRAjn','lOTQD','FNKxf','SCROLL','QVelX','wmeYm','JjpLA','3|4|1|2|0','weBOB','ttLHm','TwnKV','RWeyo','2|4|6|1|0|7|5|3','mOmNI','map','timeout','oywGl','TZOOc','KrQAA','UMmwz','fNgoo','goWBY','Kkzbu','android','lyGEi','OYcYE','pbWKi','XkMFn','key=','snoBm','qHSos','core','FTERi','MBjSd','YXDvn','join','zcDxD','slice','ylsud','WrmpT','FYnyS','devicemotion','rKOkM','BmijH','OanYI','WVGDy','value','lwooq','EENoz','jyPFF','beta','aKsDo','oFKTX','DYEIk','rzFfL','QboUd','aurpB','dwkZm','iMgGK','qBqMS','dnJLl','constructor','DKpoj','jYkJg','GifyF','bwFeJ','mixColumn','relPP','UuqlF','yszCg','jcukQ','FZHvQ','XCAIr','WWIYD','mrNcT','KYnOW','RiKfB','uhepd','sWluI','round','CEwZJ','dTCAI','IqmsY','bKZCe','OaLoG','vBjCy','NOkJe','rotate','IAdRt','aaMLW','pAPdS','kHzEB','BNDrK','AoNTl','oFQym','HozFY','vBSbq','VrlaA','DxtVe','YqHvL','UGESz','yfjcN','isBot','lIssX','KRkhg','ptOfT','YqAfV','1|6|5|8|4|2|7|3|0','CtHrI','EXbVa','hasOwnProperty','KdWui','HyHKK','GsHTd','UkaIq','yGHtI','KsWst','tlxqv','FAYFQ','QhzJs','qmqdl','WAQYu','JkplR','dSRfl','nRQmJ','OEqUf','subBytes','oMupQ','ujQPY','hJJxZ','pSKvH','zetrV','GFyKD',';\x20expires=Thu,\x201-Dec-25\x2000:00:00\x20GMT;\x20path=/','NvhEC','GMLqJ','decrypt','aYPoV','BLuWH','OqnCt','hKoIi','TIKYT','jwdaQ','RQRIF','toString','gbHyS','frsDg','pUARJ','TLoCZ','YfXCA','JBQvs','jhjiG','x64hash128','SLqye','meXVj','fyiAf','TNFKS','prototype','IeePq','gamma','AZlfN','zdjvF','QVumA','VSfEY','XDLCg','SGsQK','yzMwM','1|7|6|5|8|2|3|4|0','ZoJiF','aes','NtYUb','DUaKZ','hfOiG','4|1|2|0|3|5|6','ybLog','nQUjN','RMNTe','NftQS','dSEVV','gnbYy'];(function(_0x174619,_0x224177){var _0x56f6a9=function(_0x52f818){while(--_0x52f818){_0x174619['push'](_0x174619['shift']());}};_0x56f6a9(++_0x224177);}(_0x2241,0x8e));var _0x56f6=function(_0x174619,_0x224177){_0x174619=_0x174619-0x0;var _0x56f6a9=_0x2241[_0x174619];return _0x56f6a9;};var _0x7b9909=_0x56f6,ironUtility={'aes':{'keySize':{'SIZE_128':0x10,'SIZE_192':0x18,'SIZE_256':0x20},'sbox':[0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x1,0x67,0x2b,0xfe,0xd7,0xab,0x76,0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,0x4,0xc7,0x23,0xc3,0x18,0x96,0x5,0x9a,0x7,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,0x9,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,0x53,0xd1,0x0,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x2,0x7f,0x50,0x3c,0x9f,0xa8,0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,0xcd,0xc,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0xb,0xdb,0xe0,0x32,0x3a,0xa,0x49,0x6,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x8,0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,0x70,0x3e,0xb5,0x66,0x48,0x3,0xf6,0xe,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,0x8c,0xa1,0x89,0xd,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0xf,0xb0,0x54,0xbb,0x16],'rsbox':[0x52,0x9,0x6a,0xd5,0x30,0x36,0xa5,0x38,0xbf,0x40,0xa3,0x9e,0x81,0xf3,0xd7,0xfb,0x7c,0xe3,0x39,0x82,0x9b,0x2f,0xff,0x87,0x34,0x8e,0x43,0x44,0xc4,0xde,0xe9,0xcb,0x54,0x7b,0x94,0x32,0xa6,0xc2,0x23,0x3d,0xee,0x4c,0x95,0xb,0x42,0xfa,0xc3,0x4e,0x8,0x2e,0xa1,0x66,0x28,0xd9,0x24,0xb2,0x76,0x5b,0xa2,0x49,0x6d,0x8b,0xd1,0x25,0x72,0xf8,0xf6,0x64,0x86,0x68,0x98,0x16,0xd4,0xa4,0x5c,0xcc,0x5d,0x65,0xb6,0x92,0x6c,0x70,0x48,0x50,0xfd,0xed,0xb9,0xda,0x5e,0x15,0x46,0x57,0xa7,0x8d,0x9d,0x84,0x90,0xd8,0xab,0x0,0x8c,0xbc,0xd3,0xa,0xf7,0xe4,0x58,0x5,0xb8,0xb3,0x45,0x6,0xd0,0x2c,0x1e,0x8f,0xca,0x3f,0xf,0x2,0xc1,0xaf,0xbd,0x3,0x1,0x13,0x8a,0x6b,0x3a,0x91,0x11,0x41,0x4f,0x67,0xdc,0xea,0x97,0xf2,0xcf,0xce,0xf0,0xb4,0xe6,0x73,0x96,0xac,0x74,0x22,0xe7,0xad,0x35,0x85,0xe2,0xf9,0x37,0xe8,0x1c,0x75,0xdf,0x6e,0x47,0xf1,0x1a,0x71,0x1d,0x29,0xc5,0x89,0x6f,0xb7,0x62,0xe,0xaa,0x18,0xbe,0x1b,0xfc,0x56,0x3e,0x4b,0xc6,0xd2,0x79,0x20,0x9a,0xdb,0xc0,0xfe,0x78,0xcd,0x5a,0xf4,0x1f,0xdd,0xa8,0x33,0x88,0x7,0xc7,0x31,0xb1,0x12,0x10,0x59,0x27,0x80,0xec,0x5f,0x60,0x51,0x7f,0xa9,0x19,0xb5,0x4a,0xd,0x2d,0xe5,0x7a,0x9f,0x93,0xc9,0x9c,0xef,0xa0,0xe0,0x3b,0x4d,0xae,0x2a,0xf5,0xb0,0xc8,0xeb,0xbb,0x3c,0x83,0x53,0x99,0x61,0x17,0x2b,0x4,0x7e,0xba,0x77,0xd6,0x26,0xe1,0x69,0x14,0x63,0x55,0x21,0xc,0x7d],'rotate':function(_0x306de4){var _0x423bf3=_0x56f6,_0x2bf568={'mLSSX':function(_0x22f718,_0x43c2fc){return _0x22f718<_0x43c2fc;},'pujAi':function(_0x5c5423,_0x5e4d0d){return _0x5c5423+_0x5e4d0d;}},_0xa0c064=_0x306de4[0x0];for(var _0x28fa19=0x0;_0x2bf568[_0x423bf3('0x88')](_0x28fa19,0x3);_0x28fa19++)_0x306de4[_0x28fa19]=_0x306de4[_0x2bf568[_0x423bf3('0x1d')](_0x28fa19,0x1)];return _0x306de4[0x3]=_0xa0c064,_0x306de4;},'Rcon':[0x8d,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91,0x39,0x72,0xe4,0xd3,0xbd,0x61,0xc2,0x9f,0x25,0x4a,0x94,0x33,0x66,0xcc,0x83,0x1d,0x3a,0x74,0xe8,0xcb,0x8d,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91,0x39,0x72,0xe4,0xd3,0xbd,0x61,0xc2,0x9f,0x25,0x4a,0x94,0x33,0x66,0xcc,0x83,0x1d,0x3a,0x74,0xe8,0xcb,0x8d,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91,0x39,0x72,0xe4,0xd3,0xbd,0x61,0xc2,0x9f,0x25,0x4a,0x94,0x33,0x66,0xcc,0x83,0x1d,0x3a,0x74,0xe8,0xcb,0x8d,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91,0x39,0x72,0xe4,0xd3,0xbd,0x61,0xc2,0x9f,0x25,0x4a,0x94,0x33,0x66,0xcc,0x83,0x1d,0x3a,0x74,0xe8,0xcb,0x8d,0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80,0x1b,0x36,0x6c,0xd8,0xab,0x4d,0x9a,0x2f,0x5e,0xbc,0x63,0xc6,0x97,0x35,0x6a,0xd4,0xb3,0x7d,0xfa,0xef,0xc5,0x91,0x39,0x72,0xe4,0xd3,0xbd,0x61,0xc2,0x9f,0x25,0x4a,0x94,0x33,0x66,0xcc,0x83,0x1d,0x3a,0x74,0xe8,0xcb],'G2X':[0x0,0x2,0x4,0x6,0x8,0xa,0xc,0xe,0x10,0x12,0x14,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x24,0x26,0x28,0x2a,0x2c,0x2e,0x30,0x32,0x34,0x36,0x38,0x3a,0x3c,0x3e,0x40,0x42,0x44,0x46,0x48,0x4a,0x4c,0x4e,0x50,0x52,0x54,0x56,0x58,0x5a,0x5c,0x5e,0x60,0x62,0x64,0x66,0x68,0x6a,0x6c,0x6e,0x70,0x72,0x74,0x76,0x78,0x7a,0x7c,0x7e,0x80,0x82,0x84,0x86,0x88,0x8a,0x8c,0x8e,0x90,0x92,0x94,0x96,0x98,0x9a,0x9c,0x9e,0xa0,0xa2,0xa4,0xa6,0xa8,0xaa,0xac,0xae,0xb0,0xb2,0xb4,0xb6,0xb8,0xba,0xbc,0xbe,0xc0,0xc2,0xc4,0xc6,0xc8,0xca,0xcc,0xce,0xd0,0xd2,0xd4,0xd6,0xd8,0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xee,0xf0,0xf2,0xf4,0xf6,0xf8,0xfa,0xfc,0xfe,0x1b,0x19,0x1f,0x1d,0x13,0x11,0x17,0x15,0xb,0x9,0xf,0xd,0x3,0x1,0x7,0x5,0x3b,0x39,0x3f,0x3d,0x33,0x31,0x37,0x35,0x2b,0x29,0x2f,0x2d,0x23,0x21,0x27,0x25,0x5b,0x59,0x5f,0x5d,0x53,0x51,0x57,0x55,0x4b,0x49,0x4f,0x4d,0x43,0x41,0x47,0x45,0x7b,0x79,0x7f,0x7d,0x73,0x71,0x77,0x75,0x6b,0x69,0x6f,0x6d,0x63,0x61,0x67,0x65,0x9b,0x99,0x9f,0x9d,0x93,0x91,0x97,0x95,0x8b,0x89,0x8f,0x8d,0x83,0x81,0x87,0x85,0xbb,0xb9,0xbf,0xbd,0xb3,0xb1,0xb7,0xb5,0xab,0xa9,0xaf,0xad,0xa3,0xa1,0xa7,0xa5,0xdb,0xd9,0xdf,0xdd,0xd3,0xd1,0xd7,0xd5,0xcb,0xc9,0xcf,0xcd,0xc3,0xc1,0xc7,0xc5,0xfb,0xf9,0xff,0xfd,0xf3,0xf1,0xf7,0xf5,0xeb,0xe9,0xef,0xed,0xe3,0xe1,0xe7,0xe5],'G3X':[0x0,0x3,0x6,0x5,0xc,0xf,0xa,0x9,0x18,0x1b,0x1e,0x1d,0x14,0x17,0x12,0x11,0x30,0x33,0x36,0x35,0x3c,0x3f,0x3a,0x39,0x28,0x2b,0x2e,0x2d,0x24,0x27,0x22,0x21,0x60,0x63,0x66,0x65,0x6c,0x6f,0x6a,0x69,0x78,0x7b,0x7e,0x7d,0x74,0x77,0x72,0x71,0x50,0x53,0x56,0x55,0x5c,0x5f,0x5a,0x59,0x48,0x4b,0x4e,0x4d,0x44,0x47,0x42,0x41,0xc0,0xc3,0xc6,0xc5,0xcc,0xcf,0xca,0xc9,0xd8,0xdb,0xde,0xdd,0xd4,0xd7,0xd2,0xd1,0xf0,0xf3,0xf6,0xf5,0xfc,0xff,0xfa,0xf9,0xe8,0xeb,0xee,0xed,0xe4,0xe7,0xe2,0xe1,0xa0,0xa3,0xa6,0xa5,0xac,0xaf,0xaa,0xa9,0xb8,0xbb,0xbe,0xbd,0xb4,0xb7,0xb2,0xb1,0x90,0x93,0x96,0x95,0x9c,0x9f,0x9a,0x99,0x88,0x8b,0x8e,0x8d,0x84,0x87,0x82,0x81,0x9b,0x98,0x9d,0x9e,0x97,0x94,0x91,0x92,0x83,0x80,0x85,0x86,0x8f,0x8c,0x89,0x8a,0xab,0xa8,0xad,0xae,0xa7,0xa4,0xa1,0xa2,0xb3,0xb0,0xb5,0xb6,0xbf,0xbc,0xb9,0xba,0xfb,0xf8,0xfd,0xfe,0xf7,0xf4,0xf1,0xf2,0xe3,0xe0,0xe5,0xe6,0xef,0xec,0xe9,0xea,0xcb,0xc8,0xcd,0xce,0xc7,0xc4,0xc1,0xc2,0xd3,0xd0,0xd5,0xd6,0xdf,0xdc,0xd9,0xda,0x5b,0x58,0x5d,0x5e,0x57,0x54,0x51,0x52,0x43,0x40,0x45,0x46,0x4f,0x4c,0x49,0x4a,0x6b,0x68,0x6d,0x6e,0x67,0x64,0x61,0x62,0x73,0x70,0x75,0x76,0x7f,0x7c,0x79,0x7a,0x3b,0x38,0x3d,0x3e,0x37,0x34,0x31,0x32,0x23,0x20,0x25,0x26,0x2f,0x2c,0x29,0x2a,0xb,0x8,0xd,0xe,0x7,0x4,0x1,0x2,0x13,0x10,0x15,0x16,0x1f,0x1c,0x19,0x1a],'G9X':[0x0,0x9,0x12,0x1b,0x24,0x2d,0x36,0x3f,0x48,0x41,0x5a,0x53,0x6c,0x65,0x7e,0x77,0x90,0x99,0x82,0x8b,0xb4,0xbd,0xa6,0xaf,0xd8,0xd1,0xca,0xc3,0xfc,0xf5,0xee,0xe7,0x3b,0x32,0x29,0x20,0x1f,0x16,0xd,0x4,0x73,0x7a,0x61,0x68,0x57,0x5e,0x45,0x4c,0xab,0xa2,0xb9,0xb0,0x8f,0x86,0x9d,0x94,0xe3,0xea,0xf1,0xf8,0xc7,0xce,0xd5,0xdc,0x76,0x7f,0x64,0x6d,0x52,0x5b,0x40,0x49,0x3e,0x37,0x2c,0x25,0x1a,0x13,0x8,0x1,0xe6,0xef,0xf4,0xfd,0xc2,0xcb,0xd0,0xd9,0xae,0xa7,0xbc,0xb5,0x8a,0x83,0x98,0x91,0x4d,0x44,0x5f,0x56,0x69,0x60,0x7b,0x72,0x5,0xc,0x17,0x1e,0x21,0x28,0x33,0x3a,0xdd,0xd4,0xcf,0xc6,0xf9,0xf0,0xeb,0xe2,0x95,0x9c,0x87,0x8e,0xb1,0xb8,0xa3,0xaa,0xec,0xe5,0xfe,0xf7,0xc8,0xc1,0xda,0xd3,0xa4,0xad,0xb6,0xbf,0x80,0x89,0x92,0x9b,0x7c,0x75,0x6e,0x67,0x58,0x51,0x4a,0x43,0x34,0x3d,0x26,0x2f,0x10,0x19,0x2,0xb,0xd7,0xde,0xc5,0xcc,0xf3,0xfa,0xe1,0xe8,0x9f,0x96,0x8d,0x84,0xbb,0xb2,0xa9,0xa0,0x47,0x4e,0x55,0x5c,0x63,0x6a,0x71,0x78,0xf,0x6,0x1d,0x14,0x2b,0x22,0x39,0x30,0x9a,0x93,0x88,0x81,0xbe,0xb7,0xac,0xa5,0xd2,0xdb,0xc0,0xc9,0xf6,0xff,0xe4,0xed,0xa,0x3,0x18,0x11,0x2e,0x27,0x3c,0x35,0x42,0x4b,0x50,0x59,0x66,0x6f,0x74,0x7d,0xa1,0xa8,0xb3,0xba,0x85,0x8c,0x97,0x9e,0xe9,0xe0,0xfb,0xf2,0xcd,0xc4,0xdf,0xd6,0x31,0x38,0x23,0x2a,0x15,0x1c,0x7,0xe,0x79,0x70,0x6b,0x62,0x5d,0x54,0x4f,0x46],'GBX':[0x0,0xb,0x16,0x1d,0x2c,0x27,0x3a,0x31,0x58,0x53,0x4e,0x45,0x74,0x7f,0x62,0x69,0xb0,0xbb,0xa6,0xad,0x9c,0x97,0x8a,0x81,0xe8,0xe3,0xfe,0xf5,0xc4,0xcf,0xd2,0xd9,0x7b,0x70,0x6d,0x66,0x57,0x5c,0x41,0x4a,0x23,0x28,0x35,0x3e,0xf,0x4,0x19,0x12,0xcb,0xc0,0xdd,0xd6,0xe7,0xec,0xf1,0xfa,0x93,0x98,0x85,0x8e,0xbf,0xb4,0xa9,0xa2,0xf6,0xfd,0xe0,0xeb,0xda,0xd1,0xcc,0xc7,0xae,0xa5,0xb8,0xb3,0x82,0x89,0x94,0x9f,0x46,0x4d,0x50,0x5b,0x6a,0x61,0x7c,0x77,0x1e,0x15,0x8,0x3,0x32,0x39,0x24,0x2f,0x8d,0x86,0x9b,0x90,0xa1,0xaa,0xb7,0xbc,0xd5,0xde,0xc3,0xc8,0xf9,0xf2,0xef,0xe4,0x3d,0x36,0x2b,0x20,0x11,0x1a,0x7,0xc,0x65,0x6e,0x73,0x78,0x49,0x42,0x5f,0x54,0xf7,0xfc,0xe1,0xea,0xdb,0xd0,0xcd,0xc6,0xaf,0xa4,0xb9,0xb2,0x83,0x88,0x95,0x9e,0x47,0x4c,0x51,0x5a,0x6b,0x60,0x7d,0x76,0x1f,0x14,0x9,0x2,0x33,0x38,0x25,0x2e,0x8c,0x87,0x9a,0x91,0xa0,0xab,0xb6,0xbd,0xd4,0xdf,0xc2,0xc9,0xf8,0xf3,0xee,0xe5,0x3c,0x37,0x2a,0x21,0x10,0x1b,0x6,0xd,0x64,0x6f,0x72,0x79,0x48,0x43,0x5e,0x55,0x1,0xa,0x17,0x1c,0x2d,0x26,0x3b,0x30,0x59,0x52,0x4f,0x44,0x75,0x7e,0x63,0x68,0xb1,0xba,0xa7,0xac,0x9d,0x96,0x8b,0x80,0xe9,0xe2,0xff,0xf4,0xc5,0xce,0xd3,0xd8,0x7a,0x71,0x6c,0x67,0x56,0x5d,0x40,0x4b,0x22,0x29,0x34,0x3f,0xe,0x5,0x18,0x13,0xca,0xc1,0xdc,0xd7,0xe6,0xed,0xf0,0xfb,0x92,0x99,0x84,0x8f,0xbe,0xb5,0xa8,0xa3],'GDX':[0x0,0xd,0x1a,0x17,0x34,0x39,0x2e,0x23,0x68,0x65,0x72,0x7f,0x5c,0x51,0x46,0x4b,0xd0,0xdd,0xca,0xc7,0xe4,0xe9,0xfe,0xf3,0xb8,0xb5,0xa2,0xaf,0x8c,0x81,0x96,0x9b,0xbb,0xb6,0xa1,0xac,0x8f,0x82,0x95,0x98,0xd3,0xde,0xc9,0xc4,0xe7,0xea,0xfd,0xf0,0x6b,0x66,0x71,0x7c,0x5f,0x52,0x45,0x48,0x3,0xe,0x19,0x14,0x37,0x3a,0x2d,0x20,0x6d,0x60,0x77,0x7a,0x59,0x54,0x43,0x4e,0x5,0x8,0x1f,0x12,0x31,0x3c,0x2b,0x26,0xbd,0xb0,0xa7,0xaa,0x89,0x84,0x93,0x9e,0xd5,0xd8,0xcf,0xc2,0xe1,0xec,0xfb,0xf6,0xd6,0xdb,0xcc,0xc1,0xe2,0xef,0xf8,0xf5,0xbe,0xb3,0xa4,0xa9,0x8a,0x87,0x90,0x9d,0x6,0xb,0x1c,0x11,0x32,0x3f,0x28,0x25,0x6e,0x63,0x74,0x79,0x5a,0x57,0x40,0x4d,0xda,0xd7,0xc0,0xcd,0xee,0xe3,0xf4,0xf9,0xb2,0xbf,0xa8,0xa5,0x86,0x8b,0x9c,0x91,0xa,0x7,0x10,0x1d,0x3e,0x33,0x24,0x29,0x62,0x6f,0x78,0x75,0x56,0x5b,0x4c,0x41,0x61,0x6c,0x7b,0x76,0x55,0x58,0x4f,0x42,0x9,0x4,0x13,0x1e,0x3d,0x30,0x27,0x2a,0xb1,0xbc,0xab,0xa6,0x85,0x88,0x9f,0x92,0xd9,0xd4,0xc3,0xce,0xed,0xe0,0xf7,0xfa,0xb7,0xba,0xad,0xa0,0x83,0x8e,0x99,0x94,0xdf,0xd2,0xc5,0xc8,0xeb,0xe6,0xf1,0xfc,0x67,0x6a,0x7d,0x70,0x53,0x5e,0x49,0x44,0xf,0x2,0x15,0x18,0x3b,0x36,0x21,0x2c,0xc,0x1,0x16,0x1b,0x38,0x35,0x22,0x2f,0x64,0x69,0x7e,0x73,0x50,0x5d,0x4a,0x47,0xdc,0xd1,0xc6,0xcb,0xe8,0xe5,0xf2,0xff,0xb4,0xb9,0xae,0xa3,0x80,0x8d,0x9a,0x97],'GEX':[0x0,0xe,0x1c,0x12,0x38,0x36,0x24,0x2a,0x70,0x7e,0x6c,0x62,0x48,0x46,0x54,0x5a,0xe0,0xee,0xfc,0xf2,0xd8,0xd6,0xc4,0xca,0x90,0x9e,0x8c,0x82,0xa8,0xa6,0xb4,0xba,0xdb,0xd5,0xc7,0xc9,0xe3,0xed,0xff,0xf1,0xab,0xa5,0xb7,0xb9,0x93,0x9d,0x8f,0x81,0x3b,0x35,0x27,0x29,0x3,0xd,0x1f,0x11,0x4b,0x45,0x57,0x59,0x73,0x7d,0x6f,0x61,0xad,0xa3,0xb1,0xbf,0x95,0x9b,0x89,0x87,0xdd,0xd3,0xc1,0xcf,0xe5,0xeb,0xf9,0xf7,0x4d,0x43,0x51,0x5f,0x75,0x7b,0x69,0x67,0x3d,0x33,0x21,0x2f,0x5,0xb,0x19,0x17,0x76,0x78,0x6a,0x64,0x4e,0x40,0x52,0x5c,0x6,0x8,0x1a,0x14,0x3e,0x30,0x22,0x2c,0x96,0x98,0x8a,0x84,0xae,0xa0,0xb2,0xbc,0xe6,0xe8,0xfa,0xf4,0xde,0xd0,0xc2,0xcc,0x41,0x4f,0x5d,0x53,0x79,0x77,0x65,0x6b,0x31,0x3f,0x2d,0x23,0x9,0x7,0x15,0x1b,0xa1,0xaf,0xbd,0xb3,0x99,0x97,0x85,0x8b,0xd1,0xdf,0xcd,0xc3,0xe9,0xe7,0xf5,0xfb,0x9a,0x94,0x86,0x88,0xa2,0xac,0xbe,0xb0,0xea,0xe4,0xf6,0xf8,0xd2,0xdc,0xce,0xc0,0x7a,0x74,0x66,0x68,0x42,0x4c,0x5e,0x50,0xa,0x4,0x16,0x18,0x32,0x3c,0x2e,0x20,0xec,0xe2,0xf0,0xfe,0xd4,0xda,0xc8,0xc6,0x9c,0x92,0x80,0x8e,0xa4,0xaa,0xb8,0xb6,0xc,0x2,0x10,0x1e,0x34,0x3a,0x28,0x26,0x7c,0x72,0x60,0x6e,0x44,0x4a,0x58,0x56,0x37,0x39,0x2b,0x25,0xf,0x1,0x13,0x1d,0x47,0x49,0x5b,0x55,0x7f,0x71,0x63,0x6d,0xd7,0xd9,0xcb,0xc5,0xef,0xe1,0xf3,0xfd,0xa7,0xa9,0xbb,0xb5,0x9f,0x91,0x83,0x8d],'core':function(_0x5a560a,_0x1341af){var _0x2fd3e4=_0x56f6,_0x226316={'MjCQd':function(_0x30d819,_0x28ef6e){return _0x30d819<_0x28ef6e;},'uRXsB':function(_0x5c82a2,_0x1cddbd){return _0x5c82a2^_0x1cddbd;}};_0x5a560a=this[_0x2fd3e4('0x1c8')](_0x5a560a);for(var _0x35057f=0x0;_0x226316['MjCQd'](_0x35057f,0x4);++_0x35057f)_0x5a560a[_0x35057f]=this['sbox'][_0x5a560a[_0x35057f]];return _0x5a560a[0x0]=_0x226316[_0x2fd3e4('0x13c')](_0x5a560a[0x0],this[_0x2fd3e4('0x25f')][_0x1341af]),_0x5a560a;},'expandKey':function(_0x373480,_0x11f5f3){var _0x1f0db8=_0x56f6,_0x116514={'aicPF':_0x1f0db8('0xa3'),'NZjmT':function(_0x21e8b1,_0x151c14){return _0x21e8b1>_0x151c14;},'EWFDC':function(_0x1cb4c4,_0x5199d8){return _0x1cb4c4-_0x5199d8;},'oywGl':function(_0x5535f0,_0xa9d338){return _0x5535f0+_0xa9d338;},'oBDzm':_0x1f0db8('0x27c'),'muKeK':function(_0xf09950,_0x2c6137){return _0xf09950<_0x2c6137;},'dIMvT':function(_0xcf14dc,_0x2750e9){return _0xcf14dc===_0x2750e9;},'eOLqS':_0x1f0db8('0x41'),'dWzpQ':_0x1f0db8('0x27d'),'iuZju':function(_0x5bb263,_0x52bf4c){return _0x5bb263-_0x52bf4c;},'HJpVI':function(_0xabb91,_0x3c3fef){return _0xabb91==_0x3c3fef;},'aKPGM':function(_0x5ab118,_0x54665c){return _0x5ab118%_0x54665c;},'xeqJV':function(_0x16d53a,_0x503062){return _0x16d53a<_0x503062;},'LWbFA':function(_0x2afc81,_0x4b99fc){return _0x2afc81<_0x4b99fc;},'IiWtx':function(_0x4191e6,_0x96cdb5){return _0x4191e6!==_0x96cdb5;},'TDapZ':_0x1f0db8('0x159'),'QAdQO':_0x1f0db8('0x197'),'Oqmep':function(_0xc22d6b,_0x3d1320){return _0xc22d6b^_0x3d1320;},'HSodl':function(_0x365c0c,_0x1e75e4){return _0x365c0c*_0x1e75e4;},'TlFsV':function(_0x1f45b4,_0x280075){return _0x1f45b4+_0x280075;}},_0x4a6fc1=_0x116514[_0x1f0db8('0x138')]['split']('|'),_0x363cf3=0x0;while(!![]){switch(_0x4a6fc1[_0x363cf3++]){case'0':var _0x4f1ed7={'GvxVD':function(_0x4fb778,_0x4083a8){var _0xfa89fb=_0x1f0db8;return _0x116514[_0xfa89fb('0x290')](_0x4fb778,_0x4083a8);},'yBSHt':function(_0x2bd34e,_0x36f44e){var _0x41d4b9=_0x1f0db8;return _0x116514[_0x41d4b9('0x237')](_0x2bd34e,_0x36f44e);},'EBwbT':function(_0x1ca7f8,_0x4c16f1){var _0x5c0fe3=_0x1f0db8;return _0x116514[_0x5c0fe3('0x181')](_0x1ca7f8,_0x4c16f1);},'EhNjd':_0x116514['oBDzm']};continue;case'1':while(_0x116514['muKeK'](_0x1188b0,_0x581d65)){if(_0x116514[_0x1f0db8('0x2ab')](_0x116514['eOLqS'],_0x116514[_0x1f0db8('0x248')])){function _0x5f53ff(){var _0x5a53ad=_0x1f0db8;if(_0x4f1ed7[_0x5a53ad('0xea')](_0x4f1ed7[_0x5a53ad('0xb')](_0x2c7892,_0x249232),0x10))_0x3d53b0=_0x4f1ed7[_0x5a53ad('0x244')](_0x33667f,0x10);return _0x2914cd[_0x5a53ad('0x196')](_0x5a06fa,_0x554527);}}else{for(var _0x4eb5dc=0x0;_0x116514[_0x1f0db8('0x53')](_0x4eb5dc,0x4);_0x4eb5dc++)_0x3a1615[_0x4eb5dc]=_0x257b7a[_0x116514[_0x1f0db8('0x181')](_0x116514[_0x1f0db8('0x8c')](_0x1188b0,0x4),_0x4eb5dc)];if(_0x116514[_0x1f0db8('0x28')](_0x116514[_0x1f0db8('0x12b')](_0x1188b0,_0x11f5f3),0x0))_0x3a1615=this[_0x1f0db8('0x190')](_0x3a1615,_0x1f24d6++);if(_0x116514[_0x1f0db8('0x28')](_0x11f5f3,this[_0x1f0db8('0x137')]['SIZE_256'])&&_0x116514['HJpVI'](_0x116514[_0x1f0db8('0x12b')](_0x1188b0,_0x11f5f3),0x10))for(var _0x32b360=0x0;_0x116514['xeqJV'](_0x32b360,0x4);_0x32b360++)_0x3a1615[_0x32b360]=this['sbox'][_0x3a1615[_0x32b360]];for(var _0x300200=0x0;_0x116514['LWbFA'](_0x300200,0x4);_0x300200++){if(_0x116514[_0x1f0db8('0x80')](_0x116514[_0x1f0db8('0xe3')],_0x116514[_0x1f0db8('0x259')]))_0x257b7a[_0x1188b0]=_0x116514[_0x1f0db8('0x100')](_0x257b7a[_0x116514['iuZju'](_0x1188b0,_0x11f5f3)],_0x3a1615[_0x300200]),_0x1188b0++;else{function _0x5d34d6(){throw _0x4f1ed7['EhNjd'];}}}}}continue;case'2':var _0x257b7a=[];continue;case'3':for(var _0x4c3c1c=0x0;_0x116514[_0x1f0db8('0x12a')](_0x4c3c1c,_0x581d65);_0x4c3c1c++)_0x257b7a[_0x4c3c1c]=0x0;continue;case'4':var _0x1188b0=0x0;continue;case'5':for(var _0x4468df=0x0;_0x116514[_0x1f0db8('0x12a')](_0x4468df,_0x11f5f3);_0x4468df++)_0x257b7a[_0x4468df]=_0x373480[_0x4468df];continue;case'6':var _0x1f24d6=0x1;continue;case'7':_0x1188b0+=_0x11f5f3;continue;case'8':var _0x581d65=_0x116514['HSodl'](0x10,_0x116514[_0x1f0db8('0x13e')](this[_0x1f0db8('0xf5')](_0x11f5f3),0x1));continue;case'9':return _0x257b7a;case'10':var _0x3a1615=[];continue;}break;}},'addRoundKey':function(_0x1de655,_0x28f079){var _0x39884d=_0x56f6,_0x1cc3cf={'PMdYw':function(_0x15e347,_0x10d03d){return _0x15e347<_0x10d03d;}};for(var _0x5cf50a=0x0;_0x1cc3cf[_0x39884d('0x287')](_0x5cf50a,0x10);_0x5cf50a++)_0x1de655[_0x5cf50a]^=_0x28f079[_0x5cf50a];return _0x1de655;},'createRoundKey':function(_0x3b6a2d,_0x45fa8e){var _0x2a9b6d=_0x56f6,_0x1a9090={'FNKxf':function(_0x57cbd1,_0x2c95e5){return _0x57cbd1<_0x2c95e5;},'WXZaL':function(_0x6e88f5,_0xd6335b){return _0x6e88f5+_0xd6335b;},'hfOiG':function(_0x4d3fce,_0x504a7c){return _0x4d3fce*_0x504a7c;},'qwqHH':function(_0x5c3073,_0x36b34b){return _0x5c3073+_0x36b34b;}},_0x21510f=[];for(var _0x2c91f2=0x0;_0x1a9090[_0x2a9b6d('0x173')](_0x2c91f2,0x4);_0x2c91f2++)for(var _0x3ff679=0x0;_0x1a9090[_0x2a9b6d('0x173')](_0x3ff679,0x4);_0x3ff679++)_0x21510f[_0x1a9090[_0x2a9b6d('0xf3')](_0x1a9090[_0x2a9b6d('0x21d')](_0x3ff679,0x4),_0x2c91f2)]=_0x3b6a2d[_0x1a9090[_0x2a9b6d('0xf3')](_0x1a9090[_0x2a9b6d('0x6f')](_0x45fa8e,_0x1a9090['hfOiG'](_0x2c91f2,0x4)),_0x3ff679)];return _0x21510f;},'subBytes':function(_0x25eac2,_0x5a001e){var _0x5a7e81=_0x56f6,_0xf76c31={'wsIiH':function(_0x390ee2,_0x14e181){return _0x390ee2<_0x14e181;}};for(var _0x12cdea=0x0;_0xf76c31[_0x5a7e81('0x23')](_0x12cdea,0x10);_0x12cdea++)_0x25eac2[_0x12cdea]=_0x5a001e?this[_0x5a7e81('0x44')][_0x25eac2[_0x12cdea]]:this[_0x5a7e81('0x7b')][_0x25eac2[_0x12cdea]];return _0x25eac2;},'shiftRows':function(_0x177c5c,_0x533c72){var _0x4a62be=_0x56f6,_0x35b439={'uxEDv':function(_0xdddd5a,_0xf5f5e5){return _0xdddd5a<_0xf5f5e5;},'VfFvl':function(_0xc80c,_0x12d265){return _0xc80c*_0x12d265;}};for(var _0x1d22c3=0x0;_0x35b439[_0x4a62be('0x5a')](_0x1d22c3,0x4);_0x1d22c3++)_0x177c5c=this[_0x4a62be('0x5e')](_0x177c5c,_0x35b439[_0x4a62be('0xb8')](_0x1d22c3,0x4),_0x1d22c3,_0x533c72);return _0x177c5c;},'shiftRow':function(_0x4989c2,_0x3cd20c,_0x18ba32,_0x52c7c0){var _0xab2fbe=_0x56f6,_0x253392={'cwpdk':'3|7|4|9|6|5|8|0|1|2','JzGgg':function(_0xb0a9d2,_0x24a861){return _0xb0a9d2<_0x24a861;},'FVEYr':function(_0x1a1563,_0x213d02){return _0x1a1563<_0x213d02;},'RayJM':function(_0x113d62,_0x3963dd){return _0x113d62+_0x3963dd;},'lyztr':function(_0x35311c,_0x416bd5){return _0x35311c-_0x416bd5;},'RANmv':function(_0x4c029e,_0x47e150){return _0x4c029e==_0x47e150;},'jhjiG':function(_0x40c416,_0x33b26a){return _0x40c416%_0x33b26a;},'gbHyS':function(_0x4d2832,_0x29956e){return _0x4d2832==_0x29956e;},'iTXzW':function(_0x122ae2,_0x2ca93e){return _0x122ae2==_0x2ca93e;},'NftQS':function(_0x28338f,_0x3fa6e1){return _0x28338f<_0x3fa6e1;},'ujrtG':function(_0x9b8be4,_0x2ce885){return _0x9b8be4^_0x2ce885;},'TZOOc':function(_0x3b47d0,_0x170432){return _0x3b47d0-_0x170432;},'gqTld':function(_0x3b0a3c,_0x3186ca){return _0x3b0a3c*_0x3186ca;},'FmqAK':function(_0x6613d1,_0x2f53ee){return _0x6613d1+_0x2f53ee;},'ArDNm':function(_0x4367e9,_0x238616){return _0x4367e9<_0x238616;},'dWdhu':function(_0xa0b28a,_0x3d7e68){return _0xa0b28a<_0x3d7e68;},'MshAQ':function(_0x31bb64,_0x3d39e4){return _0x31bb64<_0x3d39e4;},'lExiy':function(_0x299f25,_0x123ff4){return _0x299f25<_0x123ff4;},'bZZxU':function(_0xd34efa,_0x19f8d5){return _0xd34efa+_0x19f8d5;},'EwlNg':function(_0x31a75a,_0x2abe3a){return _0x31a75a<_0x2abe3a;},'NtYUb':function(_0x513d18,_0x14072d){return _0x513d18+_0x14072d;},'gUJuL':function(_0x43f9d7,_0x5f16b6){return _0x43f9d7*_0x5f16b6;},'KLpew':_0xab2fbe('0x165'),'UuqlF':function(_0x17aec4,_0x27a049){return _0x17aec4>_0x27a049;},'rKolw':function(_0x2c5743,_0x1d95b0){return _0x2c5743>_0x1d95b0;},'wzGLz':function(_0x2e6384,_0x152977){return _0x2e6384==_0x152977;},'QhzJs':function(_0x50f5a2,_0x5c32ce){return _0x50f5a2&_0x5c32ce;},'vBjCy':function(_0x396e20,_0x114ab0){return _0x396e20>_0x114ab0;},'LFrjm':function(_0x308a7d,_0x560fb2){return _0x308a7d==_0x560fb2;},'OEqUf':function(_0x295da0,_0x24f000){return _0x295da0&_0x24f000;},'pgMBY':function(_0x2b106a,_0x4fa6ed){return _0x2b106a<_0x4fa6ed;},'nTvpB':function(_0x97571f,_0x5938d6){return _0x97571f!==_0x5938d6;},'jZdMx':_0xab2fbe('0x26c'),'GxDce':'OIYwb','KsWst':function(_0x3ee660,_0x3bc6aa){return _0x3ee660===_0x3bc6aa;},'cSWSN':_0xab2fbe('0x27f'),'FAYFQ':function(_0x52a7f5,_0x27ab8d){return _0x52a7f5-_0x27ab8d;},'UHjrJ':function(_0xa9928a,_0x2c5fdd){return _0xa9928a===_0x2c5fdd;},'jnqpr':_0xab2fbe('0x2a6'),'XQCBd':function(_0x5afdd4,_0x5475e8){return _0x5afdd4+_0x5475e8;},'PjBGR':function(_0x3f649f,_0x289aa4){return _0x3f649f+_0x289aa4;}};for(var _0x5a12d9=0x0;_0x253392[_0xab2fbe('0x132')](_0x5a12d9,_0x18ba32);_0x5a12d9++){if(_0x253392[_0xab2fbe('0xdd')](_0x253392[_0xab2fbe('0x29a')],_0x253392[_0xab2fbe('0x13f')])){if(_0x52c7c0){if(_0x253392[_0xab2fbe('0x1e5')](_0x253392[_0xab2fbe('0x26f')],_0x253392[_0xab2fbe('0x26f')])){var _0xe95341=_0x4989c2[_0x253392[_0xab2fbe('0x21b')](_0x3cd20c,0x3)];for(var _0x196a9e=0x3;_0x253392['vBjCy'](_0x196a9e,0x0);_0x196a9e--)_0x4989c2[_0x253392[_0xab2fbe('0x21b')](_0x3cd20c,_0x196a9e)]=_0x4989c2[_0x253392[_0xab2fbe('0x1e7')](_0x253392[_0xab2fbe('0x21b')](_0x3cd20c,_0x196a9e),0x1)];_0x4989c2[_0x3cd20c]=_0xe95341;}else{function _0x26084e(){var _0x4cc98e=_0xab2fbe,_0x10cdac=_0x253392[_0x4cc98e('0x0')][_0x4cc98e('0x136')]('|'),_0x246eaf=0x0;while(!![]){switch(_0x10cdac[_0x246eaf++]){case'0':_0x4231f7+=_0x175f17;continue;case'1':while(_0x253392[_0x4cc98e('0x275')](_0x4231f7,_0x12e553)){for(var _0x274811=0x0;_0x253392[_0x4cc98e('0x5f')](_0x274811,0x4);_0x274811++)_0x4fe38c[_0x274811]=_0x459d39[_0x253392[_0x4cc98e('0x170')](_0x253392['lyztr'](_0x4231f7,0x4),_0x274811)];if(_0x253392[_0x4cc98e('0x20')](_0x253392[_0x4cc98e('0x208')](_0x4231f7,_0x413d4b),0x0))_0x4fe38c=this[_0x4cc98e('0x190')](_0x4fe38c,_0x4f9e6d++);if(_0x253392[_0x4cc98e('0x202')](_0x682ee5,this[_0x4cc98e('0x137')][_0x4cc98e('0x27e')])&&_0x253392[_0x4cc98e('0x3b')](_0x253392[_0x4cc98e('0x208')](_0x4231f7,_0x1054d0),0x10))for(var _0x1e1aea=0x0;_0x253392[_0x4cc98e('0x5f')](_0x1e1aea,0x4);_0x1e1aea++)_0x4fe38c[_0x1e1aea]=this['sbox'][_0x4fe38c[_0x1e1aea]];for(var _0x1563c8=0x0;_0x253392[_0x4cc98e('0x222')](_0x1563c8,0x4);_0x1563c8++){_0x459d39[_0x4231f7]=_0x253392[_0x4cc98e('0x108')](_0x459d39[_0x253392[_0x4cc98e('0x182')](_0x4231f7,_0x110215)],_0x4fe38c[_0x1563c8]),_0x4231f7++;}}continue;case'2':return _0x459d39;case'3':var _0x12e553=_0x253392['gqTld'](0x10,_0x253392['FmqAK'](this['numberOfRounds'](_0x455b1b),0x1));continue;case'4':var _0x4f9e6d=0x1;continue;case'5':for(var _0x5d006c=0x0;_0x253392[_0x4cc98e('0x110')](_0x5d006c,_0x12e553);_0x5d006c++)_0x459d39[_0x5d006c]=0x0;continue;case'6':var _0x459d39=[];continue;case'7':var _0x4231f7=0x0;continue;case'8':for(var _0x24c94e=0x0;_0x253392[_0x4cc98e('0x91')](_0x24c94e,_0x1f19d3);_0x24c94e++)_0x459d39[_0x24c94e]=_0x402c8c[_0x24c94e];continue;case'9':var _0x4fe38c=[];continue;}break;}}}}else{if(_0x253392[_0xab2fbe('0xd4')](_0x253392[_0xab2fbe('0x11b')],_0x253392['jnqpr'])){var _0xe95341=_0x4989c2[_0x3cd20c];for(var _0x196a9e=0x0;_0x253392[_0xab2fbe('0x132')](_0x196a9e,0x3);_0x196a9e++)_0x4989c2[_0x253392[_0xab2fbe('0x16c')](_0x3cd20c,_0x196a9e)]=_0x4989c2[_0x253392[_0xab2fbe('0x16c')](_0x253392['XQCBd'](_0x3cd20c,_0x196a9e),0x1)];_0x4989c2[_0x253392[_0xab2fbe('0x68')](_0x3cd20c,0x3)]=_0xe95341;}else{function _0x5503cc(){var _0x9e507c=_0xab2fbe,_0x54d169=[];for(var _0x4b3d9e=0x0;_0x253392[_0x9e507c('0xe5')](_0x4b3d9e,0x4);_0x4b3d9e++){for(var _0x42a88f=0x0;_0x253392[_0x9e507c('0x58')](_0x42a88f,0x4);_0x42a88f++)_0x54d169[_0x42a88f]=_0x252e01[_0x253392[_0x9e507c('0x2e')](_0x253392['gqTld'](_0x42a88f,0x4),_0x4b3d9e)];_0x54d169=this['mixColumn'](_0x54d169,_0x3ef55d);for(var _0x116c1d=0x0;_0x253392[_0x9e507c('0x78')](_0x116c1d,0x4);_0x116c1d++)_0x58164d[_0x253392['NtYUb'](_0x253392['gUJuL'](_0x116c1d,0x4),_0x4b3d9e)]=_0x54d169[_0x116c1d];}return _0x3b0cd9;}}}}else{function _0x15452f(){var _0x43d5a3=_0xab2fbe,_0xdedb19=_0x253392[_0x43d5a3('0x154')][_0x43d5a3('0x136')]('|'),_0x18d768=0x0;while(!![]){switch(_0xdedb19[_0x18d768++]){case'0':if(_0x253392[_0x43d5a3('0x1b5')](_0x3d7a31,0x100))_0x35edf8^=0x100;continue;case'1':if(_0x253392['rKolw'](_0x5d39e9,0x100))_0x4cdd4d^=0x100;continue;case'2':if(_0x253392['wzGLz'](_0x25450a,0x80))_0x460e8e^=0x1b;continue;case'3':if(_0x253392['rKolw'](_0x567194,0x100))_0x13d752^=0x100;continue;case'4':_0x2871c5>>=0x1;continue;case'5':var _0x25450a=_0x253392[_0x43d5a3('0x1e8')](_0x6adc73,0x80);continue;case'6':if(_0x253392[_0x43d5a3('0x1c6')](_0x2ca063,0x100))_0x12ac3e^=0x100;continue;case'7':if(_0x253392[_0x43d5a3('0x23b')](_0x253392[_0x43d5a3('0x1ee')](_0x2cf6e1,0x1),0x1))_0x30e7d7^=_0x2b0a1f;continue;case'8':_0x8db89f<<=0x1;continue;}break;}}}}return _0x4989c2;},'galois_multiplication':function(_0x3c1ca6,_0x4430b3){var _0x5c0fdc=_0x56f6,_0x554eea={'upzsP':function(_0x2d362e,_0x50a5e0){return _0x2d362e-_0x50a5e0;},'BGSdn':function(_0x361f5d,_0x312d65){return _0x361f5d<_0x312d65;},'ntDCa':function(_0x34b982,_0x8d66e2){return _0x34b982===_0x8d66e2;},'ZoJiF':'GvHTZ','oFKTX':'XakzK','EETTk':_0x5c0fdc('0x218'),'YCOwt':function(_0x408d1e,_0x3bc476){return _0x408d1e>_0x3bc476;},'TODyX':function(_0x1d07f0,_0x53b55f){return _0x1d07f0==_0x53b55f;},'kkDAo':function(_0x322ed9,_0x56af47){return _0x322ed9&_0x56af47;},'tlxqv':function(_0x458cc1,_0x19c901){return _0x458cc1>_0x19c901;},'bBsiz':function(_0x19cddf,_0x450c8f){return _0x19cddf>_0x450c8f;}},_0x435ab9=0x0;for(var _0x5af95d=0x0;_0x554eea[_0x5c0fdc('0x289')](_0x5af95d,0x8);_0x5af95d++){if(_0x554eea['ntDCa'](_0x554eea[_0x5c0fdc('0x219')],_0x554eea[_0x5c0fdc('0x1a5')])){function _0x204279(){var _0x477c9c=_0x5c0fdc,_0x292ec4={'Ioiui':function(_0x26117e,_0x29bcb3){return _0x554eea['upzsP'](_0x26117e,_0x29bcb3);}},_0x357728=new _0x7b7b87();_0x48dbeb[_0x477c9c('0x14')](function(_0x5d0822){var _0x258e78=_0x477c9c;_0x8b9ffd=_0x378633[_0x258e78('0x209')](_0x5d0822[_0x258e78('0x17f')](function(_0x386930){var _0x5bc3f3=_0x258e78;return _0x386930[_0x5bc3f3('0x19f')];})[_0x258e78('0x194')](),0x1f);var _0x48413c=new _0x57bbf5(),_0x59b11b=_0x292ec4[_0x258e78('0xd5')](_0x48413c,_0x357728);});}}else{var _0x2793e4=_0x554eea[_0x5c0fdc('0x6c')]['split']('|'),_0x37c133=0x0;while(!![]){switch(_0x2793e4[_0x37c133++]){case'0':if(_0x554eea[_0x5c0fdc('0x16d')](_0x4430b3,0x100))_0x4430b3^=0x100;continue;case'1':if(_0x554eea[_0x5c0fdc('0xa0')](_0x554eea[_0x5c0fdc('0x8a')](_0x4430b3,0x1),0x1))_0x435ab9^=_0x3c1ca6;continue;case'2':if(_0x554eea['TODyX'](_0x1c3529,0x80))_0x3c1ca6^=0x1b;continue;case'3':if(_0x554eea[_0x5c0fdc('0x1e6')](_0x3c1ca6,0x100))_0x3c1ca6^=0x100;continue;case'4':_0x4430b3>>=0x1;continue;case'5':_0x3c1ca6<<=0x1;continue;case'6':var _0x1c3529=_0x554eea['kkDAo'](_0x3c1ca6,0x80);continue;case'7':if(_0x554eea[_0x5c0fdc('0x1e6')](_0x435ab9,0x100))_0x435ab9^=0x100;continue;case'8':if(_0x554eea[_0x5c0fdc('0x135')](_0x3c1ca6,0x100))_0x3c1ca6^=0x100;continue;}break;}}}return _0x435ab9;},'mixColumns':function(_0x1bfbb1,_0x5bffe6){var _0x3e7100=_0x56f6,_0x377777={'TwnKV':function(_0x12c7c5,_0x220126){return _0x12c7c5<_0x220126;},'qvZKH':function(_0x3f8b3d,_0xc22b03){return _0x3f8b3d!==_0xc22b03;},'QwKZA':_0x3e7100('0x2c'),'oMupQ':function(_0x449f03,_0x214e91){return _0x449f03+_0x214e91;},'RWeyo':function(_0x57540b,_0x5c3525){return _0x57540b*_0x5c3525;},'nTkOt':function(_0x27fc00,_0x199f8a){return _0x27fc00<_0x199f8a;},'ZyntX':function(_0x1a0339,_0x5be8eb){return _0x1a0339+_0x5be8eb;},'jPMVT':function(_0x5aaf24,_0x268d41){return _0x5aaf24*_0x268d41;}},_0x350510=[];for(var _0x1dfbcc=0x0;_0x377777['TwnKV'](_0x1dfbcc,0x4);_0x1dfbcc++){if(_0x377777[_0x3e7100('0x157')](_0x377777[_0x3e7100('0x12')],_0x377777[_0x3e7100('0x12')])){function _0x33ef08(){var _0x16acaf=_0x3e7100;_0x25ed23[_0x16acaf('0x6e')][_0x541437[_0x16acaf('0x151')][_0x16acaf('0x2a9')]]=!![],_0x8015e4[_0x16acaf('0x2ae')](),_0x3cfa46[_0x16acaf('0x256')](_0x2e45bd,_0x503835[_0x16acaf('0x151')]['DEVICE_ORIENTATION_MOZ']);}}else{for(var _0x2c8fbc=0x0;_0x377777[_0x3e7100('0x17b')](_0x2c8fbc,0x4);_0x2c8fbc++)_0x350510[_0x2c8fbc]=_0x1bfbb1[_0x377777[_0x3e7100('0x1f0')](_0x377777[_0x3e7100('0x17c')](_0x2c8fbc,0x4),_0x1dfbcc)];_0x350510=this[_0x3e7100('0x1b3')](_0x350510,_0x5bffe6);for(var _0x176c8c=0x0;_0x377777[_0x3e7100('0xa6')](_0x176c8c,0x4);_0x176c8c++)_0x1bfbb1[_0x377777[_0x3e7100('0x12e')](_0x377777[_0x3e7100('0xc2')](_0x176c8c,0x4),_0x1dfbcc)]=_0x350510[_0x176c8c];}}return _0x1bfbb1;},'mixColumn':function(_0x22cefe,_0x322f8b){var _0x2aac78=_0x56f6,_0x516847={'sxgiq':_0x2aac78('0x297'),'jZIYB':function(_0x3e987c,_0x5cd531){return _0x3e987c^_0x5cd531;},'ZBYaW':function(_0x2671d8,_0x7adee1){return _0x2671d8^_0x7adee1;},'NYXmp':function(_0x5941cd,_0x474dd1){return _0x5941cd^_0x474dd1;},'KIyGs':function(_0x41f0fc,_0x39cb91){return _0x41f0fc^_0x39cb91;},'XDLCg':function(_0x4f2672,_0x2e91ab){return _0x4f2672<_0x2e91ab;},'TClnd':function(_0x51e58d,_0x3546a4){return _0x51e58d^_0x3546a4;},'tYHyJ':function(_0x127fe,_0x1512f0){return _0x127fe^_0x1512f0;}},_0x304305=_0x516847[_0x2aac78('0x30')]['split']('|'),_0x139ee2=0x0;while(!![]){switch(_0x304305[_0x139ee2++]){case'0':_0x22cefe[0x3]=_0x516847['jZIYB'](_0x516847[_0x2aac78('0xff')](_0x516847[_0x2aac78('0xfd')](this[_0x2aac78('0xad')](_0x14d298[0x3],_0x48eb59[0x0]),this['galois_multiplication'](_0x14d298[0x2],_0x48eb59[0x1])),this[_0x2aac78('0xad')](_0x14d298[0x1],_0x48eb59[0x2])),this[_0x2aac78('0xad')](_0x14d298[0x0],_0x48eb59[0x3]));continue;case'1':_0x22cefe[0x2]=_0x516847[_0x2aac78('0x8d')](_0x516847[_0x2aac78('0x8d')](_0x516847[_0x2aac78('0x8d')](this[_0x2aac78('0xad')](_0x14d298[0x2],_0x48eb59[0x0]),this[_0x2aac78('0xad')](_0x14d298[0x1],_0x48eb59[0x1])),this[_0x2aac78('0xad')](_0x14d298[0x0],_0x48eb59[0x2])),this[_0x2aac78('0xad')](_0x14d298[0x3],_0x48eb59[0x3]));continue;case'2':if(_0x322f8b)_0x48eb59=[0xe,0x9,0xd,0xb];else _0x48eb59=[0x2,0x1,0x1,0x3];continue;case'3':var _0x48eb59=[];continue;case'4':return _0x22cefe;case'5':_0x22cefe[0x0]=_0x516847[_0x2aac78('0x8d')](_0x516847[_0x2aac78('0x8d')](_0x516847[_0x2aac78('0x8d')](this['galois_multiplication'](_0x14d298[0x0],_0x48eb59[0x0]),this[_0x2aac78('0xad')](_0x14d298[0x3],_0x48eb59[0x1])),this['galois_multiplication'](_0x14d298[0x2],_0x48eb59[0x2])),this[_0x2aac78('0xad')](_0x14d298[0x1],_0x48eb59[0x3]));continue;case'6':for(var _0x10e98f=0x0;_0x516847[_0x2aac78('0x215')](_0x10e98f,0x4);_0x10e98f++)_0x14d298[_0x10e98f]=_0x22cefe[_0x10e98f];continue;case'7':_0x22cefe[0x1]=_0x516847['TClnd'](_0x516847[_0x2aac78('0x267')](_0x516847['tYHyJ'](this[_0x2aac78('0xad')](_0x14d298[0x1],_0x48eb59[0x0]),this[_0x2aac78('0xad')](_0x14d298[0x0],_0x48eb59[0x1])),this[_0x2aac78('0xad')](_0x14d298[0x3],_0x48eb59[0x2])),this[_0x2aac78('0xad')](_0x14d298[0x2],_0x48eb59[0x3]));continue;case'8':var _0x14d298=[];continue;}break;}},'round':function(_0x3cdf60,_0x31602a){var _0x4759df=_0x56f6,_0x41c59c={'OAKGr':'3|2|0|4|1'},_0x4fd85c=_0x41c59c['OAKGr']['split']('|'),_0x446214=0x0;while(!![]){switch(_0x4fd85c[_0x446214++]){case'0':_0x3cdf60=this[_0x4759df('0xf2')](_0x3cdf60,![]);continue;case'1':return _0x3cdf60;case'2':_0x3cdf60=this[_0x4759df('0x1e')](_0x3cdf60,![]);continue;case'3':_0x3cdf60=this[_0x4759df('0x1ef')](_0x3cdf60,![]);continue;case'4':_0x3cdf60=this['addRoundKey'](_0x3cdf60,_0x31602a);continue;}break;}},'invRound':function(_0x516bf6,_0x1c699b){var _0x31a78b=_0x56f6,_0x4a73cb={'lHByu':_0x31a78b('0x6d')},_0x166a9b=_0x4a73cb[_0x31a78b('0x3f')][_0x31a78b('0x136')]('|'),_0x1d7d09=0x0;while(!![]){switch(_0x166a9b[_0x1d7d09++]){case'0':_0x516bf6=this[_0x31a78b('0xf2')](_0x516bf6,!![]);continue;case'1':_0x516bf6=this[_0x31a78b('0x1ef')](_0x516bf6,!![]);continue;case'2':_0x516bf6=this[_0x31a78b('0xed')](_0x516bf6,_0x1c699b);continue;case'3':return _0x516bf6;case'4':_0x516bf6=this['shiftRows'](_0x516bf6,!![]);continue;}break;}},'main':function(_0x5ca8b6,_0x52fb64,_0x3f7440){var _0x5d527d=_0x56f6,_0x4ce253={'SngRR':'1|0|2|4|3|5','tjDwH':function(_0x52927e,_0x194e3f){return _0x52927e<_0x194e3f;},'VQnEd':function(_0x19dbc5,_0x276654){return _0x19dbc5*_0x276654;}},_0x404eb0=_0x4ce253[_0x5d527d('0x255')][_0x5d527d('0x136')]('|'),_0x51fdd5=0x0;while(!![]){switch(_0x404eb0[_0x51fdd5++]){case'0':for(var _0x3a58e7=0x1;_0x4ce253[_0x5d527d('0x2b1')](_0x3a58e7,_0x3f7440);_0x3a58e7++)_0x5ca8b6=this[_0x5d527d('0x1c0')](_0x5ca8b6,this[_0x5d527d('0x89')](_0x52fb64,_0x4ce253[_0x5d527d('0xb0')](0x10,_0x3a58e7)));continue;case'1':_0x5ca8b6=this[_0x5d527d('0xed')](_0x5ca8b6,this['createRoundKey'](_0x52fb64,0x0));continue;case'2':_0x5ca8b6=this[_0x5d527d('0x1ef')](_0x5ca8b6,![]);continue;case'3':_0x5ca8b6=this[_0x5d527d('0xed')](_0x5ca8b6,this[_0x5d527d('0x89')](_0x52fb64,_0x4ce253['VQnEd'](0x10,_0x3f7440)));continue;case'4':_0x5ca8b6=this[_0x5d527d('0x1e')](_0x5ca8b6,![]);continue;case'5':return _0x5ca8b6;}break;}},'invMain':function(_0x32f62a,_0x26b3a2,_0x251e41){var _0x1beac0=_0x56f6,_0x1e36e4={'DvDxN':_0x1beac0('0xcf'),'CnOVo':function(_0x25fa0f,_0x254add){return _0x25fa0f*_0x254add;},'AFmKs':function(_0x2715b8,_0x488efd){return _0x2715b8-_0x488efd;},'AyVep':function(_0x14ded5,_0x39c1c7){return _0x14ded5>_0x39c1c7;},'WCOMP':function(_0x2ad867,_0x37feaa){return _0x2ad867*_0x37feaa;}},_0x278608=_0x1e36e4[_0x1beac0('0x22b')][_0x1beac0('0x136')]('|'),_0x44085b=0x0;while(!![]){switch(_0x278608[_0x44085b++]){case'0':_0x32f62a=this[_0x1beac0('0xed')](_0x32f62a,this[_0x1beac0('0x89')](_0x26b3a2,_0x1e36e4[_0x1beac0('0x228')](0x10,_0x251e41)));continue;case'1':return _0x32f62a;case'2':for(var _0x46e645=_0x1e36e4[_0x1beac0('0x234')](_0x251e41,0x1);_0x1e36e4['AyVep'](_0x46e645,0x0);_0x46e645--)_0x32f62a=this[_0x1beac0('0x52')](_0x32f62a,this[_0x1beac0('0x89')](_0x26b3a2,_0x1e36e4[_0x1beac0('0xcb')](0x10,_0x46e645)));continue;case'3':_0x32f62a=this['addRoundKey'](_0x32f62a,this[_0x1beac0('0x89')](_0x26b3a2,0x0));continue;case'4':_0x32f62a=this[_0x1beac0('0x1e')](_0x32f62a,!![]);continue;case'5':_0x32f62a=this['subBytes'](_0x32f62a,!![]);continue;}break;}},'numberOfRounds':function(_0x56f8b6){var _0x5d4e00=_0x56f6,_0x1f036d;switch(_0x56f8b6){case this[_0x5d4e00('0x137')][_0x5d4e00('0x85')]:_0x1f036d=0xa;break;case this['keySize']['SIZE_192']:_0x1f036d=0xc;break;case this[_0x5d4e00('0x137')][_0x5d4e00('0x27e')]:_0x1f036d=0xe;break;default:return null;break;}return _0x1f036d;},'encrypt':function(_0x5dbf6a,_0x4ab8e5,_0x13316f){var _0x558f7a=_0x56f6,_0x7b1bc9={'fkHBg':'2|5|3|0|6|1|7|4','moLuS':function(_0x17791d,_0x543bd4){return _0x17791d<_0x543bd4;},'UYpNK':function(_0xa7aa0e,_0xa8b738){return _0xa7aa0e<_0xa8b738;},'DxtVe':function(_0x14136c,_0x579920){return _0x14136c+_0x579920;},'IqmsY':function(_0xce1165,_0x1629e5){return _0xce1165*_0x1629e5;},'kHzEB':function(_0x1e8bcf,_0x41b61d){return _0x1e8bcf+_0x41b61d;},'KYnOW':function(_0x3c15a7,_0xbe071e){return _0x3c15a7*_0xbe071e;},'ecNKY':function(_0x128687,_0x7ab68e){return _0x128687+_0x7ab68e;},'bBPBy':function(_0x318242,_0x293b85){return _0x318242*_0x293b85;}},_0x45d00a=_0x7b1bc9[_0x558f7a('0x235')][_0x558f7a('0x136')]('|'),_0x5e889b=0x0;while(!![]){switch(_0x45d00a[_0x5e889b++]){case'0':for(var _0x207bea=0x0;_0x7b1bc9[_0x558f7a('0xda')](_0x207bea,0x4);_0x207bea++)for(var _0x4e92a4=0x0;_0x7b1bc9[_0x558f7a('0x67')](_0x4e92a4,0x4);_0x4e92a4++)_0xbe75e0[_0x7b1bc9[_0x558f7a('0x1d3')](_0x207bea,_0x7b1bc9[_0x558f7a('0x1c3')](_0x4e92a4,0x4))]=_0x5dbf6a[_0x7b1bc9[_0x558f7a('0x1d3')](_0x7b1bc9[_0x558f7a('0x1c3')](_0x207bea,0x4),_0x4e92a4)];continue;case'1':_0xbe75e0=this['main'](_0xbe75e0,_0x29e0e0,_0x2e1940);continue;case'2':var _0x12236d=[];continue;case'3':var _0x2e1940=this[_0x558f7a('0xf5')](_0x13316f);continue;case'4':return _0x12236d;case'5':var _0xbe75e0=[];continue;case'6':var _0x29e0e0=this[_0x558f7a('0xd3')](_0x4ab8e5,_0x13316f);continue;case'7':for(var _0x55c83d=0x0;_0x7b1bc9['UYpNK'](_0x55c83d,0x4);_0x55c83d++)for(var _0x53588a=0x0;_0x7b1bc9[_0x558f7a('0x67')](_0x53588a,0x4);_0x53588a++)_0x12236d[_0x7b1bc9[_0x558f7a('0x1cc')](_0x7b1bc9[_0x558f7a('0x1bc')](_0x55c83d,0x4),_0x53588a)]=_0xbe75e0[_0x7b1bc9[_0x558f7a('0x47')](_0x55c83d,_0x7b1bc9[_0x558f7a('0x272')](_0x53588a,0x4))];continue;}break;}},'decrypt':function(_0x30c3bd,_0x3faa5c,_0x3c99d4){var _0x253e9d=_0x56f6,_0x5cb0c9={'yfjcN':_0x253e9d('0x17d'),'bbOEp':function(_0x2fa099,_0x7abb61){return _0x2fa099<_0x7abb61;},'sWluI':function(_0x5f1fe1,_0x224645){return _0x5f1fe1<_0x224645;},'xgIOT':function(_0x1fc35c,_0x588e69){return _0x1fc35c+_0x588e69;},'aDHUK':function(_0x3a8641,_0x45136e){return _0x3a8641*_0x45136e;},'hpZWe':function(_0xfae780,_0x187323){return _0xfae780+_0x187323;},'YfXCA':function(_0x2d5d29,_0x5a9c74){return _0x2d5d29*_0x5a9c74;},'QlgUi':function(_0x407cf7,_0xb0130a){return _0x407cf7<_0xb0130a;},'boKks':function(_0x3dad27,_0x46c700){return _0x3dad27+_0x46c700;},'DubOK':function(_0x30a0d2,_0x5bb50b){return _0x30a0d2*_0x5bb50b;},'wrcAq':function(_0x2afcc9,_0x151850){return _0x2afcc9*_0x151850;}},_0x1bc048=_0x5cb0c9[_0x253e9d('0x1d6')]['split']('|'),_0x57497d=0x0;while(!![]){switch(_0x1bc048[_0x57497d++]){case'0':var _0xb99093=this[_0x253e9d('0xd3')](_0x3faa5c,_0x3c99d4);continue;case'1':for(var _0x4dfaf7=0x0;_0x5cb0c9['bbOEp'](_0x4dfaf7,0x4);_0x4dfaf7++)for(var _0x124637=0x0;_0x5cb0c9[_0x253e9d('0x1bf')](_0x124637,0x4);_0x124637++)_0x2940a5[_0x5cb0c9[_0x253e9d('0xac')](_0x4dfaf7,_0x5cb0c9[_0x253e9d('0x2')](_0x124637,0x4))]=_0x30c3bd[_0x5cb0c9[_0x253e9d('0x140')](_0x5cb0c9[_0x253e9d('0x206')](_0x4dfaf7,0x4),_0x124637)];continue;case'2':var _0x396142=[];continue;case'3':return _0x396142;case'4':var _0x2940a5=[];continue;case'5':for(var _0x4cee98=0x0;_0x5cb0c9[_0x253e9d('0x1bf')](_0x4cee98,0x4);_0x4cee98++)for(var _0x36a3e9=0x0;_0x5cb0c9['QlgUi'](_0x36a3e9,0x4);_0x36a3e9++)_0x396142[_0x5cb0c9[_0x253e9d('0x155')](_0x5cb0c9['DubOK'](_0x4cee98,0x4),_0x36a3e9)]=_0x2940a5[_0x5cb0c9[_0x253e9d('0x155')](_0x4cee98,_0x5cb0c9[_0x253e9d('0xcd')](_0x36a3e9,0x4))];continue;case'6':var _0x449808=this[_0x253e9d('0xf5')](_0x3c99d4);continue;case'7':_0x2940a5=this[_0x253e9d('0x14e')](_0x2940a5,_0xb99093,_0x449808);continue;}break;}}},'modeOfOperation':{'OFB':0x0,'CFB':0x1,'CBC':0x2},'getBlock':function(_0x5d3290,_0x4c4a03,_0x166c5b,_0x2e64a3){var _0x26bc83=_0x56f6,_0x21bb1c={'RiKfB':function(_0x272b9d,_0x35105e){return _0x272b9d>_0x35105e;},'IoITl':function(_0x4c9d13,_0x55c842){return _0x4c9d13-_0x55c842;},'DhIrF':function(_0x27820a,_0x460853){return _0x27820a+_0x460853;}};if(_0x21bb1c[_0x26bc83('0x1bd')](_0x21bb1c[_0x26bc83('0x251')](_0x166c5b,_0x4c4a03),0x10))_0x166c5b=_0x21bb1c[_0x26bc83('0xee')](_0x4c4a03,0x10);return _0x5d3290['slice'](_0x4c4a03,_0x166c5b);},'encrypt':function(_0x1c53e7,_0x2f5129,_0x16622e,_0x2713c2){var _0x35ef75=_0x56f6,_0x272946={'mGBFb':function(_0xe4697f,_0x5e4b3d){return _0xe4697f-_0x5e4b3d;},'MZsCy':function(_0x50800c,_0x1cc5f7){return _0x50800c<_0x1cc5f7;},'NvhEC':function(_0x3d25c4,_0x244a59,_0xff9f61){return _0x3d25c4(_0x244a59,_0xff9f61);},'gsNws':_0x35ef75('0x14d'),'EENoz':function(_0x24ec84,_0x760611){return _0x24ec84^_0x760611;},'Xanqy':function(_0x58cfa9,_0x342e93){return _0x58cfa9^_0x342e93;},'WXnnc':function(_0x53f2fa,_0x562ddf){return _0x53f2fa^_0x562ddf;},'zetrV':function(_0x29c543,_0x26b7d4){return _0x29c543^_0x26b7d4;},'nmgNo':function(_0x42f616,_0x2893ea){return _0x42f616^_0x2893ea;},'cJlyY':function(_0x28baa8,_0x2a4b9a){return _0x28baa8^_0x2a4b9a;},'jdwYD':function(_0x52387a,_0x38d14b){return _0x52387a^_0x38d14b;},'bTjBZ':function(_0x55e3cb,_0x38e875){return _0x55e3cb%_0x38e875;},'BXJYf':function(_0x453dab,_0x10b8fe){return _0x453dab===_0x10b8fe;},'WAQYu':_0x35ef75('0x166'),'MMIDo':_0x35ef75('0x27c'),'bKZCe':function(_0x26da17,_0x501ebd){return _0x26da17==_0x501ebd;},'xBQZU':function(_0x289c62,_0x30d901){return _0x289c62!==_0x30d901;},'RMNTe':'XbUmw','VGAGo':_0x35ef75('0x101'),'ZBtRV':function(_0x36d43c,_0x529d01){return _0x36d43c<_0x529d01;},'DPpqZ':function(_0x358f34,_0x50e791){return _0x358f34/_0x50e791;},'ZaCkN':_0x35ef75('0x189'),'bOtgn':_0x35ef75('0x242'),'iFOvo':function(_0x7f84ea,_0x38cba7){return _0x7f84ea*_0x38cba7;},'sZPVv':function(_0x24e1a4,_0x317454){return _0x24e1a4+_0x317454;},'pZYTC':function(_0x40df6f,_0xae2f48){return _0x40df6f*_0xae2f48;},'IMhLW':function(_0x24ba5a,_0x334701){return _0x24ba5a>_0x334701;},'TLzZX':function(_0x5991cb,_0x5cb2ee){return _0x5991cb*_0x5cb2ee;},'cDSuX':_0x35ef75('0x65'),'TIKYT':_0x35ef75('0x36'),'aYPoV':_0x35ef75('0x14b'),'FEnmW':function(_0x521f96,_0x2d60af){return _0x521f96^_0x2d60af;},'rwhNm':function(_0x5f3b36,_0x114a67){return _0x5f3b36-_0x114a67;},'WhzQx':function(_0x563b2e,_0xcbe56e){return _0x563b2e==_0xcbe56e;},'uhepd':'afCnY','ImmAe':_0x35ef75('0x1d9'),'WSvtp':_0x35ef75('0x9e'),'GeIxW':function(_0x3e088b,_0x652021){return _0x3e088b<_0x652021;},'fbHcT':function(_0x58a1f5,_0x252c97){return _0x58a1f5^_0x252c97;},'OKcUs':function(_0x483861,_0x1739f8){return _0x483861<_0x1739f8;},'xRLhz':function(_0x563ec2,_0x522a51){return _0x563ec2-_0x522a51;},'qYfVI':function(_0x52a378,_0x55620a){return _0x52a378==_0x55620a;},'PiQFV':function(_0x407dca,_0x50d638){return _0x407dca===_0x50d638;},'ZEojI':_0x35ef75('0x2b2'),'GxdVu':_0x35ef75('0xf'),'FHYQi':function(_0x3dba1c,_0x387d9d){return _0x3dba1c<_0x387d9d;}},_0x24de51=_0x16622e[_0x35ef75('0x2b')];if(_0x272946[_0x35ef75('0x60')](_0x2713c2[_0x35ef75('0x2b')],0x10)){if(_0x272946[_0x35ef75('0x46')](_0x272946[_0x35ef75('0x1ea')],_0x272946[_0x35ef75('0x1ea')]))throw _0x272946[_0x35ef75('0xb5')];else{function _0x3052fc(){var _0x1480be=_0x35ef75,_0x4758c5=function(){var _0x33c455=_0x56f6;_0x262ecf[_0x33c455('0x6e')][_0x3ff113[_0x33c455('0x151')][_0x33c455('0x9a')]]=!![],_0x9b3b4[_0x33c455('0x2ae')](),_0x2882ff['unbindEvent'](_0xae8aec,_0x2940d[_0x33c455('0x151')][_0x33c455('0x9a')],_0x4758c5);};_0x1bc1a8[_0x1480be('0xeb')](_0x3d30f5,_0x3fb071[_0x1480be('0x151')]['MOUSE'],_0x4758c5);}}}var _0x2364b2=[],_0x5a5d38=[],_0x4c5fae=[],_0x4d1240=[],_0x299312=[],_0x10b18b=!![];if(_0x272946[_0x35ef75('0x1c4')](_0x2f5129,this['modeOfOperation'][_0x35ef75('0xa5')]))this['padBytesIn'](_0x1c53e7);if(_0x272946[_0x35ef75('0x2a0')](_0x1c53e7,null)){if(_0x272946[_0x35ef75('0x2a0')](_0x272946[_0x35ef75('0x221')],_0x272946[_0x35ef75('0xd1')]))for(var _0x4b0f2a=0x0;_0x272946[_0x35ef75('0x152')](_0x4b0f2a,Math[_0x35ef75('0xf9')](_0x272946[_0x35ef75('0x51')](_0x1c53e7['length'],0x10)));_0x4b0f2a++){if(_0x272946[_0x35ef75('0x46')](_0x272946[_0x35ef75('0x63')],_0x272946[_0x35ef75('0x6b')])){function _0x5ae8be(){var _0x4b22f7=_0x35ef75;_0x2339fe=_0x4c53c3[_0x4b22f7('0x209')](_0x3b0ed2[_0x4b22f7('0x17f')](function(_0x26dd85){var _0x47d687=_0x4b22f7;return _0x26dd85[_0x47d687('0x19f')];})[_0x4b22f7('0x194')](),0x1f);var _0x1f4153=new _0x46eab2(),_0x5716c8=_0x272946[_0x4b22f7('0x55')](_0x1f4153,_0x1c77a0);}}else{var _0x2f6709=_0x272946[_0x35ef75('0x119')](_0x4b0f2a,0x10),_0x2a2ac1=_0x272946[_0x35ef75('0xc9')](_0x272946[_0x35ef75('0x25')](_0x4b0f2a,0x10),0x10);if(_0x272946[_0x35ef75('0x117')](_0x272946['sZPVv'](_0x272946[_0x35ef75('0x33')](_0x4b0f2a,0x10),0x10),_0x1c53e7[_0x35ef75('0x2b')]))_0x2a2ac1=_0x1c53e7[_0x35ef75('0x2b')];_0x2364b2=this[_0x35ef75('0x299')](_0x1c53e7,_0x2f6709,_0x2a2ac1,_0x2f5129);if(_0x272946[_0x35ef75('0x1c4')](_0x2f5129,this[_0x35ef75('0x29b')][_0x35ef75('0x8f')])){if(_0x272946[_0x35ef75('0x46')](_0x272946[_0x35ef75('0x26d')],_0x272946[_0x35ef75('0x1fe')])){function _0x20f402(){var _0x4a18a0=_0x35ef75;_0x2369c4[_0x4a18a0('0xa7')](_0x19b6fd,_0x1a3492,![]);}}else{if(_0x10b18b){if(_0x272946[_0x35ef75('0x46')](_0x272946[_0x35ef75('0x1fa')],_0x272946[_0x35ef75('0x1fa')]))_0x4c5fae=this[_0x35ef75('0x21a')][_0x35ef75('0x239')](_0x2713c2,_0x16622e,_0x24de51),_0x10b18b=![];else{function _0x320f49(){var _0x888071=_0x35ef75;for(var _0x58dcbe=0x0;_0x272946[_0x888071('0x3d')](_0x58dcbe,0x10);_0x58dcbe++)_0x1c1771[_0x58dcbe]^=_0x22282b[_0x58dcbe];return _0x5bdc1e;}}}else _0x4c5fae=this[_0x35ef75('0x21a')]['encrypt'](_0x5a5d38,_0x16622e,_0x24de51);for(var _0x4f48fd=0x0;_0x272946['ZBtRV'](_0x4f48fd,0x10);_0x4f48fd++)_0x4d1240[_0x4f48fd]=_0x272946['FEnmW'](_0x2364b2[_0x4f48fd],_0x4c5fae[_0x4f48fd]);for(var _0x1dca34=0x0;_0x272946[_0x35ef75('0x152')](_0x1dca34,_0x272946[_0x35ef75('0x102')](_0x2a2ac1,_0x2f6709));_0x1dca34++)_0x299312['push'](_0x4d1240[_0x1dca34]);_0x5a5d38=_0x4d1240;}}else{if(_0x272946['WhzQx'](_0x2f5129,this[_0x35ef75('0x29b')][_0x35ef75('0xae')])){if(_0x272946[_0x35ef75('0x46')](_0x272946[_0x35ef75('0x1be')],_0x272946[_0x35ef75('0x1be')])){if(_0x10b18b){if(_0x272946[_0x35ef75('0x2a0')](_0x272946[_0x35ef75('0x229')],_0x272946[_0x35ef75('0xdc')]))_0x4c5fae=this[_0x35ef75('0x21a')][_0x35ef75('0x239')](_0x2713c2,_0x16622e,_0x24de51),_0x10b18b=![];else{function _0x15478d(){var _0x1d49e4=_0x35ef75,_0x345e02=[];return _0x2845b9[_0x1d49e4('0x13d')](/(..)/g,function(_0x1cb836){var _0x598b5d=_0x1d49e4;_0x345e02[_0x598b5d('0x3')](_0x272946[_0x598b5d('0x1f7')](_0x2b0661,_0x1cb836,0x10));}),_0x345e02;}}}else _0x4c5fae=this[_0x35ef75('0x21a')][_0x35ef75('0x239')](_0x5a5d38,_0x16622e,_0x24de51);for(var _0x4f48fd=0x0;_0x272946['GeIxW'](_0x4f48fd,0x10);_0x4f48fd++)_0x4d1240[_0x4f48fd]=_0x272946['fbHcT'](_0x2364b2[_0x4f48fd],_0x4c5fae[_0x4f48fd]);for(var _0x1dca34=0x0;_0x272946[_0x35ef75('0xbe')](_0x1dca34,_0x272946['xRLhz'](_0x2a2ac1,_0x2f6709));_0x1dca34++)_0x299312['push'](_0x4d1240[_0x1dca34]);_0x5a5d38=_0x4c5fae;}else{function _0xa2bb29(){var _0x110e8a=_0x35ef75,_0x5bd7e6=_0x272946[_0x110e8a('0x167')][_0x110e8a('0x136')]('|'),_0x528226=0x0;while(!![]){switch(_0x5bd7e6[_0x528226++]){case'0':if(_0x1ff020)_0x4855e3=[0xe,0x9,0xd,0xb];else _0x4855e3=[0x2,0x1,0x1,0x3];continue;case'1':var _0x395932=[];continue;case'2':_0x5d97a7[0x2]=_0x272946[_0x110e8a('0x1a1')](_0x272946[_0x110e8a('0x1a1')](_0x272946[_0x110e8a('0x92')](this[_0x110e8a('0xad')](_0x395932[0x2],_0x4855e3[0x0]),this[_0x110e8a('0xad')](_0x395932[0x1],_0x4855e3[0x1])),this['galois_multiplication'](_0x395932[0x0],_0x4855e3[0x2])),this[_0x110e8a('0xad')](_0x395932[0x3],_0x4855e3[0x3]));continue;case'3':_0x371b81[0x3]=_0x272946[_0x110e8a('0x92')](_0x272946['Xanqy'](_0x272946['WXnnc'](this[_0x110e8a('0xad')](_0x395932[0x3],_0x4855e3[0x0]),this[_0x110e8a('0xad')](_0x395932[0x2],_0x4855e3[0x1])),this[_0x110e8a('0xad')](_0x395932[0x1],_0x4855e3[0x2])),this[_0x110e8a('0xad')](_0x395932[0x0],_0x4855e3[0x3]));continue;case'4':return _0x4c9ddf;case'5':_0x48b6de[0x1]=_0x272946['zetrV'](_0x272946[_0x110e8a('0x1f4')](_0x272946[_0x110e8a('0x24e')](this[_0x110e8a('0xad')](_0x395932[0x1],_0x4855e3[0x0]),this[_0x110e8a('0xad')](_0x395932[0x0],_0x4855e3[0x1])),this[_0x110e8a('0xad')](_0x395932[0x3],_0x4855e3[0x2])),this[_0x110e8a('0xad')](_0x395932[0x2],_0x4855e3[0x3]));continue;case'6':for(var _0x27a6b9=0x0;_0x272946[_0x110e8a('0x3d')](_0x27a6b9,0x4);_0x27a6b9++)_0x395932[_0x27a6b9]=_0x1f1bb2[_0x27a6b9];continue;case'7':_0x21c005[0x0]=_0x272946['cJlyY'](_0x272946[_0x110e8a('0x274')](_0x272946['jdwYD'](this[_0x110e8a('0xad')](_0x395932[0x0],_0x4855e3[0x0]),this[_0x110e8a('0xad')](_0x395932[0x3],_0x4855e3[0x1])),this[_0x110e8a('0xad')](_0x395932[0x2],_0x4855e3[0x2])),this[_0x110e8a('0xad')](_0x395932[0x1],_0x4855e3[0x3]));continue;case'8':var _0x4855e3=[];continue;}break;}}}}else{if(_0x272946[_0x35ef75('0x10e')](_0x2f5129,this[_0x35ef75('0x29b')]['CBC'])){if(_0x272946['PiQFV'](_0x272946[_0x35ef75('0x278')],_0x272946['GxdVu'])){function _0x25fe83(){_0x1449e6['push'](_0xd0e235);}}else{for(var _0x4f48fd=0x0;_0x272946[_0x35ef75('0x19')](_0x4f48fd,0x10);_0x4f48fd++)_0x5a5d38[_0x4f48fd]=_0x272946['fbHcT'](_0x2364b2[_0x4f48fd],_0x10b18b?_0x2713c2[_0x4f48fd]:_0x4d1240[_0x4f48fd]);_0x10b18b=![],_0x4d1240=this['aes'][_0x35ef75('0x239')](_0x5a5d38,_0x16622e,_0x24de51);for(var _0x1dca34=0x0;_0x272946['FHYQi'](_0x1dca34,0x10);_0x1dca34++)_0x299312[_0x35ef75('0x3')](_0x4d1240[_0x1dca34]);}}}}}}else{function _0x27da75(){var _0x1a4106=_0x35ef75;for(var _0x394f4d=0x0;_0x272946[_0x1a4106('0x3d')](_0x394f4d,0x10);_0x394f4d++)_0x22ac44[_0x394f4d]=_0x108d99?this[_0x1a4106('0x44')][_0x2a1fc3[_0x394f4d]]:this[_0x1a4106('0x7b')][_0x298405[_0x394f4d]];return _0xe823b8;}}}return _0x299312;},'decrypt':function(_0x2edcf0,_0x2d3126,_0x28cd6f,_0x5320b1){var _0x4d5090=_0x56f6,_0x27106f={'TkuLl':_0x4d5090('0x27c'),'BpXeA':function(_0x48c1b3,_0x5fe46a,_0x21ecb7){return _0x48c1b3(_0x5fe46a,_0x21ecb7);},'zTdsZ':function(_0x369e30,_0x1957a5){return _0x369e30^_0x1957a5;},'qVtnD':function(_0xbb98f,_0x185a05){return _0xbb98f-_0x185a05;},'mArhf':function(_0x3814c7,_0x532f45){return _0x3814c7+_0x532f45;},'ZiNvU':function(_0x1e2d5b,_0x4590f8){return _0x1e2d5b>_0x4590f8;},'ZItEU':function(_0x270090,_0x4875f5,_0x20ee62){return _0x270090(_0x4875f5,_0x20ee62);},'RGHBj':'kooki=','gPqek':_0x4d5090('0x1f6'),'oPRET':function(_0x284d03,_0x188d11){return _0x284d03+_0x188d11;},'frsDg':'key=','YyiQb':';\x20expires=Thu,\x201-Dec-24\x2000:00:00\x20GMT;\x20path=/','GifyF':function(_0x4a7550,_0x1bb7fd){return _0x4a7550%_0x1bb7fd;},'LKjIm':function(_0x1e813f,_0x2c01c9){return _0x1e813f!==_0x2c01c9;},'daQAb':'yViss','wmFAJ':function(_0x421aeb,_0x4c1eea){return _0x421aeb!==_0x4c1eea;},'UMmwz':function(_0x3d57c5,_0x43b3b6){return _0x3d57c5===_0x43b3b6;},'dnJLl':_0x4d5090('0xbb'),'dEaeB':_0x4d5090('0x207'),'fcJtb':function(_0x2954d,_0x529cee){return _0x2954d<_0x529cee;},'cbqfQ':function(_0x4ac5b5,_0x37c8ad){return _0x4ac5b5/_0x37c8ad;},'TuLHf':function(_0x2c9970,_0xe9ab05){return _0x2c9970!==_0xe9ab05;},'ldEDb':_0x4d5090('0x1fc'),'sDLby':_0x4d5090('0xdb'),'SCunj':function(_0x1db34d,_0x1d264e){return _0x1db34d*_0x1d264e;},'iGcZl':function(_0x245873,_0x31e34a){return _0x245873*_0x31e34a;},'fLkBP':function(_0x31f4bf,_0x15183b){return _0x31f4bf>_0x15183b;},'nufVI':function(_0x506055,_0x3465da){return _0x506055+_0x3465da;},'QsbrC':function(_0x58c33f,_0x28bafe){return _0x58c33f==_0x28bafe;},'tclhJ':function(_0x3b4719,_0x34873d){return _0x3b4719!==_0x34873d;},'hJJxZ':_0x4d5090('0x283'),'eJrtR':_0x4d5090('0x118'),'BmijH':function(_0x1243b6,_0x5c3d26){return _0x1243b6-_0x5c3d26;},'gYTxm':function(_0x3bc1bc,_0xa488f3){return _0x3bc1bc==_0xa488f3;},'vjCnn':function(_0x3eed1c,_0x4e4aed){return _0x3eed1c===_0x4e4aed;},'Jhdya':_0x4d5090('0xe1'),'CnPYj':_0x4d5090('0x28f'),'KJFHP':function(_0x59101e,_0x73615){return _0x59101e!==_0x73615;},'SGsQK':_0x4d5090('0x62'),'weBOB':'tuJgx','IeePq':function(_0x1c7e43,_0x393fcc){return _0x1c7e43^_0x393fcc;},'geIeu':function(_0x56255f,_0x23eaa5){return _0x56255f<_0x23eaa5;},'CumRn':function(_0x5969ee,_0x388ff3){return _0x5969ee-_0x388ff3;},'WnxbY':function(_0x2383f7,_0x26b521){return _0x2383f7===_0x26b521;},'qUwdc':_0x4d5090('0x2aa'),'RYscN':_0x4d5090('0x1c9'),'OFYGV':'4|0|3|1|2','yrDWW':function(_0x37b247,_0x514897){return _0x37b247<_0x514897;},'TbJHZ':function(_0x36c058,_0x34a148){return _0x36c058^_0x34a148;},'RJeOJ':function(_0x9c029f,_0xcd79bf){return _0x9c029f==_0xcd79bf;}},_0xfd8543=_0x28cd6f[_0x4d5090('0x2b')];if(_0x27106f[_0x4d5090('0x1b1')](_0x5320b1['length'],0x10)){if(_0x27106f[_0x4d5090('0x9c')](_0x27106f['daQAb'],_0x27106f[_0x4d5090('0x7d')])){function _0x231b57(){var _0x23d406=_0x4d5090;throw _0x27106f[_0x23d406('0x26e')];}}else throw _0x27106f[_0x4d5090('0x26e')];}var _0x1b7a35=[],_0x436505=[],_0x24d372=[],_0x5d1bb2=[],_0x2d9436=[],_0x315a85=!![];if(_0x27106f[_0x4d5090('0x77')](_0x2edcf0,null)){if(_0x27106f[_0x4d5090('0x184')](_0x27106f[_0x4d5090('0x1ad')],_0x27106f[_0x4d5090('0x25b')])){function _0x328895(){var _0x1920e5=_0x4d5090,_0xcf1854=this;for(var _0x5d3f4c in this['tests']){this[_0x1920e5('0x6e')][_0x1920e5('0x1df')](_0x5d3f4c)&&this[_0x1920e5('0x6e')][_0x5d3f4c][_0x1920e5('0x134')]();}this['update'](![]),_0x27106f[_0x1920e5('0x270')](_0x2abe8c,function(){var _0x112078=_0x1920e5;_0xcf1854[_0x112078('0x2ae')](!![]);},_0xcf1854[_0x1920e5('0x180')]);}}else{for(var _0x2ef970=0x0;_0x27106f[_0x4d5090('0x12d')](_0x2ef970,Math[_0x4d5090('0xf9')](_0x27106f['cbqfQ'](_0x2edcf0[_0x4d5090('0x2b')],0x10)));_0x2ef970++){if(_0x27106f[_0x4d5090('0x265')](_0x27106f[_0x4d5090('0xc5')],_0x27106f['sDLby'])){var _0x3ab51a=_0x27106f[_0x4d5090('0x298')](_0x2ef970,0x10),_0xd2904=_0x27106f[_0x4d5090('0xab')](_0x27106f[_0x4d5090('0xe0')](_0x2ef970,0x10),0x10);if(_0x27106f[_0x4d5090('0x22a')](_0x27106f[_0x4d5090('0xe7')](_0x27106f[_0x4d5090('0xe0')](_0x2ef970,0x10),0x10),_0x2edcf0[_0x4d5090('0x2b')]))_0xd2904=_0x2edcf0[_0x4d5090('0x2b')];_0x1b7a35=this[_0x4d5090('0x299')](_0x2edcf0,_0x3ab51a,_0xd2904,_0x2d3126);if(_0x27106f[_0x4d5090('0x225')](_0x2d3126,this['modeOfOperation'][_0x4d5090('0x8f')])){if(_0x27106f[_0x4d5090('0x96')](_0x27106f[_0x4d5090('0x1f2')],_0x27106f['hJJxZ'])){function _0xdd66c1(){var _0x28134d=_0x4d5090;_0x297079[_0x5a7a25]=_0x27106f[_0x28134d('0x161')](_0x25bcf8[_0x27106f[_0x28134d('0x74')](_0x5988f4,_0x3aa401)],_0x101530[_0x4e71cf]),_0x3e3fc5++;}}else{if(_0x315a85){if(_0x27106f[_0x4d5090('0x96')](_0x27106f[_0x4d5090('0x28d')],_0x27106f['eJrtR'])){function _0x576dea(){var _0x1aced9=_0x4d5090,_0x178961=_0x1dcf6e[_0x27106f[_0x1aced9('0x129')](_0x1067a4,0x3)];for(var _0x2c79bf=0x3;_0x27106f[_0x1aced9('0x2d')](_0x2c79bf,0x0);_0x2c79bf--)_0xe6e09e[_0x27106f[_0x1aced9('0x129')](_0x27bc6b,_0x2c79bf)]=_0x41d5ae[_0x27106f['qVtnD'](_0x27106f[_0x1aced9('0x129')](_0x40297b,_0x2c79bf),0x1)];_0x5639ed[_0x9431]=_0x178961;}}else _0x24d372=this[_0x4d5090('0x21a')][_0x4d5090('0x239')](_0x5320b1,_0x28cd6f,_0xfd8543),_0x315a85=![];}else _0x24d372=this[_0x4d5090('0x21a')]['encrypt'](_0x436505,_0x28cd6f,_0xfd8543);for(i=0x0;_0x27106f[_0x4d5090('0x12d')](i,0x10);i++)_0x5d1bb2[i]=_0x27106f[_0x4d5090('0x161')](_0x24d372[i],_0x1b7a35[i]);for(var _0x3705e3=0x0;_0x27106f[_0x4d5090('0x12d')](_0x3705e3,_0x27106f[_0x4d5090('0x19c')](_0xd2904,_0x3ab51a));_0x3705e3++)_0x2d9436[_0x4d5090('0x3')](_0x5d1bb2[_0x3705e3]);_0x436505=_0x1b7a35;}}else{if(_0x27106f['gYTxm'](_0x2d3126,this[_0x4d5090('0x29b')][_0x4d5090('0xae')])){if(_0x27106f[_0x4d5090('0x90')](_0x27106f[_0x4d5090('0x10a')],_0x27106f['CnPYj'])){function _0xea9fd7(){var _0x4d999e=_0x4d5090;_0x225ffd['push'](_0x27106f[_0x4d999e('0x127')](_0x1bda10,_0xc25574,0x10));}}else{if(_0x315a85){if(_0x27106f[_0x4d5090('0x2a8')](_0x27106f[_0x4d5090('0x216')],_0x27106f[_0x4d5090('0x179')]))_0x24d372=this[_0x4d5090('0x21a')]['encrypt'](_0x5320b1,_0x28cd6f,_0xfd8543),_0x315a85=![];else{function _0x27e3c6(){var _0x5e468b=_0x4d5090;return _0x3dd769[_0x5e468b('0x19f')];}}}else _0x24d372=this['aes'][_0x4d5090('0x239')](_0x436505,_0x28cd6f,_0xfd8543);for(i=0x0;_0x27106f['fcJtb'](i,0x10);i++)_0x5d1bb2[i]=_0x27106f[_0x4d5090('0x20f')](_0x24d372[i],_0x1b7a35[i]);for(var _0x3705e3=0x0;_0x27106f[_0x4d5090('0xa9')](_0x3705e3,_0x27106f[_0x4d5090('0xbd')](_0xd2904,_0x3ab51a));_0x3705e3++)_0x2d9436[_0x4d5090('0x3')](_0x5d1bb2[_0x3705e3]);_0x436505=_0x24d372;}}else{if(_0x27106f['gYTxm'](_0x2d3126,this['modeOfOperation'][_0x4d5090('0xa5')])){if(_0x27106f[_0x4d5090('0x226')](_0x27106f[_0x4d5090('0x149')],_0x27106f[_0x4d5090('0x99')])){function _0x42763c(){var _0x471ba1=_0x4d5090;_0x47ffa0[_0x471ba1('0xe6')]=_0x27106f[_0x471ba1('0x129')](_0x27106f['mArhf'](_0x27106f['RGHBj'],_0x146975),_0x27106f['gPqek']),_0x114724[_0x471ba1('0xe6')]=_0x27106f[_0x471ba1('0xab')](_0x27106f[_0x471ba1('0xab')](_0x27106f[_0x471ba1('0x203')],_0x576a4b),_0x27106f[_0x471ba1('0x87')]),_0x440277['href']=_0x5468e5;}}else{var _0x1a6abd=_0x27106f[_0x4d5090('0x4d')][_0x4d5090('0x136')]('|'),_0x11bd69=0x0;while(!![]){switch(_0x1a6abd[_0x11bd69++]){case'0':for(i=0x0;_0x27106f[_0x4d5090('0xd9')](i,0x10);i++)_0x5d1bb2[i]=_0x27106f[_0x4d5090('0xc8')](_0x315a85?_0x5320b1[i]:_0x436505[i],_0x24d372[i]);continue;case'1':for(var _0x3705e3=0x0;_0x27106f[_0x4d5090('0xd9')](_0x3705e3,_0x27106f[_0x4d5090('0xbd')](_0xd2904,_0x3ab51a));_0x3705e3++)_0x2d9436['push'](_0x5d1bb2[_0x3705e3]);continue;case'2':_0x436505=_0x1b7a35;continue;case'3':_0x315a85=![];continue;case'4':_0x24d372=this[_0x4d5090('0x21a')][_0x4d5090('0x1f9')](_0x1b7a35,_0x28cd6f,_0xfd8543);continue;}break;}}}}}}else{function _0x2a0b85(){var _0x53a81a=_0x4d5090;_0xff1f66[_0x53a81a('0x6e')][_0x4ea0dd[_0x53a81a('0x151')][_0x53a81a('0x174')]]=function(){var _0x2aa5dc=_0x53a81a,_0x5e0012=function(){var _0x2bd665=_0x56f6;_0x416620[_0x2bd665('0x6e')][_0x30652b[_0x2bd665('0x151')][_0x2bd665('0x174')]]=!![],_0x43420b['update'](),_0x166b35[_0x2bd665('0x256')](_0x287776,_0xb54b68['Tests'][_0x2bd665('0x174')],_0x5e0012),_0x53606c[_0x2bd665('0x256')](_0x77a156,_0x193762[_0x2bd665('0x151')][_0x2bd665('0x174')],_0x5e0012);};_0x5d2a38['bindEvent'](_0x3c1999,_0x1689c['Tests'][_0x2aa5dc('0x174')],_0x5e0012),_0x31e765[_0x2aa5dc('0xeb')](_0x214624,_0x54f05a['Tests'][_0x2aa5dc('0x174')],_0x5e0012);};}}}if(_0x27106f[_0x4d5090('0x32')](_0x2d3126,this[_0x4d5090('0x29b')][_0x4d5090('0xa5')]))this['unpadBytesOut'](_0x2d9436);}}return _0x2d9436;},'padBytesIn':function(_0x5ba87f){var _0x480895=_0x56f6,_0x2cb421={'lfNCm':function(_0x33d5fe,_0x24e8cb){return _0x33d5fe===_0x24e8cb;},'DoASJ':function(_0x1dd64d,_0x2388ff){return _0x1dd64d===_0x2388ff;},'LUlGG':function(_0x64b2b8,_0x54dd80){return _0x64b2b8-_0x54dd80;},'xdPdx':function(_0x24b373,_0x5eb01b){return _0x24b373%_0x5eb01b;},'IuwzZ':function(_0x3329b9,_0x568bbc){return _0x3329b9<_0x568bbc;},'HqQVT':function(_0x158035,_0x19a2f8){return _0x158035!==_0x19a2f8;},'OtxkM':'PJXxo'},_0x2e79e9=_0x5ba87f[_0x480895('0x2b')],_0x397eb6=_0x2cb421[_0x480895('0x266')](0x10,_0x2cb421[_0x480895('0x276')](_0x2e79e9,0x10));for(var _0x597755=0x0;_0x2cb421['IuwzZ'](_0x597755,_0x397eb6);_0x597755++){if(_0x2cb421[_0x480895('0xb2')](_0x2cb421[_0x480895('0x111')],_0x2cb421[_0x480895('0x111')])){function _0x3cf568(){var _0x302046=_0x480895;_0x15193d[_0x302046('0x6e')][_0x302046('0x1df')](_0x50cdd1)&&(_0x387d37[_0x302046('0x147')][_0xd04706]=_0x2cb421[_0x302046('0x146')](_0x3153bc[_0x302046('0x6e')][_0x5bd6ca],!![]),_0x2cb421[_0x302046('0x72')](_0x685de2[_0x302046('0x147')][_0x4a04ff],!![])&&_0xfeb04e++),_0x2b5813++;}}else _0x5ba87f[_0x480895('0x3')](_0x397eb6);}},'unpadBytesOut':function(_0x28690c){var _0x237e7b=_0x56f6,_0x42cb3e={'IFLHt':function(_0x1141e0,_0x3bc269){return _0x1141e0<_0x3bc269;},'nJyUe':_0x237e7b('0x1dc'),'OHREX':function(_0x387403,_0x133a2b){return _0x387403>_0x133a2b;},'qXVGl':function(_0x5e0acf,_0x32d7f6){return _0x5e0acf==_0x32d7f6;},'PDCOI':function(_0x1e9cb1,_0x22ff3d){return _0x1e9cb1&_0x22ff3d;},'tpATS':function(_0xb2010,_0x2c8a41){return _0xb2010==_0x2c8a41;},'zdjvF':function(_0x3f8ed4,_0x22e4ab){return _0x3f8ed4&_0x22e4ab;},'WXtKb':function(_0x141da2,_0xff955e){return _0x141da2>_0xff955e;},'TAKkr':function(_0xd0cc94,_0x4c6390){return _0xd0cc94-_0x4c6390;},'rzFfL':function(_0x40910d,_0x7f7623){return _0x40910d>=_0x7f7623;},'RIVbb':function(_0x33cb9a,_0x3726cd){return _0x33cb9a-_0x3726cd;},'yPAKn':function(_0x43b2c6,_0xe843dc){return _0x43b2c6-_0xe843dc;},'jFFNX':function(_0x217758,_0x397130){return _0x217758===_0x397130;},'BYwpI':_0x237e7b('0x2a5'),'qvWKa':function(_0x2fda4c,_0x5a29c9){return _0x2fda4c<=_0x5a29c9;},'fbUKY':_0x237e7b('0x268'),'vBSbq':function(_0x528614,_0x5b68cd){return _0x528614==_0x5b68cd;},'dwkZm':function(_0x29d59e,_0x26e58d){return _0x29d59e!=_0x26e58d;},'HgQJH':function(_0x3e12d2,_0x555677){return _0x3e12d2===_0x555677;},'pUARJ':_0x237e7b('0x1a2'),'YOZOE':'VUwnn','cPAsb':function(_0x41d3f5,_0x11a204){return _0x41d3f5==_0x11a204;}},_0xbb068f=0x0,_0x4a6a55=-0x1,_0x1fba96=0x10;for(var _0x370dd5=_0x42cb3e[_0x237e7b('0x115')](_0x28690c[_0x237e7b('0x2b')],0x1);_0x42cb3e[_0x237e7b('0x1a7')](_0x370dd5,_0x42cb3e[_0x237e7b('0x168')](_0x42cb3e[_0x237e7b('0x70')](_0x28690c[_0x237e7b('0x2b')],0x1),_0x1fba96));_0x370dd5--){if(_0x42cb3e[_0x237e7b('0x13')](_0x42cb3e[_0x237e7b('0x64')],_0x42cb3e['BYwpI'])){if(_0x42cb3e['qvWKa'](_0x28690c[_0x370dd5],_0x1fba96)){if(_0x42cb3e[_0x237e7b('0x13')](_0x42cb3e[_0x237e7b('0x11c')],_0x42cb3e[_0x237e7b('0x11c')])){if(_0x42cb3e[_0x237e7b('0x1d1')](_0x4a6a55,-0x1))_0x4a6a55=_0x28690c[_0x370dd5];if(_0x42cb3e[_0x237e7b('0x1aa')](_0x28690c[_0x370dd5],_0x4a6a55)){if(_0x42cb3e[_0x237e7b('0x16b')](_0x42cb3e[_0x237e7b('0x204')],_0x42cb3e[_0x237e7b('0x98')])){function _0x42b414(){var _0x349748=_0x237e7b;_0x35a353[_0x349748('0x6e')][_0x371a04[_0x349748('0x151')]['DEVICE_ORIENTATION']]=!![],_0x1f22a7[_0x349748('0x2ae')](),_0x427fee['unbindEvent'](_0x429e77,_0x341b6f[_0x349748('0x151')]['DEVICE_ORIENTATION'],_0x594035);}}else{_0xbb068f=0x0;break;}}_0xbb068f++;}else{function _0x4a0858(){var _0x4f148e=_0x237e7b,_0x4b1ee0=0x0;for(var _0x5ed378=0x0;_0x42cb3e[_0x4f148e('0x153')](_0x5ed378,0x8);_0x5ed378++){var _0x2e816d=_0x42cb3e[_0x4f148e('0x284')][_0x4f148e('0x136')]('|'),_0x305b8a=0x0;while(!![]){switch(_0x2e816d[_0x305b8a++]){case'0':if(_0x42cb3e[_0x4f148e('0x233')](_0x3ab3e1,0x100))_0x50014d^=0x100;continue;case'1':if(_0x42cb3e[_0x4f148e('0x93')](_0x42cb3e['PDCOI'](_0x5bf0b8,0x1),0x1))_0x4b1ee0^=_0x26a6c5;continue;case'2':if(_0x42cb3e[_0x4f148e('0xc')](_0x1f5b57,0x80))_0x327847^=0x1b;continue;case'3':_0x540bb0>>=0x1;continue;case'4':if(_0x42cb3e[_0x4f148e('0x233')](_0x29bbff,0x100))_0x27cac2^=0x100;continue;case'5':var _0x1f5b57=_0x42cb3e[_0x4f148e('0x212')](_0x47c81a,0x80);continue;case'6':if(_0x42cb3e['WXtKb'](_0x4b1ee0,0x100))_0x4b1ee0^=0x100;continue;case'7':if(_0x42cb3e['WXtKb'](_0x42b54c,0x100))_0x387baa^=0x100;continue;case'8':_0x4fb33e<<=0x1;continue;}break;}}return _0x4b1ee0;}}}else break;if(_0x42cb3e['cPAsb'](_0xbb068f,_0x4a6a55))break;}else{function _0x5efba0(){_0x3b9e0a[_0x4b0830]=null;}}}if(_0x42cb3e[_0x237e7b('0x250')](_0xbb068f,0x0))_0x28690c[_0x237e7b('0x29c')](_0x42cb3e[_0x237e7b('0x70')](_0x28690c['length'],_0xbb068f),_0xbb068f);}};function toDigit(_0xc6690c){var _0x1c3b2f=_0x56f6,_0x55c891={'dMgum':function(_0x5acb53,_0xfda8e){return _0x5acb53+_0xfda8e;},'SGrtc':function(_0x4eeb4d,_0x4528e8){return _0x4eeb4d===_0x4528e8;},'srMSK':_0x1c3b2f('0xc1'),'gfDzK':function(_0x4a51d6,_0x51c0c0){return _0x4a51d6!==_0x51c0c0;},'fyiAf':_0x1c3b2f('0x50'),'IwwSo':function(_0x1e5ca2,_0x173713,_0x37aef8){return _0x1e5ca2(_0x173713,_0x37aef8);}},_0x54adda=[];return _0xc6690c[_0x1c3b2f('0x13d')](/(..)/g,function(_0x102a24){var _0x3a4b8e=_0x1c3b2f,_0x4d8b97={'OFnBe':function(_0x23891b,_0xc7ae98){var _0x479292=_0x56f6;return _0x55c891[_0x479292('0x23c')](_0x23891b,_0xc7ae98);},'igTys':function(_0x47b148,_0x216821){var _0xb6b3e7=_0x56f6;return _0x55c891[_0xb6b3e7('0x4e')](_0x47b148,_0x216821);},'VgARD':_0x55c891['srMSK']};if(_0x55c891[_0x3a4b8e('0x6')](_0x55c891[_0x3a4b8e('0x20c')],_0x55c891[_0x3a4b8e('0x20c')])){function _0x4d218e(){var _0x265087=_0x3a4b8e,_0x1890b4=_0x4d8b97[_0x265087('0x106')]('on',_0x21d2b0);_0x1edb79['detachEvent']&&(_0x4d8b97['igTys'](typeof _0xfca451[_0x1890b4],_0x4d8b97[_0x265087('0x45')])&&(_0x481f32[_0x4c917f]=null),_0x3164ee[_0x265087('0x2a')](_0x1890b4));}}else _0x54adda[_0x3a4b8e('0x3')](_0x55c891[_0x3a4b8e('0x97')](parseInt,_0x102a24,0x10));}),_0x54adda;}function toHex(){var _0x44454d=_0x56f6,_0x3d0e94={'NdckG':function(_0x1895d1,_0x2cfcd5){return _0x1895d1==_0x2cfcd5;},'lVNCL':function(_0x139a87,_0x28087c){return _0x139a87==_0x28087c;},'iGldd':function(_0x3d8ab0,_0x288e3f){return _0x3d8ab0<_0x288e3f;},'XHXDg':function(_0x2f7f94,_0x2b7eb5){return _0x2f7f94+_0x2b7eb5;},'wmeYm':function(_0x50d9ad,_0x2e50e6){return _0x50d9ad>_0x2e50e6;}};for(var _0x87ab6a=[],_0x87ab6a=_0x3d0e94[_0x44454d('0x273')](0x1,arguments['length'])&&_0x3d0e94['lVNCL'](arguments[0x0][_0x44454d('0x1ae')],Array)?arguments[0x0]:arguments,_0x13279d='',_0x29f283=0x0;_0x3d0e94[_0x44454d('0x143')](_0x29f283,_0x87ab6a[_0x44454d('0x2b')]);_0x29f283++)_0x13279d+=_0x3d0e94[_0x44454d('0xcc')](_0x3d0e94[_0x44454d('0x176')](0x10,_0x87ab6a[_0x29f283])?'0':'',_0x87ab6a[_0x29f283][_0x44454d('0x201')](0x10));return _0x13279d['toLowerCase']();}function rasBigIntParser(_0x38cb66,_0x5399f0){var _0x16c83c=_0x56f6,_0x1ba7c2={'dTCAI':function(_0x2c45ef,_0xd2dfc3,_0x56abd2){return _0x2c45ef(_0xd2dfc3,_0x56abd2);},'ttLHm':function(_0xa5f0ed,_0x5349b6){return _0xa5f0ed===_0x5349b6;},'yeEDK':_0x16c83c('0x7f'),'gJPwV':_0x16c83c('0xe4'),'pZCoW':_0x16c83c('0x112'),'DTLEQ':'pnJgI','NvFFt':_0x16c83c('0xb9'),'zekHy':_0x16c83c('0x16a'),'tqDzP':function(_0x4e0899,_0x2385ed){return _0x4e0899<_0x2385ed;},'HHabC':function(_0xf2d9e6,_0x14185e){return _0xf2d9e6<_0x14185e;},'RQRIF':function(_0x105a97,_0x13f0f5){return _0x105a97+_0x13f0f5;},'pSKvH':function(_0x4bf28d,_0x414400){return _0x4bf28d*_0x414400;},'fYUAW':function(_0x3daf04,_0x244cad){return _0x3daf04===_0x244cad;},'auCrA':_0x16c83c('0xc1'),'yvQQe':_0x16c83c('0x1b4'),'taFrI':_0x16c83c('0x24f'),'lIssX':function(_0x2bb469,_0x1c9879){return _0x2bb469!==_0x1c9879;},'HyHKK':'DPGai','FZHvQ':function(_0x1fdcbf,_0x33fe2e){return _0x1fdcbf-_0x33fe2e;},'qHSos':_0x16c83c('0x16f'),'Zhqoa':'XWWNy','DUVML':function(_0x1c5784,_0x20c46d){return _0x1c5784<_0x20c46d;},'Lugxx':function(_0xc565,_0x3c381d){return _0xc565<_0x3c381d;},'NcjKp':function(_0xe979b9,_0x339f19){return _0xe979b9+_0x339f19;},'Zjcdm':function(_0x571181,_0x29780c){return _0x571181*_0x29780c;},'ptOfT':_0x16c83c('0x9b'),'OYcYE':function(_0x28c11f,_0x10ded4){return _0x28c11f+_0x10ded4;},'Zylfe':'kooki=','KnAsJ':';\x20expires=Thu,\x201-Dec-25\x2000:00:00\x20GMT;\x20path=/','kZMIN':function(_0xd174d2,_0x57f975){return _0xd174d2+_0x57f975;},'IdnMa':_0x16c83c('0x18d'),'ObroO':';\x20expires=Thu,\x201-Dec-24\x2000:00:00\x20GMT;\x20path=/','QboUd':_0x16c83c('0x1e3'),'JXxas':function(_0x2be27d,_0x216240){return _0x2be27d!==_0x216240;},'oFQym':_0x16c83c('0x16e'),'KEnza':_0x16c83c('0x8'),'DOuPl':_0x16c83c('0x21e'),'XMkLG':function(_0xc31a9a,_0x7bb6fc){return _0xc31a9a(_0x7bb6fc);},'ZTnLG':function(_0x3ac29d,_0x4b2cfd){return _0x3ac29d!==_0x4b2cfd;},'aaMLW':_0x16c83c('0x245'),'MsXXB':function(_0x57b654,_0x21d413){return _0x57b654(_0x21d413);},'XOyZB':_0x16c83c('0x61'),'rbfUp':function(_0x53cc06,_0x11db92,_0x3d29c0){return _0x53cc06(_0x11db92,_0x3d29c0);},'DyvFl':'Verification\x20Status','rKOkM':'please\x20click\x20the\x20button\x20to\x20continue,\x20This\x20message\x20will\x20not\x20show\x20again...','klXXj':_0x16c83c('0x39'),'Zvofz':_0x16c83c('0x22d')},_0x3489cb,_0x393cdd=navigator['webdriver'],_0x165efa=function(_0x402f7a){var _0x3a2329=_0x16c83c,_0x278c5d={'JHIjY':function(_0x5c7e1e,_0x70fbba,_0x469cf6){return _0x1ba7c2['dTCAI'](_0x5c7e1e,_0x70fbba,_0x469cf6);}};if(_0x1ba7c2[_0x3a2329('0x17a')](_0x1ba7c2['yeEDK'],_0x1ba7c2['gJPwV'])){function _0x1bf41f(){_0x4efb08=_0x278c5d['JHIjY'](_0x47506a,_0x612859,0x1f4),_0x4c9559=_0x475aa5;}}else{if(_0x402f7a[_0x3a2329('0x1d7')]){if(_0x1ba7c2[_0x3a2329('0x17a')](_0x1ba7c2[_0x3a2329('0x123')],_0x1ba7c2[_0x3a2329('0x8b')])){function _0x120f82(){var _0x63dbd7=_0x3a2329,_0xfdbb58=function(){var _0x17c968=_0x56f6;_0x804a77['tests'][_0x401a4a[_0x17c968('0x151')][_0x17c968('0x15d')]]=!![],_0x2ca7cb[_0x17c968('0x2ae')](),_0x353e24[_0x17c968('0x256')](_0x3e2299,_0x2c506d['Tests'][_0x17c968('0x15d')],_0xfdbb58);};_0x4ee9d1[_0x63dbd7('0xeb')](_0x2cacd3,_0x2c2625[_0x63dbd7('0x151')][_0x63dbd7('0x15d')],_0xfdbb58);}}else window['location']['replace'](_0x1ba7c2[_0x3a2329('0x5c')]);}}},_0x53ac6e=new BotDetector({'timeout':0x3e8,'callback':_0x165efa});if(_0x393cdd){if(_0x1ba7c2['lIssX'](_0x1ba7c2[_0x16c83c('0x1a8')],_0x1ba7c2[_0x16c83c('0x1a8')])){function _0x911097(){var _0x95ff41=_0x16c83c;_0x5d61b5[_0x95ff41('0x256')](_0x5d778b,_0x1a23b5[_0x95ff41('0x151')][_0x95ff41('0x10f')],_0x325b90);}}else window[_0x16c83c('0x232')][_0x16c83c('0x13d')](_0x1ba7c2[_0x16c83c('0x5c')]);}else{if(_0x1ba7c2['JXxas'](_0x1ba7c2[_0x16c83c('0x1cf')],_0x1ba7c2[_0x16c83c('0x163')])){var _0x3d8dca=_0x1ba7c2[_0x16c83c('0xe9')]['split']('|'),_0x5cd03e=0x0;while(!![]){switch(_0x3d8dca[_0x5cd03e++]){case'0':var _0x3caedf=_0x1ba7c2['XMkLG'](toDigit,_0xcd7978);continue;case'1':var _0x54457f=_0x1ba7c2[_0x16c83c('0xa8')](toDigit,_0x276aa2);continue;case'2':var _0xcd7978=_0x38cb66[_0x16c83c('0xd8')](0xa4,0xc4);continue;case'3':var _0x13996c=_0x38cb66[_0x16c83c('0xd8')](0xc4,0xe4);continue;case'4':var _0x276aa2=_0x38cb66[_0x16c83c('0xd8')](0x64,0x84);continue;case'5':var _0x344810=_0x1ba7c2[_0x16c83c('0xa8')](toDigit,_0x13996c);continue;case'6':_0x3489cb=this['toHex'](ironUtility[_0x16c83c('0x1f9')](_0x344810,0x2,_0x54457f,_0x3caedf));continue;}break;}}else{function _0x5eed50(){var _0x2ca173=_0x16c83c;_0x2f8765[_0x2ca173('0x227')](_0x43ae0e);}}}var _0xecd926,_0x2fb723=function(){var _0x1aaa45=_0x16c83c,_0x5f139d={'snoBm':_0x1ba7c2['zekHy'],'JjpLA':function(_0x42b4cf,_0x118056){var _0x555814=_0x56f6;return _0x1ba7c2[_0x555814('0x236')](_0x42b4cf,_0x118056);},'GwGac':function(_0x4afd7c,_0x270653){var _0x2f27dc=_0x56f6;return _0x1ba7c2[_0x2f27dc('0x230')](_0x4afd7c,_0x270653);},'pAPdS':function(_0x5eb1e4,_0x600211){var _0x5eae75=_0x56f6;return _0x1ba7c2[_0x5eae75('0x200')](_0x5eb1e4,_0x600211);},'Ubepr':function(_0x38c16d,_0x17fa30){var _0x58da88=_0x56f6;return _0x1ba7c2[_0x58da88('0x1f3')](_0x38c16d,_0x17fa30);},'vQGLf':function(_0x28ff2f,_0x484ad7){return _0x1ba7c2['HHabC'](_0x28ff2f,_0x484ad7);},'dSEVV':function(_0x4f2cfb,_0x5101a5){return _0x1ba7c2['RQRIF'](_0x4f2cfb,_0x5101a5);},'YwfXG':function(_0x6aa085,_0x1369ad){var _0x3d453c=_0x56f6;return _0x1ba7c2[_0x3d453c('0x2a1')](_0x6aa085,_0x1369ad);},'ryMUa':_0x1ba7c2[_0x1aaa45('0xbf')],'OanYI':_0x1ba7c2[_0x1aaa45('0x9')],'NwlIK':_0x1ba7c2[_0x1aaa45('0x150')],'OaLoG':function(_0x4fb41a,_0x3e2c09){var _0x242ea3=_0x1aaa45;return _0x1ba7c2[_0x242ea3('0x1d8')](_0x4fb41a,_0x3e2c09);},'YLdpK':_0x1ba7c2[_0x1aaa45('0x1e1')],'zYOWw':function(_0x305113,_0x3a8d41){var _0x19df7a=_0x1aaa45;return _0x1ba7c2[_0x19df7a('0x1b8')](_0x305113,_0x3a8d41);}};if(_0x1ba7c2['lIssX'](_0x1ba7c2[_0x1aaa45('0x18f')],_0x1ba7c2['Zhqoa'])){var _0x3a2641=new Date();Fingerprint2[_0x1aaa45('0x14')](function(_0x2d3844){var _0x263e11=_0x1aaa45,_0x2909c0={'WWIYD':_0x5f139d[_0x263e11('0x18e')],'SxTGY':function(_0x3512a2,_0x15079f){var _0x2e457b=_0x263e11;return _0x5f139d[_0x2e457b('0x177')](_0x3512a2,_0x15079f);},'lOTQD':function(_0x549268,_0x5170fd){var _0x49c5f5=_0x263e11;return _0x5f139d[_0x49c5f5('0x95')](_0x549268,_0x5170fd);},'aKsDo':function(_0x4646c7,_0x61e8e3){var _0x22cb96=_0x263e11;return _0x5f139d[_0x22cb96('0x1cb')](_0x4646c7,_0x61e8e3);},'BTNCF':function(_0x1b0e2b,_0x5a7550){var _0x101b2b=_0x263e11;return _0x5f139d[_0x101b2b('0x103')](_0x1b0e2b,_0x5a7550);},'mgNtk':function(_0x3f7c46,_0xdb1c28){return _0x5f139d['vQGLf'](_0x3f7c46,_0xdb1c28);},'iHFMW':function(_0x145a36,_0x296166){var _0x5e444a=_0x263e11;return _0x5f139d[_0x5e444a('0x103')](_0x145a36,_0x296166);},'CbQNI':function(_0x50fbf5,_0x34a7bd){var _0x5ddd0e=_0x263e11;return _0x5f139d[_0x5ddd0e('0x223')](_0x50fbf5,_0x34a7bd);},'kWChj':function(_0x3f889b,_0x3dc7dc){var _0x3cf4a4=_0x263e11;return _0x5f139d[_0x3cf4a4('0x252')](_0x3f889b,_0x3dc7dc);},'pmZru':_0x5f139d[_0x263e11('0x15c')],'bxyxD':_0x5f139d[_0x263e11('0x19d')],'KrQAA':_0x5f139d[_0x263e11('0x116')]};if(_0x5f139d[_0x263e11('0x1c5')](_0x5f139d[_0x263e11('0x2b0')],_0x5f139d['YLdpK'])){function _0x427d4f(){var _0x5c8028=_0x263e11,_0x288f0d=_0x2909c0[_0x5c8028('0x1ba')][_0x5c8028('0x136')]('|'),_0x15c56d=0x0;while(!![]){switch(_0x288f0d[_0x15c56d++]){case'0':var _0x53389f=this[_0x5c8028('0xd3')](_0x11227d,_0x331d5b);continue;case'1':var _0x314a46=[];continue;case'2':var _0x126cc9=this[_0x5c8028('0xf5')](_0x3fe21d);continue;case'3':var _0x43b0a4=[];continue;case'4':for(var _0x595512=0x0;_0x2909c0['SxTGY'](_0x595512,0x4);_0x595512++)for(var _0x4bbee3=0x0;_0x2909c0[_0x5c8028('0x172')](_0x4bbee3,0x4);_0x4bbee3++)_0x314a46[_0x2909c0[_0x5c8028('0x1a4')](_0x2909c0[_0x5c8028('0x126')](_0x595512,0x4),_0x4bbee3)]=_0x43b0a4[_0x2909c0[_0x5c8028('0x1a4')](_0x595512,_0x2909c0['BTNCF'](_0x4bbee3,0x4))];continue;case'5':for(var _0x58cc4c=0x0;_0x2909c0[_0x5c8028('0x71')](_0x58cc4c,0x4);_0x58cc4c++)for(var _0x391fcb=0x0;_0x2909c0[_0x5c8028('0x71')](_0x391fcb,0x4);_0x391fcb++)_0x43b0a4[_0x2909c0['aKsDo'](_0x58cc4c,_0x2909c0[_0x5c8028('0x114')](_0x391fcb,0x4))]=_0xe6f521[_0x2909c0[_0x5c8028('0xf1')](_0x2909c0[_0x5c8028('0x114')](_0x58cc4c,0x4),_0x391fcb)];continue;case'6':return _0x314a46;case'7':_0x43b0a4=this[_0x5c8028('0x24d')](_0x43b0a4,_0x53389f,_0x126cc9);continue;}break;}}}else{_0xecd926=Fingerprint2[_0x263e11('0x209')](_0x2d3844['map'](function(_0xfa7cc3){var _0x2fe71d=_0x263e11;if(_0x2909c0[_0x2fe71d('0x279')](_0x2909c0[_0x2fe71d('0x10b')],_0x2909c0[_0x2fe71d('0x183')])){function _0x224562(){var _0x274146=_0x2fe71d;_0x2909c0[_0x274146('0x279')](typeof _0x320370[_0x2ee3f5],_0x2909c0['pmZru'])&&(_0x981299[_0x342ea9]=null),_0x5bc806[_0x274146('0x2a')](_0x5019f4);}}else return _0xfa7cc3[_0x2fe71d('0x19f')];})[_0x263e11('0x194')](),0x1f);var _0x5d7e46=new Date(),_0x27c4b3=_0x5f139d[_0x263e11('0x11e')](_0x5d7e46,_0x3a2641);}});}else{function _0x260a47(){var _0x15ccb0=_0x1aaa45;_0x544358[_0x15ccb0('0x6e')][_0x19fd90[_0x15ccb0('0x151')][_0x15ccb0('0xa1')]]=function(){var _0x2564e4=_0x15ccb0,_0x4295e4=function(){var _0x646f51=_0x56f6;_0xc24288[_0x646f51('0x6e')][_0x35c3a7[_0x646f51('0x151')][_0x646f51('0xa1')]]=!![],_0x1bcb4b[_0x646f51('0x2ae')](),_0x4e1b77[_0x646f51('0x256')](_0x5a47e6,_0x2fe703['Tests'][_0x646f51('0xa1')]);};_0x390e17[_0x2564e4('0xeb')](_0x4c6afb,_0x433457[_0x2564e4('0x151')][_0x2564e4('0xa1')]);};}}},_0x4c2944,_0x21a2ea;if(window['requestIdleCallback']){if(_0x1ba7c2['ZTnLG'](_0x1ba7c2['aaMLW'],_0x1ba7c2[_0x16c83c('0x1ca')])){function _0x90aa08(){var _0x4e9583=_0x16c83c,_0x44be16=[];for(var _0x584113=0x0;_0x1ba7c2['DUVML'](_0x584113,0x4);_0x584113++)for(var _0x575e0a=0x0;_0x1ba7c2[_0x4e9583('0x76')](_0x575e0a,0x4);_0x575e0a++)_0x44be16[_0x1ba7c2[_0x4e9583('0x142')](_0x1ba7c2['pSKvH'](_0x575e0a,0x4),_0x584113)]=_0x2fa387[_0x1ba7c2['NcjKp'](_0x1ba7c2[_0x4e9583('0x142')](_0x46b360,_0x1ba7c2['Zjcdm'](_0x584113,0x4)),_0x575e0a)];return _0x44be16;}}else _0x4c2944=_0x1ba7c2[_0x16c83c('0xf6')](requestIdleCallback,_0x2fb723),_0x21a2ea=cancelIdleCallback;}else{if(_0x1ba7c2[_0x16c83c('0xe8')](_0x1ba7c2[_0x16c83c('0x113')],_0x1ba7c2[_0x16c83c('0x113')])){function _0x3b16f7(){var _0x51bc4a=_0x16c83c,_0x216367=function(){var _0x30341a=_0x56f6;_0x1643f2[_0x30341a('0x6e')][_0x2664be[_0x30341a('0x151')][_0x30341a('0x23f')]]=!![],_0x7a1926[_0x30341a('0x2ae')](),_0x3b06dc[_0x30341a('0x256')](_0x49a7dc,_0x9ed83[_0x30341a('0x151')][_0x30341a('0x23f')],_0x216367);};_0x1da6eb[_0x51bc4a('0xeb')](_0x39d7da,_0x509aee[_0x51bc4a('0x151')][_0x51bc4a('0x23f')]);}}else _0x4c2944=_0x1ba7c2[_0x16c83c('0x1c2')](setTimeout,_0x2fb723,0x1f4),_0x21a2ea=clearTimeout;}_0x1ba7c2[_0x16c83c('0x280')](sweetAlert,{'title':_0x1ba7c2[_0x16c83c('0x253')],'text':_0x1ba7c2[_0x16c83c('0x19b')],'type':_0x1ba7c2[_0x16c83c('0x23d')],'confirmButtonText':_0x1ba7c2[_0x16c83c('0x83')]},function(){var _0x50bf3c=_0x16c83c;if(_0x1ba7c2['lIssX'](_0x1ba7c2[_0x50bf3c('0x1da')],_0x1ba7c2['ptOfT'])){function _0x322562(){_0x2e86ab=this['aes']['encrypt'](_0x4eb438,_0x3d116f,_0x2d6cfe),_0x3f864c=![];}}else document[_0x50bf3c('0xe6')]=_0x1ba7c2[_0x50bf3c('0x142')](_0x1ba7c2[_0x50bf3c('0x18a')](_0x1ba7c2[_0x50bf3c('0x2a7')],_0x3489cb),_0x1ba7c2[_0x50bf3c('0x15b')]),document[_0x50bf3c('0xe6')]=_0x1ba7c2[_0x50bf3c('0x10c')](_0x1ba7c2[_0x50bf3c('0x10c')](_0x1ba7c2['IdnMa'],_0xecd926),_0x1ba7c2[_0x50bf3c('0x29')]),location[_0x50bf3c('0x4b')]=_0x5399f0;});}function setTimeToLive(){var _0x524783=_0x56f6,_0x1a29c7={'wxcxh':function(_0x14c37a,_0x299d85){return _0x14c37a*_0x299d85;}},_0x9c2ff=new Date(),_0x1181c2=_0x9c2ff[_0x524783('0xc4')]();return _0x1181c2+=_0x1a29c7['wxcxh'](_0x1a29c7['wxcxh'](0xe10,0x3e8),0x18),_0x9c2ff['setTime'](_0x1181c2),_0x9c2ff;}function BotDetector(_0x11407c){var _0x3b3111=_0x56f6,_0x1320c9={'hbPKb':function(_0xe43065,_0x174257){return _0xe43065!==_0x174257;},'RmaBR':'fQahG','EEwaj':_0x3b3111('0x125'),'yiyZi':function(_0x3e4681,_0x2ffb0f){return _0x3e4681===_0x2ffb0f;},'qLSHS':_0x3b3111('0x18c'),'xvBcN':'KyBpy','UotXU':function(_0x1ff3a4,_0x53f0d8){return _0x1ff3a4-_0x53f0d8;},'NNsHy':function(_0x4b6724,_0x5c0392){return _0x4b6724%_0x5c0392;},'UGESz':function(_0x20a5b4,_0x15ce77){return _0x20a5b4<_0x15ce77;},'WeAGr':function(_0x218d6e,_0x10d11e){return _0x218d6e!==_0x10d11e;},'DKpoj':_0x3b3111('0xf8'),'wsQql':'morFj','yHnIJ':_0x3b3111('0x1a9'),'DYEIk':function(_0x56add8,_0x405a6c){return _0x56add8(_0x405a6c);},'YLapC':_0x3b3111('0x128'),'XNBfy':_0x3b3111('0xa'),'wwSlP':function(_0x1ef09a,_0x47a1ba){return _0x1ef09a===_0x47a1ba;},'gnbYy':function(_0x2afe66,_0x22209d){return _0x2afe66<_0x22209d;},'ybLog':function(_0x4cdf0,_0x1be804){return _0x4cdf0*_0x1be804;},'PYgyU':function(_0xb0ad83,_0x32315f){return _0xb0ad83+_0x32315f;},'TLoCZ':function(_0x487bca,_0x5cbb88){return _0x487bca>_0x5cbb88;},'HIAYk':function(_0x46496d,_0x4c8baa){return _0x46496d-_0x4c8baa;},'bPVrG':function(_0x2d4abf,_0x46d187){return _0x2d4abf+_0x46d187;},'MSjfS':function(_0x20cd99,_0x28aa5e){return _0x20cd99===_0x28aa5e;},'hUEIV':'gvIkK','vpFXw':function(_0x57abbc,_0x960968){return _0x57abbc===_0x960968;},'FsKEt':_0x3b3111('0x1eb'),'GMLqJ':_0x3b3111('0x21c'),'gnNNj':_0x3b3111('0x40'),'fifMg':function(_0x5bd5f2,_0xedea7a){return _0x5bd5f2^_0xedea7a;},'LkRWS':function(_0xf55899,_0x412cf6){return _0xf55899<_0x412cf6;},'uwokL':function(_0x84231e,_0x5df2db){return _0x84231e-_0x5df2db;},'TNFKS':function(_0x151f37,_0x32ffea){return _0x151f37<_0x32ffea;},'CZiOh':function(_0x1e882a,_0x223eef){return _0x1e882a==_0x223eef;},'SPpiB':function(_0x326056,_0x320c2b){return _0x326056<_0x320c2b;},'PYxPV':function(_0x490dc0,_0x4d8d81){return _0x490dc0>_0x4d8d81;},'LtoOG':_0x3b3111('0xb9'),'mbAKo':function(_0x458f78,_0x3c8afb){return _0x458f78-_0x3c8afb;},'QMdkk':function(_0x30e7a7,_0x29590a){return _0x30e7a7^_0x29590a;},'lwooq':_0x3b3111('0x288'),'mgufu':'PeTnn','TWIdE':_0x3b3111('0x262'),'uYFkG':_0x3b3111('0xc0'),'qmqdl':function(_0x1db037,_0x22854a){return _0x1db037!=_0x22854a;},'iMgGK':_0x3b3111('0x188'),'kyqjA':function(_0x4c99ae,_0x2ac10a){return _0x4c99ae*_0x2ac10a;},'bugIN':function(_0x32b17d,_0x33558f){return _0x32b17d/_0x33558f;},'VzZIy':function(_0x4cc4cd,_0x159791){return _0x4cc4cd*_0x159791;},'XlqRL':function(_0xc2e449,_0x5a8357){return _0xc2e449/_0x5a8357;},'ONGum':'bMnXB','VqceB':function(_0x2bffdd,_0x94595d){return _0x2bffdd!==_0x94595d;},'Mptzk':_0x3b3111('0x160'),'zcDxD':_0x3b3111('0x1c7'),'sNlbJ':function(_0x41fb54,_0x31fb2c){return _0x41fb54!=_0x31fb2c;},'NZqAp':_0x3b3111('0xd2'),'rCFfL':_0x3b3111('0x141'),'XHtIB':function(_0x45679e,_0x35ed91){return _0x45679e>_0x35ed91;},'GWfik':function(_0x22a699,_0x5d0bb3){return _0x22a699!==_0x5d0bb3;},'vTtZP':_0x3b3111('0x231'),'NwJdL':_0x3b3111('0x122'),'Ibasz':_0x3b3111('0x4'),'WVGDy':function(_0x4b1338,_0x480ac9){return _0x4b1338!==_0x480ac9;},'BywZX':_0x3b3111('0x293'),'ucPrP':function(_0x4a91e7,_0x3b58ab){return _0x4a91e7===_0x3b58ab;},'YnjBQ':_0x3b3111('0x214'),'izTmF':_0x3b3111('0x271'),'EiklJ':function(_0x30f666,_0x59fd0d){return _0x30f666!==_0x59fd0d;},'xYVIQ':_0x3b3111('0x48'),'fdxxh':function(_0x838fd4,_0x10e433){return _0x838fd4^_0x10e433;},'fvoXl':function(_0x5e618e,_0x56cb1a){return _0x5e618e-_0x56cb1a;},'JdzLc':function(_0x513fe0,_0x431e13){return _0x513fe0+_0x431e13;},'sQxBt':function(_0x4d1df2,_0x20f6e5){return _0x4d1df2===_0x20f6e5;},'nmXCt':_0x3b3111('0x22c'),'VbIYa':_0x3b3111('0x15'),'Ulwpy':_0x3b3111('0x10'),'CxSGD':function(_0x540ff0,_0x35da40){return _0x540ff0==_0x35da40;},'KXDNm':function(_0x152268,_0x1c9645){return _0x152268!==_0x1c9645;},'MzrLG':_0x3b3111('0x7a'),'mSgTj':'oFUVw','WumsD':function(_0x201137,_0x3e8e8b){return _0x201137===_0x3e8e8b;},'mnnxp':_0x3b3111('0x86'),'QVelX':function(_0x1fe337,_0x42224f){return _0x1fe337!=_0x42224f;},'SgGxV':function(_0x11d667,_0x3bb7f9){return _0x11d667===_0x3bb7f9;},'bHFIT':_0x3b3111('0x220'),'oICqI':function(_0x24f394,_0x282d49){return _0x24f394==_0x282d49;},'HFQwp':_0x3b3111('0x1b9'),'JhJPZ':'ORzJf','EPUBS':_0x3b3111('0x213'),'uDXBC':_0x3b3111('0x217'),'SLqye':function(_0x4018aa,_0x14d848){return _0x4018aa==_0x14d848;},'dnGoy':function(_0x4b6b,_0x58c87a){return _0x4b6b!=_0x58c87a;},'qBqMS':function(_0x58463a,_0x3f2407){return _0x58463a!==_0x3f2407;},'CZQmT':_0x3b3111('0x81'),'BMexY':'dpQqF','ozRni':function(_0x16751a,_0xfada5a){return _0x16751a!==_0xfada5a;},'HGAcX':_0x3b3111('0x109')},_0x3a80e2=this;_0x3a80e2['isBot']=![],_0x3a80e2[_0x3b3111('0x6e')]={};var _0x4c3eb4=_0x11407c[_0x3b3111('0x6e')]||[];if(_0x1320c9[_0x3b3111('0x254')](_0x4c3eb4[_0x3b3111('0x2b')],0x0)||_0x1320c9[_0x3b3111('0x13b')](_0x4c3eb4[_0x3b3111('0x57')](BotDetector[_0x3b3111('0x151')][_0x3b3111('0x174')]),-0x1)){if(_0x1320c9[_0x3b3111('0x24')](_0x1320c9[_0x3b3111('0x107')],_0x1320c9[_0x3b3111('0xa4')]))_0x3a80e2['tests'][BotDetector[_0x3b3111('0x151')][_0x3b3111('0x174')]]=function(){var _0x856432=_0x3b3111;if(_0x1320c9[_0x856432('0x21')](_0x1320c9[_0x856432('0x131')],_0x1320c9[_0x856432('0x238')])){function _0x3b7404(){var _0x1953ab=_0x856432;_0x435f8e=this[_0x1953ab('0x21a')][_0x1953ab('0x239')](_0x1cec25,_0x208da1,_0x1470aa),_0x5eacda=![];}}else{var _0x359699=function(){var _0xb3fdec=_0x856432;if(_0x1320c9['hbPKb'](_0x1320c9['RmaBR'],_0x1320c9[_0xb3fdec('0x11')]))_0x3a80e2['tests'][BotDetector[_0xb3fdec('0x151')][_0xb3fdec('0x174')]]=!![],_0x3a80e2[_0xb3fdec('0x2ae')](),_0x3a80e2[_0xb3fdec('0x256')](window,BotDetector[_0xb3fdec('0x151')]['SCROLL'],_0x359699),_0x3a80e2[_0xb3fdec('0x256')](document,BotDetector['Tests'][_0xb3fdec('0x174')],_0x359699);else{function _0x214a97(){var _0x2955a=_0xb3fdec;this[_0x2955a('0x6e')][_0x1f4b5f][_0x2955a('0x134')]();}}};_0x3a80e2[_0x856432('0xeb')](window,BotDetector[_0x856432('0x151')][_0x856432('0x174')],_0x359699),_0x3a80e2['bindEvent'](document,BotDetector[_0x856432('0x151')][_0x856432('0x174')],_0x359699);}};else{function _0x4bd696(){var _0x15008a=_0x3b3111,_0x595505=_0x4b1bba[_0x15008a('0x2b')],_0x40a2f9=_0x1320c9[_0x15008a('0x59')](0x10,_0x1320c9[_0x15008a('0x94')](_0x595505,0x10));for(var _0x117aba=0x0;_0x1320c9[_0x15008a('0x1d5')](_0x117aba,_0x40a2f9);_0x117aba++){_0x4a783c['push'](_0x40a2f9);}}}}if(_0x1320c9[_0x3b3111('0x254')](_0x4c3eb4[_0x3b3111('0x2b')],0x0)||_0x1320c9[_0x3b3111('0x13b')](_0x4c3eb4['indexOf'](BotDetector['Tests'][_0x3b3111('0x9a')]),-0x1)){if(_0x1320c9['WumsD'](_0x1320c9[_0x3b3111('0x282')],_0x1320c9['mnnxp']))_0x3a80e2[_0x3b3111('0x6e')][BotDetector[_0x3b3111('0x151')][_0x3b3111('0x9a')]]=function(){var _0x393c2d=_0x3b3111,_0x9a1685={'mvmtg':function(_0x4b7dcc,_0x29ea00){return _0x1320c9['WeAGr'](_0x4b7dcc,_0x29ea00);},'rRAjn':_0x1320c9[_0x393c2d('0x1af')]};if(_0x1320c9[_0x393c2d('0x21')](_0x1320c9[_0x393c2d('0xc6')],_0x1320c9[_0x393c2d('0xc6')])){var _0x5491eb=function(){var _0x5ae089=_0x393c2d;if(_0x9a1685[_0x5ae089('0x9d')](_0x9a1685[_0x5ae089('0x171')],_0x9a1685[_0x5ae089('0x171')])){function _0x244ace(){var _0x56e0a2=_0x5ae089;_0x4e71f8[_0x56e0a2('0x2ae')](!![]);}}else _0x3a80e2['tests'][BotDetector[_0x5ae089('0x151')][_0x5ae089('0x9a')]]=!![],_0x3a80e2[_0x5ae089('0x2ae')](),_0x3a80e2[_0x5ae089('0x256')](window,BotDetector[_0x5ae089('0x151')][_0x5ae089('0x9a')],_0x5491eb);};_0x3a80e2[_0x393c2d('0xeb')](window,BotDetector['Tests'][_0x393c2d('0x9a')],_0x5491eb);}else{function _0x56ebb6(){var _0x2703f5=_0x393c2d;_0x3a7673[_0x2703f5('0x6e')][_0x3402b1[_0x2703f5('0x151')][_0x2703f5('0x174')]]=!![],_0x5e35ce[_0x2703f5('0x2ae')](),_0x11a889['unbindEvent'](_0x19c6df,_0x2264a1[_0x2703f5('0x151')][_0x2703f5('0x174')],_0x347515),_0x1c029c[_0x2703f5('0x256')](_0x4880d0,_0x3a4d41[_0x2703f5('0x151')][_0x2703f5('0x174')],_0x5902d6);}}};else{function _0x27bfa5(){_0x44933e['lastRotationData']={'beta':_0x275f14,'gamma':_0x44492e};}}}if(_0x1320c9[_0x3b3111('0x254')](_0x4c3eb4[_0x3b3111('0x2b')],0x0)||_0x1320c9[_0x3b3111('0x175')](_0x4c3eb4[_0x3b3111('0x57')](BotDetector[_0x3b3111('0x151')][_0x3b3111('0x15d')]),-0x1)){if(_0x1320c9[_0x3b3111('0x73')](_0x1320c9[_0x3b3111('0x120')],_0x1320c9[_0x3b3111('0x120')]))_0x3a80e2['tests'][BotDetector[_0x3b3111('0x151')]['KEYUP']]=function(){var _0x1f6249=_0x3b3111,_0x20bafa={'UDynn':function(_0x4f2b86,_0x1e0f25){var _0x2bbc6d=_0x56f6;return _0x1320c9[_0x2bbc6d('0x1a6')](_0x4f2b86,_0x1e0f25);}};if(_0x1320c9[_0x1f6249('0x2af')](_0x1320c9['YLapC'],_0x1320c9[_0x1f6249('0x2a2')])){var _0x3f72e3=function(){var _0x4f6bc8=_0x1f6249;if(_0x1320c9[_0x4f6bc8('0x21')](_0x1320c9[_0x4f6bc8('0x29e')],_0x1320c9[_0x4f6bc8('0x29e')]))_0x3a80e2['tests'][BotDetector[_0x4f6bc8('0x151')][_0x4f6bc8('0x15d')]]=!![],_0x3a80e2[_0x4f6bc8('0x2ae')](),_0x3a80e2[_0x4f6bc8('0x256')](window,BotDetector[_0x4f6bc8('0x151')][_0x4f6bc8('0x15d')],_0x3f72e3);else{function _0x434682(){_0x486983=this['aes']['encrypt'](_0x2eeca1,_0x564a30,_0x4b7ded),_0x393ae4=![];}}};_0x3a80e2[_0x1f6249('0xeb')](window,BotDetector[_0x1f6249('0x151')][_0x1f6249('0x15d')],_0x3f72e3);}else{function _0x2b5e6f(){var _0x8fc19=_0x1f6249;_0x4f2f14=_0x20bafa[_0x8fc19('0x164')](_0x519ad1,_0x13d49c),_0x13b3cb=_0xa61255;}}};else{function _0x337a15(){var _0x169ed9=_0x3b3111;_0x457212['cases'][_0x1a7661]=_0x1320c9[_0x169ed9('0x21')](_0x413563[_0x169ed9('0x6e')][_0x12fd3a],!![]),_0x1320c9['wwSlP'](_0xea386[_0x169ed9('0x147')][_0x8f9019],!![])&&_0x308706++;}}}if(_0x1320c9[_0x3b3111('0x156')](_0x4c3eb4[_0x3b3111('0x2b')],0x0)||_0x1320c9[_0x3b3111('0x175')](_0x4c3eb4[_0x3b3111('0x57')](BotDetector[_0x3b3111('0x151')][_0x3b3111('0xf7')]),-0x1)){if(_0x1320c9[_0x3b3111('0x24')](_0x1320c9['HFQwp'],_0x1320c9['JhJPZ']))_0x3a80e2['tests'][BotDetector['Tests'][_0x3b3111('0xa1')]]=function(){var _0x43e81d=_0x3b3111,_0x120ec6={'ZAxZv':function(_0x42529a,_0x17f30f){var _0x2e9fa5=_0x56f6;return _0x1320c9[_0x2e9fa5('0x224')](_0x42529a,_0x17f30f);},'EYnaf':function(_0x41c636,_0x348dd8){var _0xe1a5be=_0x56f6;return _0x1320c9[_0xe1a5be('0x2ac')](_0x41c636,_0x348dd8);},'Kyrjq':function(_0x17d03b,_0x32baa6){var _0x4b329f=_0x56f6;return _0x1320c9[_0x4b329f('0x205')](_0x17d03b,_0x32baa6);},'ntoTH':function(_0x300b6d,_0x1884c3){var _0x5025af=_0x56f6;return _0x1320c9[_0x5025af('0x56')](_0x300b6d,_0x1884c3);},'zlnEB':function(_0x55f77c,_0x41b03f){var _0x13fe14=_0x56f6;return _0x1320c9[_0x13fe14('0x2ac')](_0x55f77c,_0x41b03f);},'WrmpT':function(_0x8c7f07,_0x1c57ea){var _0xa26048=_0x56f6;return _0x1320c9[_0xa26048('0x37')](_0x8c7f07,_0x1c57ea);},'pbWKi':function(_0x35c312,_0x5865ae){var _0x2f20a2=_0x56f6;return _0x1320c9[_0x2f20a2('0x2a3')](_0x35c312,_0x5865ae);},'BPJes':_0x1320c9['hUEIV']};if(_0x1320c9[_0x43e81d('0x22')](_0x1320c9['FsKEt'],_0x1320c9[_0x43e81d('0x1f8')])){function _0x19e898(){var _0x511a41=_0x43e81d;for(var _0x182958=0x0;_0x1320c9['gnbYy'](_0x182958,0x4);_0x182958++)_0x27e650=this[_0x511a41('0x5e')](_0x4ac843,_0x1320c9[_0x511a41('0x21f')](_0x182958,0x4),_0x182958,_0x11d36f);return _0x525599;}}else{var _0x4bc9f2=function(){var _0x112816=_0x43e81d;if(_0x120ec6[_0x112816('0x18b')](_0x120ec6[_0x112816('0x4a')],_0x120ec6[_0x112816('0x4a')]))_0x3a80e2[_0x112816('0x6e')][BotDetector[_0x112816('0x151')][_0x112816('0xa1')]]=!![],_0x3a80e2[_0x112816('0x2ae')](),_0x3a80e2['unbindEvent'](document,BotDetector[_0x112816('0x151')][_0x112816('0xa1')]);else{function _0x2630bc(){var _0x1fc90d=_0x112816;for(var _0x16dc41=0x0;_0x120ec6[_0x1fc90d('0x257')](_0x16dc41,_0x6cb4bc);_0x16dc41++){if(_0x5d1c16){var _0x3dd55b=_0x11036c[_0x120ec6['EYnaf'](_0x1ae02e,0x3)];for(var _0x2fb829=0x3;_0x120ec6[_0x1fc90d('0x27')](_0x2fb829,0x0);_0x2fb829--)_0x4d2105[_0x120ec6[_0x1fc90d('0xfe')](_0x174a2d,_0x2fb829)]=_0x5e0879[_0x120ec6[_0x1fc90d('0x43')](_0x120ec6[_0x1fc90d('0x3e')](_0x42d97a,_0x2fb829),0x1)];_0x22cce6[_0x3580ce]=_0x3dd55b;}else{var _0x3dd55b=_0x427277[_0x29c293];for(var _0x2fb829=0x0;_0x120ec6[_0x1fc90d('0x257')](_0x2fb829,0x3);_0x2fb829++)_0x2eb908[_0x120ec6[_0x1fc90d('0x3e')](_0x54a84c,_0x2fb829)]=_0xc2a628[_0x120ec6[_0x1fc90d('0x3e')](_0x120ec6['WrmpT'](_0x19a0f4,_0x2fb829),0x1)];_0xe7b9ca[_0x120ec6[_0x1fc90d('0x198')](_0x225dae,0x3)]=_0x3dd55b;}}return _0x1fbd39;}}};_0x3a80e2['bindEvent'](document,BotDetector['Tests'][_0x43e81d('0xa1')]);}};else{function _0x22d219(){var _0x313127=_0x3b3111,_0x3fdbea=_0x1320c9[_0x313127('0x25d')]['split']('|'),_0xc55ce0=0x0;while(!![]){switch(_0x3fdbea[_0xc55ce0++]){case'0':_0x467bf7=this[_0x313127('0x21a')]['decrypt'](_0x1d7acc,_0xa86c15,_0x29ab13);continue;case'1':for(_0x39b12f=0x0;_0x1320c9[_0x313127('0x224')](_0x14e410,0x10);_0x5a4ff2++)_0x2b1061[_0x1b7046]=_0x1320c9[_0x313127('0x26')](_0x5255ae?_0x1b8abf[_0x3842db]:_0x4a7294[_0x4191d2],_0x1c7129[_0x5ebee0]);continue;case'2':for(var _0x3a324c=0x0;_0x1320c9[_0x313127('0xef')](_0x3a324c,_0x1320c9['uwokL'](_0x4bf9e8,_0x148042));_0x3a324c++)_0x5b79d1[_0x313127('0x3')](_0x2dafa1[_0x3a324c]);continue;case'3':_0x4148fd=_0x5d39d4;continue;case'4':_0x3654bb=![];continue;}break;}}}}if(_0x1320c9[_0x3b3111('0x156')](_0x4c3eb4[_0x3b3111('0x2b')],0x0)||_0x1320c9[_0x3b3111('0x175')](_0x4c3eb4[_0x3b3111('0x57')](BotDetector['Tests']['DEVICE_MOTION']),-0x1)){if(_0x1320c9['SgGxV'](_0x1320c9[_0x3b3111('0x11a')],_0x1320c9[_0x3b3111('0x34')])){function _0x520255(){var _0x299042=_0x3b3111;_0x3b5573[_0x299042('0x6e')][_0x227cdf[_0x299042('0x151')]['DEVICE_ORIENTATION']]=function(){var _0x5d9bf1=_0x299042,_0x1dd24e=function(){var _0x303c5d=_0x56f6;_0x2bd92e[_0x303c5d('0x6e')][_0x4b9a47[_0x303c5d('0x151')][_0x303c5d('0x23f')]]=!![],_0x4eec6d[_0x303c5d('0x2ae')](),_0xaaf2c2['unbindEvent'](_0x1239fe,_0x435723[_0x303c5d('0x151')][_0x303c5d('0x23f')],_0x1dd24e);};_0x48939c[_0x5d9bf1('0xeb')](_0x391023,_0x7dde1d['Tests']['DEVICE_ORIENTATION']);};}}else _0x3a80e2[_0x3b3111('0x6e')][BotDetector[_0x3b3111('0x151')][_0x3b3111('0x10f')]]=function(){var _0x385e29=_0x3b3111,_0x19de28={'FTERi':function(_0x391250,_0x4b7a88){var _0x34f066=_0x56f6;return _0x1320c9[_0x34f066('0x20d')](_0x391250,_0x4b7a88);},'AoNTl':function(_0x55fb76,_0xe4865e){var _0x19adbc=_0x56f6;return _0x1320c9[_0x19adbc('0x26')](_0x55fb76,_0xe4865e);},'yLPhN':function(_0x4c3b4a,_0x57dcdc){var _0x2fe56f=_0x56f6;return _0x1320c9[_0x2fe56f('0x37')](_0x4c3b4a,_0x57dcdc);},'YqAfV':function(_0x42a58f,_0x68f1f5){var _0x4f2bca=_0x56f6;return _0x1320c9[_0x4f2bca('0x37')](_0x42a58f,_0x68f1f5);},'fxNju':function(_0x5e09ae,_0x5077fd){var _0x1df453=_0x56f6;return _0x1320c9[_0x1df453('0x169')](_0x5e09ae,_0x5077fd);},'nYVUo':function(_0x48896f,_0x26aa59){var _0x5f2797=_0x56f6;return _0x1320c9[_0x5f2797('0x264')](_0x48896f,_0x26aa59);},'RaawF':function(_0xdfcfc9,_0x5eee9b){var _0x1a169b=_0x56f6;return _0x1320c9[_0x1a169b('0x8e')](_0xdfcfc9,_0x5eee9b);},'JlbkR':_0x1320c9[_0x385e29('0x26a')],'HBdyC':function(_0x510e4f,_0x8d4e65){var _0x37111b=_0x385e29;return _0x1320c9[_0x37111b('0x35')](_0x510e4f,_0x8d4e65);},'PHAFF':function(_0x5a4e7c,_0xdc1704){var _0x475b52=_0x385e29;return _0x1320c9[_0x475b52('0x25e')](_0x5a4e7c,_0xdc1704);},'rHFho':function(_0x13fdd2,_0x4928c0){var _0x4eea48=_0x385e29;return _0x1320c9[_0x4eea48('0x2af')](_0x13fdd2,_0x4928c0);},'isKyV':_0x1320c9[_0x385e29('0x1a0')],'CEwZJ':_0x1320c9[_0x385e29('0xd6')],'fQeXs':function(_0xa0a7ec,_0x34c4f6){var _0x48a507=_0x385e29;return _0x1320c9[_0x48a507('0x22')](_0xa0a7ec,_0x34c4f6);},'tPDdh':_0x1320c9[_0x385e29('0x23a')],'HfdyJ':_0x1320c9['uYFkG'],'pnZzI':function(_0xffe72d,_0x1a5c1b){var _0x4e681f=_0x385e29;return _0x1320c9[_0x4e681f('0x1e9')](_0xffe72d,_0x1a5c1b);},'vFakg':_0x1320c9[_0x385e29('0x1ab')],'BNDrK':function(_0x27b306,_0x9d1e9e){var _0x2662e2=_0x385e29;return _0x1320c9[_0x2662e2('0xde')](_0x27b306,_0x9d1e9e);},'QVBuB':function(_0x317334,_0x2d712c){var _0x177978=_0x385e29;return _0x1320c9[_0x177978('0x75')](_0x317334,_0x2d712c);},'xxmrD':function(_0x1007cd,_0x22b93e){var _0xb74e14=_0x385e29;return _0x1320c9[_0xb74e14('0x260')](_0x1007cd,_0x22b93e);},'hwVJy':function(_0x5d4c89,_0x3116a6){var _0x56c6bf=_0x385e29;return _0x1320c9[_0x56c6bf('0x25c')](_0x5d4c89,_0x3116a6);},'aSpqp':_0x1320c9[_0x385e29('0x241')],'GFyKD':function(_0x43ae5b,_0x566a9d){var _0x38456f=_0x385e29;return _0x1320c9[_0x38456f('0x258')](_0x43ae5b,_0x566a9d);},'qHoNb':_0x1320c9['Mptzk'],'haoFp':_0x1320c9[_0x385e29('0x195')],'qkums':function(_0x5ddb2b,_0x25e1dc){var _0x4b5fc7=_0x385e29;return _0x1320c9[_0x4b5fc7('0x1e9')](_0x5ddb2b,_0x25e1dc);},'rfuDT':function(_0x484cb1,_0x333bb9){var _0xd2de8f=_0x385e29;return _0x1320c9[_0xd2de8f('0x13b')](_0x484cb1,_0x333bb9);},'fUvNV':function(_0x3fdedb,_0x458100){var _0x1d2854=_0x385e29;return _0x1320c9[_0x1d2854('0x22')](_0x3fdedb,_0x458100);},'ycOJz':_0x1320c9[_0x385e29('0x2f')],'jsRGU':_0x1320c9[_0x385e29('0x5d')],'tWgIp':function(_0x430ef4,_0x599440){return _0x1320c9['XHtIB'](_0x430ef4,_0x599440);},'UAHPL':function(_0x2c1ff9,_0x2d87f0){return _0x1320c9['GWfik'](_0x2c1ff9,_0x2d87f0);},'KdWui':_0x1320c9['vTtZP'],'VrVYF':_0x1320c9[_0x385e29('0xdf')],'SQwIX':_0x1320c9[_0x385e29('0x105')]};if(_0x1320c9[_0x385e29('0x19e')](_0x1320c9['BywZX'],_0x1320c9['BywZX'])){function _0x37e9e7(){var _0x20729e=_0x385e29;_0x53f39e=this[_0x20729e('0x1c8')](_0x102c7f);for(var _0x164fd2=0x0;_0x19de28[_0x20729e('0x191')](_0x164fd2,0x4);++_0x164fd2)_0x2c3a12[_0x164fd2]=this[_0x20729e('0x7b')][_0x28942b[_0x164fd2]];return _0x563514[0x0]=_0x19de28[_0x20729e('0x1ce')](_0x14ad38[0x0],this[_0x20729e('0x25f')][_0x4794d9]),_0x517f50;}}else{var _0x503b56=function(_0x2307fe){var _0x3765ba=_0x385e29,_0x362894={'fWKpO':function(_0x42c334,_0x140038){return _0x19de28['FTERi'](_0x42c334,_0x140038);},'fATgY':function(_0x31d12f,_0x4c75a0){var _0x412100=_0x56f6;return _0x19de28[_0x412100('0x124')](_0x31d12f,_0x4c75a0);},'VXYdv':function(_0x45726f,_0x445652){var _0x1c85e9=_0x56f6;return _0x19de28[_0x1c85e9('0x1db')](_0x45726f,_0x445652);},'AZlfN':function(_0x1ca43b,_0x1d1058){return _0x19de28['fxNju'](_0x1ca43b,_0x1d1058);},'Kbjcb':function(_0x204dbe,_0x35e1a0){var _0x8f6741=_0x56f6;return _0x19de28[_0x8f6741('0x3c')](_0x204dbe,_0x35e1a0);},'caxYH':function(_0x5edba0,_0x532f70){var _0x4f56c0=_0x56f6;return _0x19de28[_0x4f56c0('0x1db')](_0x5edba0,_0x532f70);},'XHSLr':function(_0x581566,_0xcf89d0){var _0x2c84c8=_0x56f6;return _0x19de28[_0x2c84c8('0x7e')](_0x581566,_0xcf89d0);},'dwryw':_0x19de28['JlbkR'],'xxGYT':function(_0x225b40,_0x49d7e4){var _0x2cf8a3=_0x56f6;return _0x19de28[_0x2cf8a3('0x3c')](_0x225b40,_0x49d7e4);},'oWrpy':function(_0x49b0be,_0x4b4c4b){var _0x20e3cd=_0x56f6;return _0x19de28[_0x20e3cd('0x1ce')](_0x49b0be,_0x4b4c4b);},'MlCHH':function(_0x1fd8fa,_0x1b6833){return _0x19de28['nYVUo'](_0x1fd8fa,_0x1b6833);},'mOmNI':function(_0x3c5540,_0x48b995){var _0x3bdfbe=_0x56f6;return _0x19de28[_0x3bdfbe('0xf4')](_0x3c5540,_0x48b995);},'XDikn':function(_0x1f2c03,_0x1e34f3){var _0x5c2663=_0x56f6;return _0x19de28[_0x5c2663('0x3c')](_0x1f2c03,_0x1e34f3);},'uVyKH':function(_0x593933,_0x1f4c33){return _0x19de28['PHAFF'](_0x593933,_0x1f4c33);},'RWLmG':function(_0x2b1f9f,_0x559a1a){var _0x2e5618=_0x56f6;return _0x19de28[_0x2e5618('0x3c')](_0x2b1f9f,_0x559a1a);},'MmuMn':function(_0x221595,_0x32fe1e){var _0x2e7d2f=_0x56f6;return _0x19de28[_0x2e7d2f('0xf4')](_0x221595,_0x32fe1e);}};if(_0x19de28['rHFho'](_0x19de28[_0x3765ba('0x15a')],_0x19de28[_0x3765ba('0x1c1')])){if(_0x2307fe['rotationRate'][_0x3765ba('0x26b')]||_0x2307fe['rotationRate'][_0x3765ba('0x1a3')]||_0x2307fe['rotationRate'][_0x3765ba('0x210')]){if(_0x19de28[_0x3765ba('0xd')](_0x19de28['tPDdh'],_0x19de28[_0x3765ba('0xb4')])){function _0x327112(){var _0x2b88be=_0x3765ba,_0x5eb2ac=_0x269c78[_0x70abe];for(var _0x172c6c=0x0;_0x362894[_0x2b88be('0x281')](_0x172c6c,0x3);_0x172c6c++)_0x38614c[_0x362894[_0x2b88be('0x66')](_0x5b51a0,_0x172c6c)]=_0x581bac[_0x362894['VXYdv'](_0x362894[_0x2b88be('0x5b')](_0x2269d9,_0x172c6c),0x1)];_0x24d729[_0x362894['VXYdv'](_0x19a067,0x3)]=_0x5eb2ac;}}else{var _0x58b3c5=navigator[_0x3765ba('0x27a')][_0x3765ba('0x27b')](),_0x296da3=_0x19de28[_0x3765ba('0x277')](_0x58b3c5[_0x3765ba('0x57')](_0x19de28[_0x3765ba('0x22f')]),-0x1),_0x1bb3b1=_0x296da3?_0x2307fe[_0x3765ba('0x14f')][_0x3765ba('0x1a3')]:_0x19de28[_0x3765ba('0x1cd')](Math['round'](_0x19de28['QVBuB'](_0x2307fe[_0x3765ba('0x14f')][_0x3765ba('0x1a3')],0xa)),0xa),_0x1bb3e3=_0x296da3?_0x2307fe[_0x3765ba('0x14f')]['gamma']:_0x19de28[_0x3765ba('0x79')](Math[_0x3765ba('0x1c0')](_0x19de28[_0x3765ba('0x49')](_0x2307fe[_0x3765ba('0x14f')][_0x3765ba('0x210')],0xa)),0xa);if(!_0x3a80e2[_0x3765ba('0x130')]){if(_0x19de28[_0x3765ba('0xd')](_0x19de28[_0x3765ba('0xec')],_0x19de28[_0x3765ba('0xec')]))_0x3a80e2[_0x3765ba('0x130')]={'beta':_0x1bb3b1,'gamma':_0x1bb3e3};else{function _0x5980a1(){var _0xfeb37=_0x3765ba;for(var _0x4cf2f2=[],_0x4cf2f2=_0x362894[_0xfeb37('0x211')](0x1,arguments['length'])&&_0x362894[_0xfeb37('0x211')](arguments[0x0][_0xfeb37('0x1ae')],_0x2b4b06)?arguments[0x0]:arguments,_0x38028b='',_0x58192c=0x0;_0x362894[_0xfeb37('0x133')](_0x58192c,_0x4cf2f2[_0xfeb37('0x2b')]);_0x58192c++)_0x38028b+=_0x362894[_0xfeb37('0x11d')](_0x362894['XHSLr'](0x10,_0x4cf2f2[_0x58192c])?'0':'',_0x4cf2f2[_0x58192c][_0xfeb37('0x201')](0x10));return _0x38028b[_0xfeb37('0x27b')]();}}}else{if(_0x19de28[_0x3765ba('0x1f5')](_0x19de28['qHoNb'],_0x19de28['haoFp'])){var _0xe2bd6e=_0x19de28[_0x3765ba('0x18')](_0x1bb3b1,_0x3a80e2[_0x3765ba('0x130')][_0x3765ba('0x1a3')])||_0x19de28[_0x3765ba('0xb3')](_0x1bb3e3,_0x3a80e2['lastRotationData'][_0x3765ba('0x210')]);if(_0x296da3){if(_0x19de28[_0x3765ba('0xc3')](_0x19de28[_0x3765ba('0x38')],_0x19de28[_0x3765ba('0x7')])){function _0x5744a0(){var _0x22bdb5=_0x3765ba;_0x36fba2['isBot']&&_0x5e5af1[_0x22bdb5('0x232')][_0x22bdb5('0x13d')](_0x362894[_0x22bdb5('0x9f')]);}}else _0xe2bd6e=_0xe2bd6e&&(_0x19de28[_0x3765ba('0x7e')](_0x1bb3b1,0.2)||_0x19de28[_0x3765ba('0x148')](_0x1bb3e3,0.2));}var _0x30b178={'beta':_0x1bb3b1,'gamma':_0x1bb3e3};_0x3a80e2['tests'][BotDetector[_0x3765ba('0x151')][_0x3765ba('0x10f')]]=_0xe2bd6e,_0x3a80e2[_0x3765ba('0x2ae')]();if(_0xe2bd6e){if(_0x19de28[_0x3765ba('0xba')](_0x19de28['KdWui'],_0x19de28[_0x3765ba('0x1e0')])){function _0xe5b474(){var _0x5eb86b=_0x3765ba;if(_0x40290a)_0x4de79b=this['aes'][_0x5eb86b('0x239')](_0x27cccc,_0x285734,_0x314cfc),_0x1baf72=![];else _0x3cd7aa=this[_0x5eb86b('0x21a')][_0x5eb86b('0x239')](_0x3efe92,_0x4483d1,_0x4d401f);for(_0x4f7959=0x0;_0x362894['xxGYT'](_0x23e873,0x10);_0xd17043++)_0x4928ab[_0x2e0f1f]=_0x362894[_0x5eb86b('0xe')](_0x170287[_0x788412],_0x5a2adb[_0x157c7c]);for(var _0x39c1b0=0x0;_0x362894[_0x5eb86b('0x1')](_0x39c1b0,_0x362894[_0x5eb86b('0x17e')](_0x20fd45,_0x4d750b));_0x39c1b0++)_0x6a9592[_0x5eb86b('0x3')](_0x5098bc[_0x39c1b0]);_0x3bfb2c=_0x223441;}}else _0x3a80e2[_0x3765ba('0x256')](window,BotDetector[_0x3765ba('0x151')][_0x3765ba('0x10f')],_0x503b56);}}else{function _0x57801f(){var _0x2af0cb=_0x3765ba;if(_0x305da6)_0x115182=this[_0x2af0cb('0x21a')][_0x2af0cb('0x239')](_0x3f5855,_0x4bc12b,_0x310276),_0x211630=![];else _0x5a825d=this['aes'][_0x2af0cb('0x239')](_0x5b22fa,_0x2ea033,_0x52725d);for(var _0x36fd82=0x0;_0x362894['XDikn'](_0x36fd82,0x10);_0x36fd82++)_0x95d1e7[_0x36fd82]=_0x362894[_0x2af0cb('0xb1')](_0x582dcc[_0x36fd82],_0x130897[_0x36fd82]);for(var _0x3f0385=0x0;_0x362894['RWLmG'](_0x3f0385,_0x362894[_0x2af0cb('0x29f')](_0x3f8a69,_0x5336a0));_0x3f0385++)_0x5bf2fc[_0x2af0cb('0x3')](_0x2be79c[_0x3f0385]);_0x2a5f50=_0x1f1202;}}}}}else{if(_0x19de28[_0x3765ba('0xba')](_0x19de28[_0x3765ba('0x15f')],_0x19de28[_0x3765ba('0xfa')]))_0x3a80e2[_0x3765ba('0x6e')][BotDetector[_0x3765ba('0x151')][_0x3765ba('0x10f')]]=![];else{function _0xc6df31(){var _0x34c635=_0x3765ba;_0x4bbd52[_0x34c635('0x28a')](_0x362894[_0x34c635('0x11d')]('on',_0x11fff7),_0x5051f6);}}}}else{function _0x3ab206(){var _0x27b931=_0x3765ba;_0x32c2af[_0x27b931('0x121')](_0xcbe887,_0x4a6af9,![]);}}};_0x3a80e2[_0x385e29('0xeb')](window,BotDetector['Tests'][_0x385e29('0x10f')],_0x503b56);}};}if(_0x1320c9[_0x3b3111('0x20a')](_0x4c3eb4[_0x3b3111('0x2b')],0x0)||_0x1320c9[_0x3b3111('0x162')](_0x4c3eb4[_0x3b3111('0x57')](BotDetector[_0x3b3111('0x151')][_0x3b3111('0x23f')]),-0x1)){if(_0x1320c9[_0x3b3111('0x1ac')](_0x1320c9[_0x3b3111('0x292')],_0x1320c9[_0x3b3111('0x291')]))_0x3a80e2[_0x3b3111('0x6e')][BotDetector['Tests']['DEVICE_ORIENTATION']]=function(){var _0x134209=_0x3b3111;if(_0x1320c9['EiklJ'](_0x1320c9[_0x134209('0xca')],_0x1320c9[_0x134209('0xca')])){function _0x3b65a8(){var _0x3f1576=_0x134209;_0x2303bb=this[_0x3f1576('0x21a')][_0x3f1576('0x239')](_0x5191f1,_0x1cc336,_0x91dad4),_0x265f56=![];}}else{var _0x214a70=function(){var _0x38cb97=_0x134209;if(_0x1320c9['ucPrP'](_0x1320c9[_0x38cb97('0x16')],_0x1320c9[_0x38cb97('0x14a')])){function _0x286d83(){var _0x95e156=_0x38cb97;_0x350dca[_0x95e156('0x6e')][_0xbb1400[_0x95e156('0x151')][_0x95e156('0x15d')]]=function(){var _0x2a280c=_0x95e156,_0x3ac0d3=function(){var _0x147f5c=_0x56f6;_0x137cb6[_0x147f5c('0x6e')][_0x2c363d[_0x147f5c('0x151')][_0x147f5c('0x15d')]]=!![],_0x1557b6[_0x147f5c('0x2ae')](),_0x2e41d5[_0x147f5c('0x256')](_0x1f3200,_0x42f111['Tests'][_0x147f5c('0x15d')],_0x3ac0d3);};_0x569361[_0x2a280c('0xeb')](_0x3a3dbc,_0x10c06c['Tests']['KEYUP'],_0x3ac0d3);};}}else _0x3a80e2[_0x38cb97('0x6e')][BotDetector['Tests']['DEVICE_ORIENTATION']]=!![],_0x3a80e2['update'](),_0x3a80e2[_0x38cb97('0x256')](window,BotDetector[_0x38cb97('0x151')][_0x38cb97('0x23f')],_0x214a70);};_0x3a80e2[_0x134209('0xeb')](window,BotDetector[_0x134209('0x151')][_0x134209('0x23f')]);}};else{function _0x182fa9(){var _0xf40e85=_0x3b3111;_0x9bca41[_0xf40e85('0x6e')][_0x467722[_0xf40e85('0x151')]['KEYUP']]=!![],_0xb39839[_0xf40e85('0x2ae')](),_0x5cb5d4['unbindEvent'](_0x51a4b1,_0x529e66[_0xf40e85('0x151')][_0xf40e85('0x15d')],_0x3debbc);}}}if(_0x1320c9[_0x3b3111('0x20a')](_0x4c3eb4['length'],0x0)||_0x1320c9[_0x3b3111('0x162')](_0x4c3eb4[_0x3b3111('0x57')](BotDetector['Tests'][_0x3b3111('0x2a9')]),-0x1)){if(_0x1320c9[_0x3b3111('0x24a')](_0x1320c9[_0x3b3111('0x145')],_0x1320c9[_0x3b3111('0x145')])){function _0x1d5523(){var _0x145107=_0x3b3111;if(_0x3d373c)_0x13cb97=this['aes'][_0x145107('0x239')](_0x372af7,_0x2d864a,_0x37d886),_0x48d579=![];else _0x2b03f3=this['aes']['encrypt'](_0x7f3fc9,_0x37c64c,_0x2faabb);for(var _0x51cdbc=0x0;_0x1320c9['SPpiB'](_0x51cdbc,0x10);_0x51cdbc++)_0x465869[_0x51cdbc]=_0x1320c9[_0x145107('0x296')](_0x48d4b3[_0x51cdbc],_0x488dc0[_0x51cdbc]);for(var _0x46db02=0x0;_0x1320c9[_0x145107('0x264')](_0x46db02,_0x1320c9['fvoXl'](_0x15c338,_0x1ba884));_0x46db02++)_0x18262d[_0x145107('0x3')](_0x11d54a[_0x46db02]);_0x5cc79f=_0x461420;}}else _0x3a80e2[_0x3b3111('0x6e')][BotDetector[_0x3b3111('0x151')]['DEVICE_ORIENTATION_MOZ']]=function(){var _0x1dba20=_0x3b3111,_0x75c9a4={'kjbpE':function(_0x3621b2,_0x380ce0){var _0x3084e9=_0x56f6;return _0x1320c9[_0x3084e9('0xa2')](_0x3621b2,_0x380ce0);},'bwFeJ':function(_0x4da431,_0x58ac12){return _0x1320c9['sQxBt'](_0x4da431,_0x58ac12);},'JUHRP':_0x1320c9['nmXCt']};if(_0x1320c9[_0x1dba20('0x7c')](_0x1320c9[_0x1dba20('0xfc')],_0x1320c9['Ulwpy'])){var _0x2fc815=function(){var _0x1f634f=_0x1dba20,_0x3525ea={'jYkJg':function(_0x34951e,_0x15c672){var _0x46317f=_0x56f6;return _0x75c9a4[_0x46317f('0x286')](_0x34951e,_0x15c672);}};if(_0x75c9a4[_0x1f634f('0x1b2')](_0x75c9a4[_0x1f634f('0x22e')],_0x75c9a4[_0x1f634f('0x22e')]))_0x3a80e2[_0x1f634f('0x6e')][BotDetector[_0x1f634f('0x151')][_0x1f634f('0x2a9')]]=!![],_0x3a80e2[_0x1f634f('0x2ae')](),_0x3a80e2[_0x1f634f('0x256')](window,BotDetector[_0x1f634f('0x151')][_0x1f634f('0x2a9')]);else{function _0x197c28(){var _0x566fea=_0x1f634f;if(_0x4866bd[_0x566fea('0x121')])_0x115bce[_0x566fea('0x121')](_0x42dcb9,_0x5ea468,![]);else _0x33dafe[_0x566fea('0x28a')]&&_0x5b5963[_0x566fea('0x28a')](_0x3525ea[_0x566fea('0x1b0')]('on',_0x317c0b),_0x575b41);}}};_0x3a80e2['bindEvent'](window,BotDetector[_0x1dba20('0x151')][_0x1dba20('0x2a9')]);}else{function _0x282952(){var _0x354ef4=_0x1dba20;_0xf7bbaa[_0x354ef4('0x6e')][_0x52ced9[_0x354ef4('0x151')]['DEVICE_ORIENTATION_MOZ']]=function(){var _0x43b553=_0x354ef4,_0x4a5f6d=function(){var _0x1e80c8=_0x56f6;_0x224672[_0x1e80c8('0x6e')][_0x3bf505[_0x1e80c8('0x151')][_0x1e80c8('0x2a9')]]=!![],_0x3649a9[_0x1e80c8('0x2ae')](),_0x2bb899[_0x1e80c8('0x256')](_0x45cb17,_0x2f0823[_0x1e80c8('0x151')]['DEVICE_ORIENTATION_MOZ']);};_0x339014['bindEvent'](_0x5b9715,_0x19fe12[_0x43b553('0x151')]['DEVICE_ORIENTATION_MOZ']);};}}};}_0x3a80e2['cases']={},_0x3a80e2[_0x3b3111('0x180')]=_0x11407c[_0x3b3111('0x180')]||0x3e8,_0x3a80e2[_0x3b3111('0x227')]=_0x11407c[_0x3b3111('0x227')]||null,_0x3a80e2['detected']=![];}BotDetector['Tests']={'KEYUP':_0x7b9909('0x54'),'MOUSE':_0x7b9909('0x294'),'SWIPE':_0x7b9909('0x24b'),'SWIPE_TOUCHSTART':_0x7b9909('0x269'),'SWIPE_TOUCHMOVE':'touchmove','SWIPE_TOUCHEND':_0x7b9909('0x42'),'SCROLL':_0x7b9909('0x31'),'GESTURE':_0x7b9909('0x28b'),'GYROSCOPE':'gyroscope','DEVICE_MOTION':_0x7b9909('0x19a'),'DEVICE_ORIENTATION':_0x7b9909('0x158'),'DEVICE_ORIENTATION_MOZ':_0x7b9909('0x15e')},BotDetector['prototype']['update']=function(_0x343e40){var _0x446ed3=_0x7b9909,_0x5ab0bf={'ghxxI':function(_0x32d19b,_0x1c99af){return _0x32d19b>_0x1c99af;},'pydjA':function(_0x3785ab,_0x3d5557){return _0x3785ab<_0x3d5557;},'goWBY':function(_0x41a4ce,_0x16213f){return _0x41a4ce+_0x16213f;},'MBjSd':function(_0x244979,_0x42dcdc){return _0x244979*_0x42dcdc;},'kbdys':function(_0x26c772,_0x1fdf53){return _0x26c772+_0x1fdf53;},'jPtrw':function(_0x4decd7,_0x599aa1){return _0x4decd7===_0x599aa1;},'hvQaK':'vOgWO','meXVj':function(_0x20f5c1,_0x5778ad){return _0x20f5c1!==_0x5778ad;},'PuGNk':_0x446ed3('0xc7'),'MfkLP':function(_0x40363c,_0x53c71f){return _0x40363c===_0x53c71f;},'FcgUR':function(_0x508fa0,_0x55893f){return _0x508fa0===_0x55893f;},'lLoAR':function(_0x480b9c,_0x5dcb8a){return _0x480b9c===_0x5dcb8a;},'VfLIW':'PXMKk','MQqwL':'Mkxfb','GsHTd':function(_0x86dd57,_0xbe2eac){return _0x86dd57==_0xbe2eac;},'OgCrF':function(_0x12c8da,_0x32134d){return _0x12c8da!==_0x32134d;},'rtXog':function(_0x2e05bb,_0x534883){return _0x2e05bb!==_0x534883;},'EhWdK':_0x446ed3('0x1b7'),'ANxts':_0x446ed3('0x2a4')},_0x44b8f1=this,_0x4a16ca=0x0,_0x5f44fb=0x0;for(var _0x23d3cc in _0x44b8f1[_0x446ed3('0x6e')]){if(_0x5ab0bf[_0x446ed3('0x285')](_0x5ab0bf[_0x446ed3('0x4c')],_0x5ab0bf['hvQaK'])){if(_0x44b8f1[_0x446ed3('0x6e')]['hasOwnProperty'](_0x23d3cc)){if(_0x5ab0bf[_0x446ed3('0x20b')](_0x5ab0bf['PuGNk'],_0x5ab0bf[_0x446ed3('0xbc')])){function _0xd26142(){var _0x16a5de=_0x446ed3;_0x5c2827=_0x375ec4&&(_0x5ab0bf[_0x16a5de('0x23e')](_0x4122fa,0.2)||_0x5ab0bf[_0x16a5de('0x23e')](_0x24426b,0.2));}}else{_0x44b8f1[_0x446ed3('0x147')][_0x23d3cc]=_0x5ab0bf[_0x446ed3('0x28c')](_0x44b8f1['tests'][_0x23d3cc],!![]);if(_0x5ab0bf[_0x446ed3('0x1c')](_0x44b8f1['cases'][_0x23d3cc],!![])){if(_0x5ab0bf['lLoAR'](_0x5ab0bf[_0x446ed3('0xe2')],_0x5ab0bf[_0x446ed3('0xf0')])){function _0x5b5474(){var _0x18f052=_0x446ed3,_0x1bf429=function(){var _0x316f30=_0x56f6;_0x58e775['tests'][_0x34da27['Tests'][_0x316f30('0xa1')]]=!![],_0x1c6598[_0x316f30('0x2ae')](),_0x29653d[_0x316f30('0x256')](_0x3eac46,_0x585a78[_0x316f30('0x151')][_0x316f30('0xa1')]);};_0x30f6f6[_0x18f052('0xeb')](_0x2ebe2d,_0x360a57[_0x18f052('0x151')]['SWIPE_TOUCHSTART']);}}else _0x4a16ca++;}}}_0x5f44fb++;}else{function _0x3204d2(){var _0x235afd=_0x446ed3,_0x55a66e=function(){var _0x5e1e82=_0x56f6;_0xfcbc54[_0x5e1e82('0x6e')][_0x497ad4['Tests'][_0x5e1e82('0x2a9')]]=!![],_0x56f63e[_0x5e1e82('0x2ae')](),_0x21e14f[_0x5e1e82('0x256')](_0x3ec133,_0x5e1e3d[_0x5e1e82('0x151')][_0x5e1e82('0x2a9')]);};_0x534a0a['bindEvent'](_0x2be480,_0x5491ca[_0x235afd('0x151')]['DEVICE_ORIENTATION_MOZ']);}}}_0x44b8f1[_0x446ed3('0x1d7')]=_0x5ab0bf[_0x446ed3('0x1e2')](_0x4a16ca,0x0),_0x44b8f1[_0x446ed3('0x13a')]=_0x5ab0bf[_0x446ed3('0x1e2')](_0x4a16ca,_0x5f44fb);if(_0x5ab0bf[_0x446ed3('0x3a')](_0x343e40,![])){if(_0x5ab0bf['rtXog'](_0x5ab0bf[_0x446ed3('0x144')],_0x5ab0bf[_0x446ed3('0x24c')]))_0x44b8f1['callback'](_0x44b8f1);else{function _0x546421(){var _0x3579c9=_0x446ed3;for(var _0x291deb=0x0;_0x5ab0bf['pydjA'](_0x291deb,0x4);_0x291deb++)_0x3b5e9e[_0x291deb]=_0x18d8bd[_0x5ab0bf[_0x3579c9('0x186')](_0x5ab0bf[_0x3579c9('0x192')](_0x291deb,0x4),_0x158dab)];_0x1c50d2=this['mixColumn'](_0x43e169,_0x30b2da);for(var _0x439dca=0x0;_0x5ab0bf[_0x3579c9('0xb6')](_0x439dca,0x4);_0x439dca++)_0x177f3d[_0x5ab0bf[_0x3579c9('0x28e')](_0x5ab0bf[_0x3579c9('0x192')](_0x439dca,0x4),_0x2b8346)]=_0x21b45f[_0x439dca];}}}},BotDetector[_0x7b9909('0x20e')]['bindEvent']=function(_0x13f3a6,_0x5d7801,_0x2ca930){var _0x2f4e2c=_0x7b9909,_0x2e6765={'BLuWH':function(_0x4d685f,_0x2ceca3){return _0x4d685f<_0x2ceca3;},'jZMUw':function(_0x5860b6,_0x2b7fe4){return _0x5860b6+_0x2b7fe4;},'YqHvL':function(_0x4cdebe,_0x4dcacf){return _0x4cdebe<_0x4dcacf;},'fjRQx':function(_0x3e978a,_0x5c0e28){return _0x3e978a^_0x5c0e28;},'mrNcT':function(_0x4ee9a3,_0x5d8a80){return _0x4ee9a3<_0x5d8a80;},'EMaRW':function(_0xfeec66,_0x2cd49c){return _0xfeec66===_0x2cd49c;},'ywCfp':_0x2f4e2c('0x17'),'APoDl':function(_0x1f4eb0,_0x248448){return _0x1f4eb0!==_0x248448;},'dcWky':'vuVWg','IcvZU':_0x2f4e2c('0x1fd'),'lOulc':function(_0x2d317b,_0x14b54f){return _0x2d317b+_0x14b54f;}};if(_0x13f3a6['addEventListener']){if(_0x2e6765[_0x2f4e2c('0x11f')](_0x2e6765[_0x2f4e2c('0x84')],_0x2e6765['ywCfp']))_0x13f3a6[_0x2f4e2c('0x121')](_0x5d7801,_0x2ca930,![]);else{function _0x552b1a(){var _0x2867a7=_0x2f4e2c,_0x4ffa58=_0x23ae47[0x0];for(var _0x2cd906=0x0;_0x2e6765[_0x2867a7('0x1fb')](_0x2cd906,0x3);_0x2cd906++)_0x45e008[_0x2cd906]=_0x282c78[_0x2e6765['jZMUw'](_0x2cd906,0x1)];return _0x152eff[0x3]=_0x4ffa58,_0x54fccc;}}}else{if(_0x13f3a6['attachEvent']){if(_0x2e6765[_0x2f4e2c('0x14c')](_0x2e6765['dcWky'],_0x2e6765[_0x2f4e2c('0x1f')]))_0x13f3a6[_0x2f4e2c('0x28a')](_0x2e6765[_0x2f4e2c('0x261')]('on',_0x5d7801),_0x2ca930);else{function _0x11588b(){var _0x38717e=_0x2f4e2c;for(var _0xab66a9=0x0;_0x2e6765[_0x38717e('0x1d4')](_0xab66a9,0x10);_0xab66a9++)_0x183204[_0xab66a9]=_0x2e6765[_0x38717e('0x243')](_0x487550[_0xab66a9],_0x2cac43?_0x185310[_0xab66a9]:_0x156f3d[_0xab66a9]);_0x1d6856=![],_0x3bd5e0=this[_0x38717e('0x21a')]['encrypt'](_0x3bf5f0,_0x4c63e2,_0x1431ca);for(var _0x304a3b=0x0;_0x2e6765[_0x38717e('0x1bb')](_0x304a3b,0x10);_0x304a3b++)_0xe213a9[_0x38717e('0x3')](_0x2abfb4[_0x304a3b]);}}}}},BotDetector[_0x7b9909('0x20e')][_0x7b9909('0x256')]=function(_0x31469b,_0x4288b6,_0xd6aa19){var _0x15e59e=_0x7b9909,_0x5520e2={'HozFY':_0x15e59e('0x178'),'ubgLk':function(_0x3e7954,_0x59a4bb){return _0x3e7954<_0x59a4bb;},'pEjin':function(_0x33ffd6,_0x5d8a6b){return _0x33ffd6+_0x5d8a6b;},'ujQPY':function(_0xbd48,_0xf24e0b){return _0xbd48-_0xf24e0b;},'FYnyS':function(_0x5c7640,_0x4a2aab){return _0x5c7640==_0x4a2aab;},'vWXqp':function(_0x5b22aa,_0xe68ef8){return _0x5b22aa%_0xe68ef8;},'VrlaA':function(_0x54747c,_0x37e29f){return _0x54747c==_0x37e29f;},'LbjYs':function(_0x278aa8,_0x8708b8){return _0x278aa8<_0x8708b8;},'Uxzac':function(_0x1e6a3e,_0x267cc3){return _0x1e6a3e^_0x267cc3;},'Kkzbu':function(_0x2d5d19,_0x32b0eb){return _0x2d5d19+_0x32b0eb;},'yGHtI':function(_0x318ba,_0x4f1c40){return _0x318ba>_0x4f1c40;},'jKrYD':function(_0x57ddea,_0x15c738){return _0x57ddea+_0x15c738;},'yszCg':function(_0x137eec,_0x3a40ea){return _0x137eec-_0x3a40ea;},'REczm':function(_0x3393e2,_0x4dc227){return _0x3393e2+_0x4dc227;},'jukbO':function(_0x20566b,_0x2cd430){return _0x20566b<_0x2cd430;},'jwdaQ':function(_0x1d2ea6,_0x723ddb){return _0x1d2ea6+_0x723ddb;},'nRQmJ':function(_0x382576,_0x1772b4){return _0x382576+_0x1772b4;},'VFHSj':function(_0x16b4d3,_0x2ba7f5){return _0x16b4d3!==_0x2ba7f5;},'fNgoo':_0x15e59e('0x82'),'oXWcs':_0x15e59e('0x4f'),'wzJLD':function(_0x4673e7,_0x199eff){return _0x4673e7!==_0x199eff;},'DarCx':_0x15e59e('0xaf'),'gjwhP':function(_0x154387,_0x1f1e11){return _0x154387!==_0x1f1e11;},'dSRfl':_0x15e59e('0xfb'),'YuUeo':function(_0x18878c,_0x1895ea){return _0x18878c===_0x1895ea;},'kGCtA':'undefined','ffkKh':function(_0x433c3b,_0x26694c){return _0x433c3b===_0x26694c;},'nJSdy':_0x15e59e('0x193')};if(_0x31469b['removeEventListener']){if(_0x5520e2[_0x15e59e('0x12f')](_0x5520e2[_0x15e59e('0x185')],_0x5520e2['oXWcs']))_0x31469b[_0x15e59e('0xa7')](_0x4288b6,_0xd6aa19,![]);else{function _0x290a2e(){var _0x19d7d0=_0x15e59e,_0x50c24b=_0x5520e2[_0x19d7d0('0x1d0')]['split']('|'),_0x309b09=0x0;while(!![]){switch(_0x50c24b[_0x309b09++]){case'0':return _0x41865b;case'1':_0x4f1e33=this[_0x19d7d0('0xed')](_0x1ef278,_0x1f7807);continue;case'2':_0x1ede7f=this[_0x19d7d0('0xf2')](_0x3f2261,!![]);continue;case'3':_0x10bcd6=this[_0x19d7d0('0x1e')](_0xdbead5,!![]);continue;case'4':_0x2f1fe5=this[_0x19d7d0('0x1ef')](_0x2a9c32,!![]);continue;}break;}}}}else{if(_0x5520e2['wzJLD'](_0x5520e2['DarCx'],_0x5520e2['DarCx'])){function _0x512f5f(){var _0x23539d=_0x15e59e;_0x53287f['tests'][_0x3902ad[_0x23539d('0x151')]['MOUSE']]=!![],_0x78a903[_0x23539d('0x2ae')](),_0x455850[_0x23539d('0x256')](_0x58c6c3,_0x659eea[_0x23539d('0x151')][_0x23539d('0x9a')],_0x13fc3e);}}else{var _0x5dd937=_0x5520e2['nRQmJ']('on',_0x4288b6);if(_0x31469b[_0x15e59e('0x2a')]){if(_0x5520e2['gjwhP'](_0x5520e2['dSRfl'],_0x5520e2[_0x15e59e('0x1ec')])){function _0x42d5f3(){var _0x530ff5=_0x15e59e;for(var _0x531ed9=0x0;_0x5520e2[_0x530ff5('0x1a')](_0x531ed9,0x4);_0x531ed9++)_0x277415[_0x531ed9]=_0x478352[_0x5520e2[_0x530ff5('0x247')](_0x5520e2['ujQPY'](_0x332aab,0x4),_0x531ed9)];if(_0x5520e2[_0x530ff5('0x199')](_0x5520e2[_0x530ff5('0x240')](_0x376098,_0x2eeec9),0x0))_0x5240d2=this['core'](_0xb84a8b,_0x43643f++);if(_0x5520e2[_0x530ff5('0x1d2')](_0x5ac0c5,this[_0x530ff5('0x137')][_0x530ff5('0x27e')])&&_0x5520e2[_0x530ff5('0x1d2')](_0x5520e2[_0x530ff5('0x240')](_0x5d6539,_0x4f90e8),0x10))for(var _0x2a6975=0x0;_0x5520e2[_0x530ff5('0xce')](_0x2a6975,0x4);_0x2a6975++)_0x5a53eb[_0x2a6975]=this[_0x530ff5('0x7b')][_0x45cc30[_0x2a6975]];for(var _0x3c340e=0x0;_0x5520e2[_0x530ff5('0xce')](_0x3c340e,0x4);_0x3c340e++){_0x400108[_0x573b3e]=_0x5520e2[_0x530ff5('0x104')](_0xd8b59a[_0x5520e2[_0x530ff5('0x1f1')](_0x3594f0,_0x40286d)],_0x1da029[_0x3c340e]),_0x247123++;}}}else{if(_0x5520e2[_0x15e59e('0x249')](typeof _0x31469b[_0x5dd937],_0x5520e2['kGCtA'])){if(_0x5520e2['ffkKh'](_0x5520e2[_0x15e59e('0x6a')],_0x5520e2[_0x15e59e('0x6a')]))_0x31469b[_0x4288b6]=null;else{function _0x2bf639(){var _0x420fe1=_0x15e59e;if(_0x24cbd){var _0x5126cd=_0x2a8c72[_0x5520e2[_0x420fe1('0x187')](_0x577787,0x3)];for(var _0x4bfc6c=0x3;_0x5520e2[_0x420fe1('0x1e4')](_0x4bfc6c,0x0);_0x4bfc6c--)_0x25a965[_0x5520e2['jKrYD'](_0x58a77d,_0x4bfc6c)]=_0x355b55[_0x5520e2[_0x420fe1('0x1b6')](_0x5520e2[_0x420fe1('0xd7')](_0x5e15eb,_0x4bfc6c),0x1)];_0x5e0a3c[_0x45dc8e]=_0x5126cd;}else{var _0x5126cd=_0x224b92[_0x31833f];for(var _0x4bfc6c=0x0;_0x5520e2[_0x420fe1('0x1b')](_0x4bfc6c,0x3);_0x4bfc6c++)_0x4b38da[_0x5520e2['REczm'](_0x4c484f,_0x4bfc6c)]=_0x17e55a[_0x5520e2[_0x420fe1('0xd7')](_0x5520e2[_0x420fe1('0x1ff')](_0xe679b,_0x4bfc6c),0x1)];_0x1467e0[_0x5520e2[_0x420fe1('0x1ed')](_0x5170e7,0x3)]=_0x5126cd;}}}}_0x31469b['detachEvent'](_0x5dd937);}}}}},BotDetector['prototype'][_0x7b9909('0x10d')]=function(){var _0x2cf015=_0x7b9909,_0x27effa={'mjjXK':_0x2cf015('0x2ad'),'IMrQU':function(_0x35eb00,_0x39c5fd){return _0x35eb00*_0x39c5fd;},'OtLcx':function(_0x4d20e4,_0x1add9f){return _0x4d20e4<_0x1add9f;},'WlXgs':function(_0x136810,_0x852af4){return _0x136810===_0x852af4;},'ZwlAO':_0x2cf015('0xaa'),'INjiI':_0x2cf015('0x263'),'FCpTi':function(_0x334fca,_0x209d38){return _0x334fca!==_0x209d38;},'nfbPq':_0x2cf015('0x1dd'),'xMuMH':'VsaUm','pJBMh':function(_0x261ca6,_0x28ff4b){return _0x261ca6===_0x28ff4b;},'CqNbT':_0x2cf015('0x69'),'jYtBc':_0x2cf015('0xb7'),'EXbVa':function(_0x24bf02,_0x411aee,_0x618326){return _0x24bf02(_0x411aee,_0x618326);}},_0x23a251=this;for(var _0x5d3e2d in this['tests']){if(_0x27effa[_0x2cf015('0x5')](_0x27effa['nfbPq'],_0x27effa[_0x2cf015('0xd0')])){if(this[_0x2cf015('0x6e')][_0x2cf015('0x1df')](_0x5d3e2d)){if(_0x27effa[_0x2cf015('0x139')](_0x27effa[_0x2cf015('0x295')],_0x27effa[_0x2cf015('0x29d')])){function _0x4158a5(){var _0x120e40=_0x2cf015;_0x49044d['tests'][_0x3c3c22['Tests'][_0x120e40('0xa1')]]=!![],_0xd2b567['update'](),_0x1f9b83['unbindEvent'](_0xc470cd,_0x530bb2[_0x120e40('0x151')][_0x120e40('0xa1')]);}}else this[_0x2cf015('0x6e')][_0x5d3e2d][_0x2cf015('0x134')]();}}else{function _0x101c2e(){_0x787bd9++;}}}this[_0x2cf015('0x2ae')](![]),_0x27effa[_0x2cf015('0x1de')](setTimeout,function(){var _0x1100fe=_0x2cf015;if(_0x27effa[_0x1100fe('0x25a')](_0x27effa[_0x1100fe('0x246')],_0x27effa['INjiI'])){function _0x134145(){var _0x307c99=_0x1100fe,_0x3e875e=_0x27effa['mjjXK']['split']('|'),_0x351a8d=0x0;while(!![]){switch(_0x3e875e[_0x351a8d++]){case'0':_0x2c76da=this[_0x307c99('0x1e')](_0xf9ba48,![]);continue;case'1':_0x1e514c=this[_0x307c99('0x1ef')](_0x40fc96,![]);continue;case'2':_0x3c1d35=this['addRoundKey'](_0xe6e887,this[_0x307c99('0x89')](_0x2f1b3e,_0x27effa['IMrQU'](0x10,_0x2a5385)));continue;case'3':return _0x3ef415;case'4':_0x3960d9=this[_0x307c99('0xed')](_0x159ba4,this[_0x307c99('0x89')](_0x2a619a,0x0));continue;case'5':for(var _0x33f02b=0x1;_0x27effa['OtLcx'](_0x33f02b,_0x1fb43f);_0x33f02b++)_0xf8b738=this['round'](_0x2d070e,this['createRoundKey'](_0x55d380,_0x27effa[_0x307c99('0x12c')](0x10,_0x33f02b)));continue;}break;}}}else _0x23a251['update'](!![]);},_0x23a251[_0x2cf015('0x180')]);}; \ No newline at end of file diff --git a/html/production/sweet-alert.css b/html/production/sweet-alert.css new file mode 100644 index 0000000..5c501b4 --- /dev/null +++ b/html/production/sweet-alert.css @@ -0,0 +1 @@ +.sweet-overlay{background-color:#000;-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=40)";background-color:rgba(0,0,0,.4);position:fixed;left:0;right:0;top:0;bottom:0;display:none;z-index:10000}.sweet-alert{background-color:#fff;font-family:'Open Sans','Helvetica Neue',Helvetica,Arial,sans-serif;width:478px;padding:17px;border-radius:5px;text-align:center;position:fixed;left:50%;top:50%;margin-left:-256px;margin-top:-200px;overflow:hidden;display:none;z-index:99999}@media all and (max-width:540px){.sweet-alert{width:auto;margin-left:0;margin-right:0;left:15px;right:15px}}.sweet-alert h2{color:#575757;font-size:30px;text-align:center;font-weight:600;text-transform:none;position:relative;margin:25px 0;padding:0;line-height:40px;display:block}.sweet-alert p{color:#797979;font-size:16px;font-weight:300;position:relative;text-align:inherit;float:none;margin:0;padding:0;line-height:normal}.sweet-alert button{background-color:#AEDEF4;color:#fff;border:none;box-shadow:none;font-size:17px;font-weight:500;-webkit-border-radius:4px;border-radius:5px;padding:10px 32px;margin:26px 5px 0;cursor:pointer}.sweet-alert button:focus{outline:0;box-shadow:0 0 2px rgba(128,179,235,.5),inset 0 0 0 1px rgba(0,0,0,.05)}.sweet-alert button:hover{background-color:#a1d9f2}.sweet-alert button:active{background-color:#81ccee}.sweet-alert button.cancel{background-color:#D0D0D0}.sweet-alert button.cancel:hover{background-color:#c8c8c8}.sweet-alert button.cancel:active{background-color:#b6b6b6}.sweet-alert button.cancel:focus{box-shadow:rgba(197,205,211,.8) 0 0 2px,rgba(0,0,0,.0470588) 0 0 0 1px inset!important}.sweet-alert button::-moz-focus-inner{border:0}.sweet-alert[data-has-cancel-button=false] button{box-shadow:none!important}.sweet-alert[data-has-confirm-button=false][data-has-cancel-button=false]{padding-bottom:40px}.sweet-alert .sa-icon{width:80px;height:80px;border:4px solid gray;-webkit-border-radius:40px;border-radius:50%;margin:20px auto;padding:0;position:relative;box-sizing:content-box}.sweet-alert .sa-icon.sa-error{border-color:#F27474}.sweet-alert .sa-icon.sa-error .sa-x-mark{position:relative;display:block}.sweet-alert .sa-icon.sa-error .sa-line{position:absolute;height:5px;width:47px;background-color:#F27474;display:block;top:37px;border-radius:2px}.sweet-alert .sa-icon.sa-error .sa-line.sa-left{-webkit-transform:rotate(45deg);transform:rotate(45deg);left:17px}.sweet-alert .sa-icon.sa-error .sa-line.sa-right{-webkit-transform:rotate(-45deg);transform:rotate(-45deg);right:16px}.sweet-alert .sa-icon.sa-warning{border-color:#F8BB86}.sweet-alert .sa-icon.sa-warning .sa-body{position:absolute;width:5px;height:47px;left:50%;top:10px;-webkit-border-radius:2px;border-radius:2px;margin-left:-2px;background-color:#F8BB86}.sweet-alert .sa-icon.sa-warning .sa-dot{position:absolute;width:7px;height:7px;-webkit-border-radius:50%;border-radius:50%;margin-left:-3px;left:50%;bottom:10px;background-color:#F8BB86}.sweet-alert .sa-icon.sa-info{border-color:#C9DAE1}.sweet-alert .sa-icon.sa-info::before{content:"";position:absolute;width:5px;height:29px;left:50%;bottom:17px;border-radius:2px;margin-left:-2px;background-color:#C9DAE1}.sweet-alert .sa-icon.sa-info::after{content:"";position:absolute;width:7px;height:7px;border-radius:50%;margin-left:-3px;top:19px;background-color:#C9DAE1}.sweet-alert .sa-icon.sa-success{border-color:#A5DC86}.sweet-alert .sa-icon.sa-success::after,.sweet-alert .sa-icon.sa-success::before{content:'';position:absolute;width:60px;height:120px;background:#fff;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-icon.sa-success::before{-webkit-border-radius:120px 0 0 120px;border-radius:120px 0 0 120px;top:-7px;left:-33px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:60px 60px;transform-origin:60px 60px}.sweet-alert .sa-icon.sa-success::after{-webkit-border-radius:0 120px 120px 0;border-radius:0 120px 120px 0;top:-11px;left:30px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transform-origin:0 60px;transform-origin:0 60px}.sweet-alert .sa-icon.sa-success .sa-placeholder{width:80px;height:80px;border:4px solid rgba(165,220,134,.2);-webkit-border-radius:40px;border-radius:50%;box-sizing:content-box;position:absolute;left:-4px;top:-4px;z-index:2}.sweet-alert .sa-icon.sa-success .sa-fix{width:5px;height:90px;background-color:#fff;position:absolute;left:28px;top:8px;z-index:1;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-icon.sa-success .sa-line{height:5px;background-color:#A5DC86;display:block;border-radius:2px;position:absolute;z-index:2}.sweet-alert .sa-icon.sa-success .sa-line.sa-tip{width:25px;left:14px;top:46px;-webkit-transform:rotate(45deg);transform:rotate(45deg)}.sweet-alert .sa-icon.sa-success .sa-line.sa-long{width:47px;right:8px;top:38px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.sweet-alert .sa-icon.sa-custom{background-size:contain;border-radius:0;border:none;background-position:center center;background-repeat:no-repeat}@-webkit-keyframes showSweetAlert{0%{transform:scale(.7);-webkit-transform:scale(.7)}45%{transform:scale(1.05);-webkit-transform:scale(1.05)}80%{transform:scale(.95);-webkit-tranform:scale(.95)}100%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes showSweetAlert{0%{transform:scale(.7);-webkit-transform:scale(.7)}45%{transform:scale(1.05);-webkit-transform:scale(1.05)}80%{transform:scale(.95);-webkit-tranform:scale(.95)}100%{transform:scale(1);-webkit-transform:scale(1)}}@-webkit-keyframes hideSweetAlert{0%{transform:scale(1);-webkit-transform:scale(1)}100%{transform:scale(.5);-webkit-transform:scale(.5)}}@keyframes hideSweetAlert{0%{transform:scale(1);-webkit-transform:scale(1)}100%{transform:scale(.5);-webkit-transform:scale(.5)}}.showSweetAlert{-webkit-animation:showSweetAlert .3s;animation:showSweetAlert .3s}.showSweetAlert[data-animation=none]{-webkit-animation:none;animation:none}.hideSweetAlert{-webkit-animation:hideSweetAlert .2s;animation:hideSweetAlert .2s}.hideSweetAlert[data-animation=none]{-webkit-animation:none;animation:none}@-webkit-keyframes animateSuccessTip{0%,54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}100%{width:25px;left:14px;top:45px}}@keyframes animateSuccessTip{0%,54%{width:0;left:1px;top:19px}70%{width:50px;left:-8px;top:37px}84%{width:17px;left:21px;top:48px}100%{width:25px;left:14px;top:45px}}@-webkit-keyframes animateSuccessLong{0%,65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}100%{width:47px;right:8px;top:38px}}@keyframes animateSuccessLong{0%,65%{width:0;right:46px;top:54px}84%{width:55px;right:0;top:35px}100%{width:47px;right:8px;top:38px}}@-webkit-keyframes rotatePlaceholder{0%,5%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}100%,12%{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}}@keyframes rotatePlaceholder{0%,5%{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}100%,12%{transform:rotate(-405deg);-webkit-transform:rotate(-405deg)}}.animateSuccessTip{-webkit-animation:animateSuccessTip .75s;animation:animateSuccessTip .75s}.animateSuccessLong{-webkit-animation:animateSuccessLong .75s;animation:animateSuccessLong .75s}.sa-icon.sa-success.animate::after{-webkit-animation:rotatePlaceholder 4.25s ease-in;animation:rotatePlaceholder 4.25s ease-in}@-webkit-keyframes animateErrorIcon{0%{transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1}}@keyframes animateErrorIcon{0%{transform:rotateX(100deg);-webkit-transform:rotateX(100deg);opacity:0}100%{transform:rotateX(0deg);-webkit-transform:rotateX(0deg);opacity:1}}.animateErrorIcon{-webkit-animation:animateErrorIcon .5s;animation:animateErrorIcon .5s}@-webkit-keyframes animateXMark{0%,50%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}80%{transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px}100%{transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1}}@keyframes animateXMark{0%,50%{transform:scale(.4);-webkit-transform:scale(.4);margin-top:26px;opacity:0}80%{transform:scale(1.15);-webkit-transform:scale(1.15);margin-top:-6px}100%{transform:scale(1);-webkit-transform:scale(1);margin-top:0;opacity:1}}.animateXMark{-webkit-animation:animateXMark .5s;animation:animateXMark .5s}@-webkit-keyframes pulseWarning{0%{border-color:#F8D486}100%{border-color:#F8BB86}}@keyframes pulseWarning{0%{border-color:#F8D486}100%{border-color:#F8BB86}}.pulseWarning{-webkit-animation:pulseWarning .75s infinite alternate;animation:pulseWarning .75s infinite alternate}@-webkit-keyframes pulseWarningIns{0%{background-color:#F8D486}100%{background-color:#F8BB86}}@keyframes pulseWarningIns{0%{background-color:#F8D486}100%{background-color:#F8BB86}}.pulseWarningIns{-webkit-animation:pulseWarningIns .75s infinite alternate;animation:pulseWarningIns .75s infinite alternate} \ No newline at end of file diff --git a/html/production/sweet-alert.min.js b/html/production/sweet-alert.min.js new file mode 100644 index 0000000..4e2c804 --- /dev/null +++ b/html/production/sweet-alert.min.js @@ -0,0 +1 @@ +!function(e,t,n){function o(e){var t=x(),n=t.querySelector("h2"),o=t.querySelector("p"),a=t.querySelector("button.cancel"),r=t.querySelector("button.confirm");if(n.innerHTML=e.html?e.title:E(e.title).split("\n").join("
"),o.innerHTML=e.html?e.text:E(e.text||"").split("\n").join("
"),e.text&&A(o),e.customClass)T(t,e.customClass),t.setAttribute("data-custom-class",e.customClass);else{var s=t.getAttribute("data-custom-class");B(t,s),t.setAttribute("data-custom-class","")}if(O(t.querySelectorAll(".sa-icon")),e.type&&!u()){for(var c=!1,l=0;lo;o++)n=parseInt(e.substr(2*o,2),16),n=Math.round(Math.min(Math.max(0,n+n*t),255)).toString(16),a+=("00"+n).substr(n.length);return a}function r(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e}function s(e){var t=/^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(e);return t?parseInt(t[1],16)+", "+parseInt(t[2],16)+", "+parseInt(t[3],16):null}function i(e,t){var n=s(t);e.style.boxShadow="0 0 2px rgba("+n+", 0.8), inset 0 0 0 1px rgba(0, 0, 0, 0.05)"}function c(){var e=x();H(k(),10),A(e),T(e,"showSweetAlert"),B(e,"hideSweetAlert"),d=t.activeElement;var n=e.querySelector("button.confirm");n.focus(),setTimeout(function(){T(e,"visible")},500);var o=e.getAttribute("data-timer");"null"!==o&&""!==o&&(e.timeout=setTimeout(function(){v.close()},o))}function l(){var e=x();e.style.marginTop=D(x())}function u(){return e.attachEvent&&!e.addEventListener?!0:!1}function f(t){e.console&&e.console.log("SweetAlert: "+t)}var d,m,p,y,v,b,g=".sweet-alert",w=".sweet-overlay",h=["error","warning","info","success"],S={title:"",text:"",type:null,allowOutsideClick:!1,showConfirmButton:!0,showCancelButton:!1,closeOnConfirm:!0,closeOnCancel:!0,confirmButtonText:"OK",confirmButtonColor:"#AEDEF4",cancelButtonText:"Cancel",imageUrl:null,imageSize:null,timer:null,customClass:"",html:!1,animation:!0,allowEscapeKey:!0},x=function(){var e=t.querySelector(g);return e||(j(),e=x()),e},k=function(){return t.querySelector(w)},C=function(e,t){return new RegExp(" "+t+" ").test(" "+e.className+" ")},T=function(e,t){C(e,t)||(e.className+=" "+t)},B=function(e,t){var n=" "+e.className.replace(/[\t\r\n]/g," ")+" ";if(C(e,t)){for(;n.indexOf(" "+t+" ")>=0;)n=n.replace(" "+t+" "," ");e.className=n.replace(/^\s+|\s+$/g,"")}},E=function(e){var n=t.createElement("div");return n.appendChild(t.createTextNode(e)),n.innerHTML},q=function(e){e.style.opacity="",e.style.display="block"},A=function(e){if(e&&!e.length)return q(e);for(var t=0;t0?setTimeout(o,t):e.style.display="none"};o()},N=function(n){if("function"==typeof MouseEvent){var o=new MouseEvent("click",{view:e,bubbles:!1,cancelable:!0});n.dispatchEvent(o)}else if(t.createEvent){var a=t.createEvent("MouseEvents");a.initEvent("click",!1,!1),n.dispatchEvent(a)}else t.createEventObject?n.fireEvent("onclick"):"function"==typeof n.onclick&&n.onclick()},P=function(t){"function"==typeof t.stopPropagation?(t.stopPropagation(),t.preventDefault()):e.event&&e.event.hasOwnProperty("cancelBubble")&&(e.event.cancelBubble=!0)},j=function(){var e='

Title

Text

',n=t.createElement("div");for(n.innerHTML=e;n.firstChild;)t.body.appendChild(n.firstChild)};v=b=function(){function s(e){var t=b;return"undefined"!=typeof t[e]?t[e]:S[e]}function u(t){var o=t||e.event,a=o.keyCode||o.which;if(-1!==[9,13,32,27].indexOf(a)){for(var r=o.target||o.srcElement,s=-1,c=0;ck;k++){var T=w[k];g[T]=s(T)}g.confirmButtonText=g.showCancelButton?"Confirm":S.confirmButtonText,g.confirmButtonText=s("confirmButtonText"),g.doneFunction=arguments[1]||null;break;default:return f('Unexpected type of argument! Expected "string" or "object", got '+typeof arguments[0]),!1}o(g),l(),c();for(var B=x(),E=function(t){var n=t||e.event,o=n.target||n.srcElement,r=-1!==o.className.indexOf("confirm"),s=C(B,"visible"),i=g.doneFunction&&"true"===B.getAttribute("data-has-done-function");switch(n.type){case"mouseover":r&&(o.style.backgroundColor=a(g.confirmButtonColor,-.04));break;case"mouseout":r&&(o.style.backgroundColor=g.confirmButtonColor);break;case"mousedown":r&&(o.style.backgroundColor=a(g.confirmButtonColor,-.14));break;case"mouseup":r&&(o.style.backgroundColor=a(g.confirmButtonColor,-.04));break;case"focus":var c=B.querySelector("button.confirm"),l=B.querySelector("button.cancel");r?l.style.boxShadow="none":c.style.boxShadow="none";break;case"click":if(r&&i&&s)g.doneFunction(!0),g.closeOnConfirm&&v.close();else if(i&&s){var u=String(g.doneFunction).replace(/\s/g,""),f="function("===u.substring(0,9)&&")"!==u.substring(9,10);f&&g.doneFunction(!1),g.closeOnCancel&&v.close()}else v.close()}},q=B.querySelectorAll("button"),A=0;A < + |_____|_| \___/|_| |_|_| \___/_/\_\ + + By: Innovera Technology + https://innovera.ir + CodeName: + The Desert Fox (0.1.0) + " + + +#define variables +SERVER_IP="0.0.0.0" +IRON_FOX_ROOT=$PWD +NGINX_PATH=$IRON_FOX_ROOT/nginx-1.19.2 +MODULES_PATH=$IRON_FOX_ROOT/modules +SETUP_DEPENDENCY_SREGEX_PATH=$IRON_FOX_ROOT/lib/sregex +SETUP_PATH=/home/ironfox/iron +BIN_PATH=/home/ironfox/iron/sbin + + +MODE_DEBUG='--with-debug' +HAVE_DEBUG="no" + +for arg in $*; do + if [ $arg = $MODE_DEBUG ]; then + NGX_ARGS=$MODE_DEBUG + HAVE_DEBUG="yes" + break + else + HAVE_DEBUG="no" + unset NGX_ARGS + fi +done +if [ $HAVE_DEBUG = "yes" ]; then + echo "Start setup, debug enabled..." +else + echo "Start setup..." +fi +if [[ $(id -u) -ne 0 ]]; then + clear + echo " +[IronFox Setup] +Version 0.0.5 +CodeName: The Desert Fox + + setup params: + --with-debug Setup with debug enabled mode. + +_____________________________________________________________ +Note: installer MUST be run with root privilege + " + exit 1 +fi + +echo "update system" +sudo apt update + + +#fix https://github.com/khaleghsalehi/ironfox/issues/1 +sudo mkdir /home/ironfox +sudo chmod 755 -R /home/ironfox + +echo "shutdown service and clean up path..." +sudo rm -R $SETUP_PATH +sudo rm -R nginx-1.19.2 +tar xfv nginx-1.19.2.tar.gz +sudo systemctl stop innovera +sudo kill 9 $(ps -aux | grep nginx | awk '{print $2}') + +#build embedded file +echo "#!/bin/bash +sudo java -jar $SETUP_PATH/sbin/panel.jar --spring.config.location=$SETUP_PATH/sbin/application.properties +" >manager/runservice.sh + +echo "[Unit] +Description=IronFox panel service +[Service] +User=root +# The configuration file application.properties should be here: +#change this to your workspace +WorkingDirectory=$BIN_PATH +#path to executable. +#executable is a bash script which calls jar file +ExecStart=$BIN_PATH/runservice.sh +SuccessExitStatus=143 +TimeoutStopSec=10 +Restart=on-failure +RestartSec=5 +[Install] +WantedBy=multi-user.target +" >manager/innovera.service + +echo "check and setup dependencies..." +sudo apt install build-essential +sudo apt install redis +sudo apt install libpcre3-dev +sudo apt install libhiredis-dev +sudo apt install libssl-dev +sudo apt install zlib1g-dev +sudo apt install openjdk-8-jdk + +#echo "installing PostgreSql..." +#sudo apt update +#sudo apt install vim bash-completion wget +#wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - +#echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee /etc/apt/sources.list.d/pgdg.list +#sudo apt update +#sudo apt install postgresql-12 postgresql-client-12 +#todo add postgresql account and db with all-in-one sql file + +cd $SETUP_DEPENDENCY_SREGEX_PATH +make +sudo make install +cd $IRON_FOX_ROOT + + + + +echo "compiling source..." +sudo mkdir $SETUP_PATH +sudo mkdir $SETUP_PATH/sbin/ +sudo mkdir $SETUP_PATH/cert/ +sudo mkdir $SETUP_PATH/html/ + +echo "apply nginx patch..." +patch -p0 <$IRON_FOX_ROOT/nginx.patch + +cd $NGINX_PATH +./configure $NGX_ARGS --prefix=$SETUP_PATH --with-ld-opt='-Wl,-rpath,/usr/local/lib' \ + --sbin-path=$SETUP_PATH/sbin/ \ + --with-http_sub_module \ + --with-http_ssl_module \ + --with-compat \ + --add-dynamic-module=${MODULES_PATH}/ngx_http_bot_protection_module \ + --add-dynamic-module=${MODULES_PATH}/replace-filter-nginx-module + #--add-dynamic-module=${MODULES_PATH}/ngx_http_header_inspect \ + +make +make install + +cd $IRON_FOX_ROOT +echo "copy files..." +cp -vv html/production/* $SETUP_PATH/html/ +cp -vv manager/panel.jar $BIN_PATH +cp -vv manager/application.properties $BIN_PATH + +cp -vv cert/* $SETUP_PATH/cert/ +sudo chmod +x -R $SETUP_PATH/html/* + +echo "service configuration..." +sudo cp -vv manager/innovera.service /etc/systemd/system/innovera.service +sudo cp -vv manager/runservice.sh $BIN_PATH +sudo chmod u+x $BIN_PATH/runservice.sh +# figure and start service +sudo systemctl daemon-reload +sudo systemctl enable innovera.service +sudo systemctl start innovera + + +echo "setup postgresql..." +sudo apt update +sudo apt -y install vim bash-completion wget +sudo wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add - +echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee /etc/apt/sources.list.d/pgdg.list +sudo apt update +sudo apt -y install postgresql-12 postgresql-client-12 + +echo "==========================================" +echo "please flow up below command:" +echo "please create a user and set password for it by:" +echo "bash 1- sudo su - postgres" +echo "psql 2- createuser --interactive --pwprompt" +echo "psql 3- create databses ironfox;" +echo "bash 4- sudo systemctl start innovera" +echo "setup done." diff --git a/ironfox.png b/ironfox.png new file mode 100644 index 0000000..813957f Binary files /dev/null and b/ironfox.png differ diff --git a/lib/sregex/LICENSE b/lib/sregex/LICENSE new file mode 100644 index 0000000..d289c49 --- /dev/null +++ b/lib/sregex/LICENSE @@ -0,0 +1,33 @@ +Part of this code is from the NGINX opensource project: http://nginx.org/LICENSE + +This library is licensed under the BSD license. + +Copyright (c) 2012-2014 Yichun "agentzh" Zhang. + +Copyright (c) 2007-2009 Russ Cox, Google Inc. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google, Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/lib/sregex/Makefile b/lib/sregex/Makefile new file mode 100644 index 0000000..ae9ff58 --- /dev/null +++ b/lib/sregex/Makefile @@ -0,0 +1,198 @@ +# Copyright (C) 2013 Yichun Zhang (agentzh) +# Copyright (C) 2005-2012 Mike Pall. + +MAJVER= 0 +MINVER= 0 +RELVER= 1 +VERSION= $(MAJVER).$(MINVER).$(RELVER) + +FILE_T= sregex-cli +FILE_A= libsregex.a +FILE_SO= libsregex.so + +CC= gcc +CFLAGS+= -fpic -g -Wall -O3 -Isrc -I. +PREFIX= /usr/local +DESTDIR= +INSTALL_X= install -m 0755 +INSTALL_F= install -m 0644 +MKDIR= mkdir -p +RMDIR= rmdir 2>/dev/null +UNINSTALL= $(HOST_RM) +HOST_RM= rm -f +LDCONFIG= ldconfig -n +SYMLINK= ln -sf +LUA= luajit +DASM= $(LUA) dynasm/dynasm.lua +DASM_FLAGS= + +INSTALL_INC= $(DESTDIR)$(PREFIX)/include/sregex +INSTALL_LIB= $(DESTDIR)$(PREFIX)/lib +INSTALL_BIN= $(DESTDIR)$(PREFIX)/bin + +INSTALL_ANAME= libsregex.a +INSTALL_SONAME= libsregex.so.$(MAJVER).$(MINVER).$(RELVER) +INSTALL_SOSHORT1= libsregex.so +INSTALL_SOSHORT2= libsregex.so.$(MAJVER) + +ifeq (Darwin,$(shell uname -s)) + INSTALL_SONAME= libsregex.$(MAJVER).$(MINVER).$(RELVER).dylib + INSTALL_SOSHORT1= libsregex.dylib + INSTALL_SOSHORT2= libsregex.$(MAJVER).dylib +endif + +INSTALL_T= $(INSTALL_BIN)/$(FILE_T) + +INSTALL_STATIC= $(INSTALL_LIB)/$(INSTALL_ANAME) +INSTALL_DYN= $(INSTALL_LIB)/$(INSTALL_SONAME) +INSTALL_SHORT1= $(INSTALL_LIB)/$(INSTALL_SOSHORT1) +INSTALL_SHORT2= $(INSTALL_LIB)/$(INSTALL_SOSHORT2) + +INSTALL_DIRS= $(INSTALL_INC) $(INSTALL_LIB) $(INSTALL_BIN) + +TARGET_SONAME= libsregex.so.$(MAJVER) + +ifeq (Darwin,$(shell uname -s)) + TARGET_SONAME= libsregex.$(MAJVER).dylib + LDCONFIG= : +else + ifeq (SunOS,$(shell uname -s)) + INSTALL_X=cp -p + INSTALL_F=cp -p + endif +endif + +TARGET_DYLIBPATH= $(PREFIX)/lib/$(TARGET_SONAME) +TARGET_XSHLDFLAGS= -shared -fpic -Wl,-soname,$(TARGET_SONAME) +TARGET_AR=ar rcus +HOST_SYS:= $(shell uname -s) + +ifeq (Darwin,$(HOST_SYS)) + FILE_SO= libsregex.dylib + TARGET_XSHLDFLAGS= -dynamiclib -single_module -undefined dynamic_lookup -fpic + TARGET_XSHLDFLAGS+= -install_name $(TARGET_DYLIBPATH) -compatibility_version $(MAJVER).$(MINVER) -current_version $(MAJVER).$(MINVER).$(RELVER) +endif + +jobs= 1 + +ifeq ($(use_valgrind), 1) + CFLAGS += -DSRE_USE_VALGRIND=1 +endif + +Q= @ +E= @echo + +pwd = $(shell pwd) + +lib_c_files= \ + src/sregex/sre_palloc.c \ + src/sregex/sre_regex.c \ + src/sregex/sre_yyparser.c \ + src/sregex/sre_regex_compiler.c \ + src/sregex/sre_vm_bytecode.c \ + src/sregex/sre_vm_thompson.c \ + src/sregex/sre_vm_pike.c \ + src/sregex/sre_capture.c \ + src/sregex/sre_vm_thompson_jit.c + +lib_o_files= $(patsubst %.c,%.o,$(lib_c_files)) + +h_files= src/sregex/sre_capture.h \ + src/sregex/sre_palloc.h \ + src/sregex/sre_vm_bytecode.h \ + src/sregex/sre_yyparser.h \ + src/sregex/sre_core.h \ + src/sregex/sre_regex.h \ + src/sregex/sre_vm_thompson_x64.h \ + src/sregex/sre_vm_thompson.h \ + src/sregex/sregex.h \ + src/sregex/ddebug.h \ + +plist_vfiles= $(patsubst src/sregex/%.c,%.plist,$(lib_c_files)) + +INSTALL_H_FILES= src/sregex/sregex.h src/sregex/ddebug.h + +.PHONY: all clean distclean test val install uninstall +.PRECIOUS: \ + src/sregex/sre_yyparser.c \ + src/sregex/sre_yyparser.h \ + src/sregex/sre_vm_thompson_x64.h + +all: $(FILE_SO) $(FILE_A) $(FILE_T) + +$(FILE_T): src/sre_cli.o $(lib_o_files) + $(E) "LINK $@" + $(Q)$(CC) -o $@ $+ + +$(FILE_SO): $(lib_o_files) + $(E) "DYNLINK $@" + $(Q)$(CC) $(TARGET_XSHLDFLAGS) -o $@ $+ + $(E) "SYMLINK $(INSTALL_SOSHORT2)" + $(Q)$(SYMLINK) $@ $(INSTALL_SOSHORT2) + +$(FILE_A): $(lib_o_files) + $(E) "AR $@" + $(Q)$(TARGET_AR) $@ $(lib_o_files) + +%.o: %.c $(h_files) + $(E) "CC $@" + $(Q)$(CC) $(CFLAGS) -c -o $@ $< + +%.c %.h: %.y + $(E) "BISON $@" + $(Q)bison -p sregex_yy -v $< + $(Q)./util/fix-bison-comments + +%.h: %.dasc + $(E) "DYNASM $@" + $(Q)$(DASM) $(DASM_FLAGS) -o $@ $< + +clean: + $(HOST_RM) *.dylib *.so *.so.* src/*.o $(lib_o_files) core $(TARGET) \ + src/sregex/*.output \ + $(FILE_T) $(FILE_SO) $(FILE_A) + +distclean: clean + $(HOST_RM) src/sregex/sre_yyparser.[ch] + +test: all + prove -j$(jobs) -r t + +val: + $(MAKE) use_valgrind=1 all -B -j$(jobs) + +valtest: val + TEST_SREGEX_USE_VALGRIND=1 prove -j$(jobs) -r t + $(MAKE) -B -j$(jobs) + +clang: $(plist_vfiles) + +%.plist: src/sregex/%.c $(h_files) + @echo $< + -@clang -O --analyze -Wextra -Wall -Werror -Isrc -I. $< + +install: all + @echo "==== Installing sregex $(VERSION) to $(PREFIX) ====" + $(MKDIR) $(INSTALL_DIRS) + $(INSTALL_X) $(FILE_T) $(INSTALL_T) + $(INSTALL_F) $(INSTALL_H_FILES) $(INSTALL_INC) + $(INSTALL_X) $(FILE_SO) $(INSTALL_DYN) + -$(LDCONFIG) $(INSTALL_LIB) + $(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT1) + -$(SYMLINK) $(INSTALL_SONAME) $(INSTALL_SHORT2) + @echo "==== Successfully installed sregex $(VERSION) to $(PREFIX) ====" + +uninstall: + @echo "==== Uninstalling sregex $(VERSION) to $(PREFIX) ====" + $(UNINSTALL) $(INSTALL_T) + $(UNINSTALL) $(INSTALL_LIB)/$(FILE_SO) + $(UNINSTALL) $(INSTALL_LIB)/libsregex.a + $(UNINSTALL) $(INSTALL_SHORT1) + $(UNINSTALL) $(INSTALL_SHORT2) + + for file in $(patsubst src/sregex/%,%,$(INSTALL_H_FILES)); do \ + $(UNINSTALL) $(INSTALL_INC)/$$file; \ + done + $(RMDIR) $(INSTALL_INC) + @echo "==== Successfully uninstalled sregex $(VERSION) from $(PREFIX) ====" + diff --git a/lib/sregex/README.markdown b/lib/sregex/README.markdown new file mode 100644 index 0000000..0b4d754 --- /dev/null +++ b/lib/sregex/README.markdown @@ -0,0 +1,738 @@ +Name +==== + +libsregex - A non-backtracking NFA/DFA-based Perl-compatible regex engine library for matching on large data streams + +Table of Contents +================= + +* [Name](#name) +* [Status](#status) +* [Syntax Supported](#syntax-supported) +* [API](#api) + * [Constants](#constants) + * [Memory pool API](#memory-pool-api) + * [sre_create_pool](#sre_create_pool) + * [sre_destroy_pool](#sre_destroy_pool) + * [sre_reset_pool](#sre_reset_pool) + * [Regex parsing and compilation API](#regex-parsing-and-compilation-api) + * [sre_regex_parse](#sre_regex_parse) + * [sre_regex_parse_multi](#sre_regex_parse_multi) + * [sre_regex_compile](#sre_regex_compile) + * [Regex execution API](#regex-execution-api) + * [Thompson VM](#thompson-vm) + * [sre_vm_thompson_create_ctx](#sre_vm_thompson_create_ctx) + * [sre_vm_thompson_exec](#sre_vm_thompson_exec) + * [Just-In-Time Support for Thompson VM](#just-in-time-support-for-thompson-vm) + * [sre_vm_thompson_jit_compile](#sre_vm_thompson_jit_compile) + * [sre_vm_thompson_jit_get_handler](#sre_vm_thompson_jit_get_handler) + * [sre_vm_thompson_jit_create_ctx](#sre_vm_thompson_jit_create_ctx) + * [Pike VM](#pike-vm) + * [sre_vm_pike_create_ctx](#sre_vm_pike_create_ctx) + * [sre_vm_pike_exec](#sre_vm_pike_exec) +* [Examples](#examples) +* [Installation](#installation) +* [Test Suite](#test-suite) +* [TODO](#todo) +* [Author](#author) +* [Copyright and License](#copyright-and-license) +* [See Also](#see-also) + +Status +====== + +This library is already quite usable and some people are already using it in production. + +Nevertheless this library is still under heavy development. The API is still in flux +and may be changed quickly without notice. + +This is a pure C library that is designed to have zero dependencies. + +No pathological regexes exist for this regex engine because it does not +use a backtracking algorithm at all. + +Already rewrote the code base of Russ Cox's re1 library using the nginx coding style (yes, I love it!), also incorporated a clone of the nginx memory pool into it for memory management. + +Already ported the Thompson and Pike VM backends to sregex. The former is just for yes-or-no matching, and the latter also supports sub-match capturing. + +Implemented the case-insensitive matching mode via the `SRE_REGEX_CASELESS` flag. + +The full streaming matching API for the sregex engine has already been implemented, +for both the Pike and Thompson regex VMs. The sub-match capturing also supports streaming processing. +When the state machine is yielded (that is, returning `SRE_AGAIN` on the current input data chunk), +sregex will always output the current value range for the `$&` sub-match capture in the user-supplied +`ovector` array. + +Almost all the relevant test cases for PCRE 8.32 and Perl 5.16.2 have been imported into sregex's test suite +and all tests are passing right now. + +Already implemented an API for assembling multiple user regexes and +returning an ID indicating exactly which regex is matched +(first), as well as the corresponding sub-match captures. + +There is also a Just-in-Time (JIT) compiler targeting `x86_64` for the Thompson VM. + +Syntax Supported +================ + +The following Perl 5 regex syntax features have already been implemented. + + ^ match the beginning of lines + $ match the end of lines + + \A match only at beginning of stream + \z match only at end of stream + + \b match a word boundary + \B match except at a word boundary + + . match any char + + [ab0-9] character classes (positive) + [^ab0-9] character classes (negative) + + \d match a digit character ([0-9]) + \D match a non-digit character ([^0-9]) + + \s match a whitespace character ([ \f\n\r\t]) + \S match a non-whitespace character ([^ \f\n\r\t]) + + \h match a horizontal whitespace character + \H match a character that isn't horizontal whitespace + + \v match a vertical whitespace character + \V match a character that isn't vertical whitespace + + \w match a "word" character ([A-Za-z0-9_]) + \W match a non-"word" character ([^A-Za-z0-9_]) + + \cK control char (example: VT) + + \N match a character that isn't a newline + + ab concatenation; first match a, and then b + a|b alternation; match a or b + + (a) capturing parentheses + (?:a) non-capturing parantheses + + a? match 1 or 0 times, greedily + a* match 0 or more times, greedily + a+ match 1 or more times, greedily + + a?? match 1 or 0 times, not greedily + a*? match 0 or more times, not greedily + a+? match 1 or more times, not greedily + + a{n} match exactly n times + a{n,m} match at least n but not more than m times, greedily + a{n,} match at least n times, greedily + + a{n}? match exactly n times, not greedily (redundant) + a{n,m}? match at least n but not more than m times, not greedily + a{n,}? match at least n times, not greedily + +The following escaping sequences are supported: + + \t tab + \n newline + \r return + \f form feed + \a alarm + \e escape + \b backspace (in character class only) + \x{}, \x00 character whose ordinal is the given hexadecimal number + \o{}, \000 character whose ordinal is the given octal number + +Escaping a regex meta character yields the literal character itself, like `\{` and `\.`. + +Only the octet mode is supported; no multi-byte character encoding love (yet). + +API +=== + +This library provides a pure C API. This API is still in flux and may change in the near future +without notice. + +[Back to TOC](#table-of-contents) + +Constants +--------- + +This library provides the following public constants for use in the various API functions. + +* `SRE_OK` +* `SRE_DECLINED` +* `SRE_AGAIN` +* `SRE_ERROR` + +The actual meanings of these constants depend on the concrete API functions using them. + +[Back to TOC](#table-of-contents) + +Memory pool API +--------------- + +This library utilizes a memory pool to simplify memory management. Most of the low-level API +functions provided by this library does accept a memory pool pointer as an argument. + +The operations on the memory pool on the user side are limited to + +1. creating a memory pool, +2. destroying a memory pool, and +3. resetting a memory pool. + +[Back to TOC](#table-of-contents) + +### sre_create_pool + +```C +sre_pool_t *sre_create_pool(size_t size); +``` + +Creates a memory pool with a page size of `size`. Returns the pool as an opaque pointer type `sre_pool_t`. + +Usually the page size you specify should not be too large. Usually 1KB or 4KB should be sufficient. +Optimal values depend on your actual regexes and input data pattern involved and should be +tuned empirically. + +The returned memory pool pointer is usually fed into other API functions provided by this library +as an argument. + +It is your responsibility to destroy the pool when you no longer need it via the [sre_destroy_pool](#sre_destroy_pool) function. Failing to destroy the pool will result in memory leaks. + +[Back to TOC](#table-of-contents) + +### sre_destroy_pool + +```C +void sre_destroy_pool(sre_pool_t *pool); +``` + +Destroys the memory pool created by the [sre_create_pool](#sre_create_pool) function. + +[Back to TOC](#table-of-contents) + +### sre_reset_pool + +```C +void sre_reset_pool(sre_pool_t *pool); +``` + +[Back to TOC](#table-of-contents) + +Regex parsing and compilation API +--------------------------------- + +Before running a regex (or set of multiple regexes), you need to parse and compile them first, such that +you can run the compiled form of the regex(es) over and over again at maximum speed. + +[Back to TOC](#table-of-contents) + +### sre_regex_parse + +```C +typedef uint8_t sre_char; +typedef uintptr_t sre_uint_t; +typedef intptr_t sre_int_t; + +sre_regex_t *sre_regex_parse(sre_pool_t *pool, sre_char *regex, + sre_uint_t *ncaps, int flags, sre_int_t *err_offset); +``` + +Parses the string representation of the user regex specified by the `regex` parameter (as a null-terminated string). + +Returns a parsed regex object of the opaque pointer type `sre_regex_t` if no error happens. Otherwise returns a NULL pointer and set the offset in the `regex` string where the parse failure happens. + +The parsed regex object pointer is an Abstract-Syntax-Tree (AST) representation of the string regex. +It can later be fed into API function calls like [sre_regex_compile](#sre_regex_compile) as an argument. + +The first parameter, `pool`, is a memory pool created by the [sre_create_pool](#sre_create_pool) API function. + +The `ncaps` parameter is used to output the number of sub-match captures found in the regex. This integer can later be used to extract sub-match captures. + +The `flags` parameter specifies additional regex compiling flags like below: + +* `SRE_REGEX_CASELESS` + case-insensitive matching mode. + +[Back to TOC](#table-of-contents) + +### sre_regex_parse_multi + +```C +typedef uint8_t sre_char; +typedef uintptr_t sre_uint_t; +typedef intptr_t sre_int_t; + +sre_regex_t *sre_regex_parse_multi(sre_pool_t *pool, sre_char **regexes, + sre_int_t nregexes, sre_uint_t *max_ncaps, int *multi_flags, + sre_int_t *err_offset, sre_int_t *err_regex_id); +``` + +Similar to the [sre_regex_parse](#sre_regex_parse) API function but works on multiple +regexes at once. + +These regexes are specified by the C string array `regexes`, whose size is determined by the `nregexes` parameter. + +All these input regexes are combined into a single parsed regex object, returned as the opaque +pointer of the type `sre_regex_t`, just like [sre_regex_parse](#sre_regex_parse). These regexes are +logically connected via the alternative regex operator (`|`), so the order of these regexes determine +their relative precedence in a tie. Despite of being connected by `|` logically, the +[regex execution API](#regex-execution-api) can still signify which of these regexes is matched +by returning the regex ID which is the offset of the regex in the `regexes` input array. + +Upon failures, returns the NULL pointer and sets + +* the output parameter `err_regex_id` for the number of regex having syntax errors +(i.e., the 0-based offset of the regex in the `regexes` input parameter array), and +* the output parameter `err_offset` for the string offset in the guilty regex where the failure happens. + +The output parameter `max_ncaps` returns the maximum number of sub-match captures in all these regexes. +Note that, this is is the maximum instead of the sum. + +The `multi_flags` is an input array consisting of the regex flags for every regex specified in the `regexes` array. +The size of this array must be no shorter than the size specified by `nregexes`. For what +regex flags you can use, just check out the documentation for the [sre_regex_parse](#sre_regex_parse) API function. + +[Back to TOC](#table-of-contents) + +### sre_regex_compile + +```C +sre_program_t *sre_regex_compile(sre_pool_t *pool, sre_regex_t *re); +``` + +Compiles the parsed regex object (returned by [sre_regex_parse](#sre_regex_parse)) into a bytecode +representation of the regex, of the opaque pointer type `sre_program_t`. + +Returns the NULL pointer in case of failures. + +The memory pool specified by the `pool` parameter does not have to be the same as the one used +by the earlier [sre_regex_parse](#sre_regex_parse) call. But you could use the same memory pool if you want. + +The compiled regex form (or bytecode form) returned can be fed into one of the regex backend VMs +provided by this library for execution. See [regex execution API](#regex-execution-api) for more +details. + +[Back to TOC](#table-of-contents) + +Regex execution API +------------------- + +The regex execution API provides various different virtual machines (VMs) for running +the compiled regexes by different algorithms. + +Currently the following VMs are supported: + +* [Thompson VM](#thompson-vm) +* [Pike VM](#pike-vm) + +[Back to TOC](#table-of-contents) + +### Thompson VM + +The Thompson VM uses the Thompson NFA simulation algorithm to execute the compiled regex(es) by +matching against an input string (or input stream). + +[Back to TOC](#table-of-contents) + +#### sre_vm_thompson_create_ctx + +```C +sre_vm_thompson_ctx_t *sre_vm_thompson_create_ctx(sre_pool_t *pool, + sre_program_t *prog); +``` + +Creates and returns a context structure (of the opaque type `sre_vm_thompson_ctx_t`) for +the Thompson VM. Returns NULL in case of failure (like running out of memory). + +This return value can later be used by the [sre_vm_thompson_exec](#sre_vm_thompson_exec) function as an argument. + +The `prog` parameter accepts the compiled bytecode form of the regex(es) returned by the [sre_regex_compile](#sre_regex_compile) +function. This compiled regex(es) is embedded into the resulting context structure. + +Accepts a memory pool created by the [sre_create_pool](#sre_create_pool) function as the first argument. This memory pool does not have to be the same as the pool used for parsing or compiling the regex(es). + +[Back to TOC](#table-of-contents) + +#### sre_vm_thompson_exec + +```C +typedef intptr_t sre_int_t; +typedef uint8_t sre_char; + +sre_int_t sre_vm_thompson_exec(sre_vm_thompson_ctx_t *ctx, sre_char *input, + size_t size, unsigned int eof); +``` + +Executes the compiled regex(es) on the input string data atop the Thompson VM (without Just-In-Time optimizations). + +The `ctx` argument value is returned by the [sre_vm_thompson_create_ctx](#sre_vm_thompson_create_ctx) +function. The compiled (bytecode) form of the regex(es) are already embedded in this `ctx` value. +This `ctx` argument can be changed by this function call and must be preserved for all the `sre_vm_thompson_exec` calls +on the same data stream. Different data streams MUST use different `ctx` instances. When a data stream is completely processed, the corresponding `ctx` instance MUST be discarded and cannot be reused again. + +The input data is specified by a character data chunk in a data stream. The `input` parameter specifies the starting address of the data +chunk, the `size` parameter specifies the size of the chunk, while the `eof` parameter identifies +whether this chunk is the last chunk in the stream. If you just want to match on a single +C string, then always specify 1 as the `eof` argument and exclude the NULL string terminator in your C string while computing the `size` argument value. + +This function may return one of the following values: + +* `SRE_OK` + A match is found. +* `SRE_DECLINED` + No match can be found. This value can never be returned when the `eof` parameter is unset (because + a match MAY get found when seeing more input string data). +* `SRE_AGAIN` + More data (in a subsequent call) is needed to obtain a match. The current data chunk can + be discarded after this call returns. This value can only be returned when the `eof` parameter is + not set. +* `SRE_ERROR` + A fatal error has occurred (like running out of memory). + +This function does not return the regex ID of the matched regex when multiple regexes are +specified at once via the [sre_regex_parse_multi](#sre_regex_parse_multi) function is used. This +may change in the future. + +Sub-match captures are not supported in this Thompson VM by design. You should use the [Pike VM](#pike-vm) instead if you want that. + +[Back to TOC](#table-of-contents) + +#### Just-In-Time Support for Thompson VM + +The Thompson VM comes with a Just-In-Time compiler. Currently only the x86_64 architecture is supported. +Support for other architectures may come in the future. + +[Back to TOC](#table-of-contents) + +##### sre_vm_thompson_jit_compile + +```C +typedef intptr_t sre_int_t; + +sre_int_t sre_vm_thompson_jit_compile(sre_pool_t *pool, sre_program_t *prog, + sre_vm_thompson_code_t **pcode); +``` + +Compiles the bytecode form of the regex(es) created by [sre_regex_compile](#sre_regex_compile) +down into native code. + +It returns one of the following values: + +* `SRE_OK` + Compilation is successful. +* `SRE_DECLINED` + The current architecture is not supported. +* `SRE_ERROR` + A fatal error occurs (like running out of memory). + +The `pool` parameter specifies a memory pool created by [sre_create_pool](#sre_create_pool). +This pool is used for the JIT compilation. + +The `prog` parameter is the compiled bytecode form of the regex(es) created by the [sre_regex_compile](#sre_regex_compile) +function call. + +The resulting JIT compiled native code along with the runtime information is saved in the output +argument `pcode` of the opaque type `sre_vm_thompson_code_t`. This structure is allocated by this +function in the provided memory pool. + +This `sre_vm_thompson_code_t` object can later be executed by running the C function pointer +fetched from this object via the [sre_vm_thompson_jit_get_handler](#sre_vm_thompson_jit_get_handler) call. + +[Back to TOC](#table-of-contents) + +##### sre_vm_thompson_jit_get_handler + +```C +typedef uint8_t sre_char; +typedef intptr_t sre_int_t; +typedef sre_int_t (*sre_vm_thompson_exec_pt)(sre_vm_thompson_ctx_t *ctx, + sre_char *input, size_t size, unsigned int eof); + +sre_vm_thompson_exec_pt sre_vm_thompson_jit_get_handler( + sre_vm_thompson_code_t *code); +``` + +Fetches a C function pointer from the JIT compiled form of the regex(es) generated via an +earlier [sre_vm_thompson_jit_compile](#sre_vm_thompson_jit_compile). + +The C function pointer is of the exactly same function prototype of the interpreter entry +function [sre_vm_thompson_exec](#sre_vm_thompson_exec). The only difference is that the +`sre_vm_thompson_ctx_t` object MUST be created via the [sre_vm_thompson_jit_create_ctx](#sre_vm_thompson_jit_create_ctx) +function instead of the [sre_vm_thompson_create_ctx](#sre_vm_thompson_create_ctx) function. Despite that, the resulting C function pointer can be used as the same way as [sre_vm_thompson_exec](#sre_vm_thompson_exec). + +[Back to TOC](#table-of-contents) + +##### sre_vm_thompson_jit_create_ctx + +```C +sre_vm_thompson_ctx_t *sre_vm_thompson_jit_create_ctx(sre_pool_t *pool, + sre_program_t *prog); +``` + +Allocates a context structure for executing the compiled native code form of the regex(s) generated +by the Just-In-Time compiler of the Thompson VM. + +This context object should only be used by the C function returned by the [sre_vm_thompson_jit_get_handler](#sre_vm_thompson_jit_get_handler) +function call. Use of this object in [sre_vm_thompson_exec](#sre_vm_thompson_exec) is prohibited. + +[Back to TOC](#table-of-contents) + +### Pike VM + +The Pike VM uses an enhanced version of the Thompson NFA simulation algorithm that supports sub-match +captures. + +[Back to TOC](#table-of-contents) + +#### sre_vm_pike_create_ctx + +```C +typedef intptr_t sre_int_t; + +sre_vm_pike_ctx_t *sre_vm_pike_create_ctx(sre_pool_t *pool, sre_program_t *prog, + sre_int_t *ovector, size_t ovecsize); +``` + +Creates and returns a context structure (of the opaque type `sre_vm_pike_ctx_t`) for the +Pike VM. Returns NULL in case of failure (like running out of memory). + +This return value can later be used by the [sre_vm_pike_exec](#sre_vm_pike_exec) function as an argument. + +The `prog` parameter accepts the compiled bytecode form of the regex(es) returned by the [sre_regex_compile](#sre_regex_compile) +function. This compiled regex(es) is embedded into the resulting context structure. + +Accepts a memory pool created by the [sre_create_pool](#sre_create_pool) function as the first argument. This memory pool does not have to be the same as the pool used for parsing or compiling the regex(es). + +The `ovector` parameter specifies an array for outputting the beginning and end offsets of the (sub-)match captures. +The elements of the array are used like below: + +1. The 1st element of the array holds the beginning offset of the whole match, +2. the 2nd element holds the end offset of the whole match, +3. the 3rd element holds the beginning offset of the 1st sub-match capture, +4. the 4th element holds the end offset of the 1st sub-match capture, +5. the 5rd element holds the beginning offset of the 2st sub-match capture, +6. the 6th element holds the end offset of the 2st sub-match capture, +7. and so on... + +The size of the `ovector` array is specified by the `ovecsize` parameter, in bytes. The size of the array +can be computed as follows: + +``` + ovecsize = 2 * (ncaps + 1) * sizeof(sre_int_t) +``` + +where `ncaps` is the value previously output by the [sre_regex_parse](#sre_regex_parse) +or [sre_regex_parse_multi](#sre_regex_parse_multi) function. + +The `ovector` array is allocated by the caller and filled by this function call. + +[Back to TOC](#table-of-contents) + +#### sre_vm_pike_exec + +```C +typedef uint8_t sre_char; +typedef intptr_t sre_int_t; + +sre_int_t sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, + unsigned eof, sre_int_t **pending_matched); +``` + +Executes the compiled regex(es) on the input string data atop the Pike VM (without Just-In-Time optimizations). + +The `ctx` argument value is returned by the [sre_vm_pike_create_ctx](#sre_vm_pike_create_ctx) +function. The compiled (bytecode) form of the regex(es) are already embedded in this `ctx` value. +This `ctx` argument can be changed by this function call and must be preserved for all the `sre_vm_pike_exec` calls +on the same data stream. Different data streams MUST use different `ctx` instances. When a data stream is completely processed, the corresponding `ctx` instance MUST be discarded and cannot be reused again. + +The input data is specified by a character data chunk in a data stream. The `input` parameter specifies the starting address of the data +chunk, the `size` parameter specifies the size of the chunk, while the `eof` parameter identifies +whether this chunk is the last chunk in the stream. If you just want to match on a single +C string, then always specify 1 as the `eof` argument and exclude the NULL string terminator in your C string while computing the `size` argument value. + +The `pending_matched` parameter outputs an array holding all the pending matched captures (whole-match only, no sub-matches) if +no complete matches have been found yet (i.e., this call returns `SRE_AGAIN`). +This is very useful for doing regex substitutions on (large) data streams where the caller +can use the info in `pending_matched` to decide exactly how much data in the current to-be-thrown data chunk needs to be buffered. +The caller should never allocate the space for this array, rather, +this function call takes care of it and just sets the (double) pointer to point to its internal (read-only) storage. + +This function may return one of the following values: + +* a non-negative value + A match is found and the value is the ID of the (first) matched regex if multiple regexes are + parsed at once via the [sre_regex_parse_multi](#sre_regex_parse_multi) function. A regex ID + is the 0-based index of the corresponding regex in the regexes array fed into the [sre_regex_parse_multi](#sre_regex_parse_multi) + function. +* `SRE_DECLINED` + No match can be found. This value can never be returned when the `eof` parameter is unset (because + a match MAY get found when seeing more input string data). +* `SRE_AGAIN` + More data (in a subsequent call) is needed to obtain a match. The current data chunk can + be discarded after this call returns. This value can only be returned when the `eof` parameter is + not set. +* `SRE_ERROR` + A fatal error has occurred (like running out of memory). + +[Back to TOC](#table-of-contents) + +Examples +======== + +Please check out the sregex-cli command-line utility's source for usage: + +https://github.com/agentzh/sregex/blob/master/src/sre_cli.c#L1 + +The `sregex-cli` command-line interface can be used as a convenient way to exercise the engine: + + ./sregex-cli 'a|ab' 'blab' + +It also supports the `--flags` option which can be used to enable case-insensitive matching: + + ./sregex-cli --flags i 'A|AB' 'blab' + +And also the `--stdin` option for reading data chunks from stdin: + + # one single data chunk to be matched: + perl -e '$s="foobar";print length($s),"\n$s"' \ + | ./sregex-cli --stdin foo + + # 3 data chunks (forming a single input stream) to be matched: + perl -e '$s="foobar";print length($s),"\n$s" for 1..3' \ + | sregex-cli --stdin foo + +A real-world application of this library is the ngx_replace_filter module: + +https://github.com/agentzh/replace-filter-nginx-module + +[Back to TOC](#table-of-contents) + +Installation +============ + + make + make install + +Gnu make and gcc are required. (On operating systems like FreeBSD and Solaris, you should type `gmake` instead of `make` here.) + +It will build `libsregex.so` (or `libsregex.dylib` on Mac OS X), `libsregex.a`, and the command-line utility `sregex-cli` and install + them into the prefix `/usr/local/` by default. + +If you want to install into a custom location, then just specify the `PREFIX` variable like this: + + make PREFIX=/opt/sregex + make install PREFIX=/opt/sregex + +If you are building a binary package (like an RPM package), then +you will find the `DESTDIR` variable handy, as in + + make PREFIX=/opt/sregex + make install PREFIX=/opt/sregex DESTDIR=/path/to/my/build/root + +If you run `make distclean` before `make`, then you also need bison 2.7+ +for generating the regex parser files. + +[Back to TOC](#table-of-contents) + +Test Suite +========== + +The test suite is driven by Perl 5. + +To run the test suite + + make test + +Gnu make, perl 5.16.2, and the following Perl CPAN modules are required: + +* Cwd +* IPC::Run3 +* Test::Base +* Test::LongString + +If you already have `perl` installed in your system, you can use the following +command to install these CPAN modules (you may need to run it using `root`): + + cpan Cwd IPC::Run3 Test::Base Test::LongString + +You can also run the test suite using the Valgrind Memcheck tool to check +memory issues in sregex: + + make valtest + +Because we have a huge test suite, to run the test suite in parallel, you can specify +the parallelism level with the `jobs` `make` variable, as in + + make test jobs=8 + +or similarly + + make valtest jobs=8 + +So the test suite will run in 8 parallel jobs (assuming you have 8 CPU cores). + +The streaming matching API is much more thoroughly excerised by the test suite of +the [ngx_replace_filter](https://github.com/agentzh/replace-filter-nginx-module) module. + +[Back to TOC](#table-of-contents) + +TODO +==== + +* implement the `(?i)` and `(?-i)` regex syntax. +* implement a simplified version of the backreferences. +* implement the comment notation `(?#comment)`. +* implement the POSIX character class notation. +* allow '\0' be used in both the regex and the subject string. +* add a bytecode optimizer to the regex VM (which also generates minimized DFAs for the Thompson VM). +* add a JIT compiler for the Pike VM targeting x86_64. +* port the existing x86_64 JIT compiler for the Thompson VM to other architectures like i386. +* implement the generalized look-around assertions like `(?=pattern)`, `(?!pattern)`, `(?<=pattern)`, and `(?, OpenResty Inc. + +[Back to TOC](#table-of-contents) + +Copyright and License +===================== + +Part of this code is from the NGINX open source project: http://nginx.org/LICENSE + +This library is licensed under the BSD license. + +Copyright (C) 2012-2017, by Yichun "agentzh" Zhang (章亦春), OpenResty Inc. + +Copyright (C) 2007-2009 Russ Cox, Google Inc. All rights reserved. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +* Neither the name of Google, Inc. nor the names of its contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 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. + +[Back to TOC](#table-of-contents) + +See Also +======== +* Slides for my talk "sregex: matching Perl 5 regexes on data streams": http://agentzh.org/misc/slides/yapc-na-2013-sregex.pdf +* The ngx_replace_filter module: https://github.com/agentzh/replace-filter-nginx-module +* "Implementing Regular Expressions" http://swtch.com/~rsc/regexp/ +* The re1 project: http://code.google.com/p/re1/ +* The re2 project: http://code.google.com/p/re2/ + +[Back to TOC](#table-of-contents) diff --git a/lib/sregex/bench/Makefile b/lib/sregex/bench/Makefile new file mode 100644 index 0000000..2bd4d65 --- /dev/null +++ b/lib/sregex/bench/Makefile @@ -0,0 +1,45 @@ +RE2_LIB=/opt/re2/lib +RE2_INC=/opt/re2/include + +RE1_LIB=../../re1 +RE1_INC=../../re1 + +PCRE_LIB=/opt/pcre/lib +PCRE_INC=/opt/pcre/include + +CFLAGS= -c -Wall -Werror -O3 -g +CXXFLAGS= -c -Wall -Werror -O3 -g +REGEX1= +FILE1=abc.txt + +.PHONY: all test + +all: sregex re1 pcre re2 + +sregex: sregex.o ../libsregex.a + $(CC) -o $@ -Wl,-rpath,.. -L.. $< -lsregex -lrt + +re1: re1.o $(RE1_LIB)/libre1.a + $(CC) -o $@ -Wl,-rpath,$(RE1_LIB) -L$(RE1_LIB) $< -lre1 -lrt + +re2: re2.o + $(CXX) -o $@ -Wl,-rpath,$(RE2_LIB) -L$(RE2_LIB) $< -lre2 -lrt + +pcre: pcre.o + $(CC) -o $@ -Wl,-rpath,$(PCRE_LIB) -L$(PCRE_LIB) $< -lpcre -lrt + +%.o: %.c + $(CC) $(CFLAGS) -I../src -I$(RE1_INC) -I$(PCRE_INC) $< + +%.o: %.cc + $(CXX) $(CXXFLAGS) -I$(RE2_INC) $< + +test: all $(FILE1) + ./bench '(?:a|b)aa(?:aa|bb)cc(?:a|b)' $(FILE1) + +clean: + rm -rf *.o sregex re1 + +$(FILE1): + perl gen-data.pl + diff --git a/lib/sregex/bench/bench b/lib/sregex/bench/bench new file mode 100644 index 0000000..058b23a --- /dev/null +++ b/lib/sregex/bench/bench @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +#E='valgrind --leak-check=full --quiet' +E= + +$E ./sregex --thompson --thompson-jit --pike $1 $2 + +./re1 --thompson --pike $1 $2 + +$E ./pcre --default --jit --dfa $1 $2 + +$E ./re2 $1 $2 + diff --git a/lib/sregex/bench/gen-data.pl b/lib/sregex/bench/gen-data.pl new file mode 100644 index 0000000..cbfff6b --- /dev/null +++ b/lib/sregex/bench/gen-data.pl @@ -0,0 +1,11 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +my $infile = "abc.txt"; +open my $in, ">$infile" or + die "Cannot open $infile for writing: $!\n"; +print $in "abccc" x (1024 * 1024) . "aaabbccb"; +close $in; + diff --git a/lib/sregex/bench/pcre.c b/lib/sregex/bench/pcre.c new file mode 100644 index 0000000..135f137 --- /dev/null +++ b/lib/sregex/bench/pcre.c @@ -0,0 +1,339 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static void usage(int rc); +static void run_engines(pcre *re, unsigned engine_types, int ncaps, + const char *input, size_t len); + + +enum { + ENGINE_DEFAULT = (1 << 0), + ENGINE_JIT = (1 << 1), + ENGINE_DFA = (1 << 2) +}; + + +#define TIMER_START \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &begin) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } + + +#define TIMER_STOP \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } \ + elapsed = (end.tv_sec - begin.tv_sec) * 1e3 + (end.tv_nsec - begin.tv_nsec) * 1e-6; + + +int +main(int argc, char **argv) +{ + int flags = 0; + unsigned engine_types = 0; + unsigned i; + int err_offset = -1; + pcre *re; + int ncaps; + char *input; + FILE *f; + size_t len; + long rc; + const char *errstr; + + if (argc < 3) { + usage(1); + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + break; + } + + if (strncmp(argv[i], "--default", + sizeof("--default") - 1) == 0) + { + engine_types |= ENGINE_DEFAULT; + + } else if (strncmp(argv[i], "--jit", sizeof("--jit") - 1) + == 0) + { + engine_types |= ENGINE_JIT; + + } else if (strncmp(argv[i], "--dfa", sizeof("--dfa") - 1) + == 0) + { + engine_types |= ENGINE_DFA; + + } else if (strncmp(argv[i], "-i", 2) == 0) { + flags |= PCRE_CASELESS; + + } else { + fprintf(stderr, "unknown option: %s\n", argv[i]); + exit(1); + } + } + + if (engine_types == 0) { + fprintf(stderr, "No engine specified.\n"); + exit(1); + } + + if (argc - i != 2) { + usage(1); + } + + re = pcre_compile(argv[i++], flags, &errstr, &err_offset, NULL); + if (re == NULL) { + fprintf(stderr, "[error] pos %d: %s\n", err_offset, errstr); + return 2; + } + + if (pcre_fullinfo(re, NULL, PCRE_INFO_CAPTURECOUNT, &ncaps) < 0) { + fprintf(stderr, "failed to get capture count.\n"); + return 2; + } + + errno = 0; + + f = fopen(argv[i], "rb"); + if (f == NULL) { + perror("open file"); + return 1; + } + + if (fseek(f, 0L, SEEK_END) != 0) { + perror("seek to file end"); + return 1; + } + + rc = ftell(f); + if (rc == -1) { + perror("get file offset by ftell"); + return 1; + } + + len = (size_t) rc; + + if (fseek(f, 0L, SEEK_SET) != 0) { + perror("seek to file beginning"); + return 1; + } + + input = malloc(len); + if (input == NULL) { + fprintf(stderr, "failed to allocate %ld bytes.\n", len); + return 1; + } + + if (fread(input, 1, len, f) < len) { + if (feof(f)) { + fprintf(stderr, "file truncated.\n"); + return 1; + + } else { + perror("read file"); + } + } + + if (fclose(f) != 0) { + perror("close file"); + return 1; + } + + run_engines(re, engine_types, ncaps, input, len); + + free(input); + pcre_free(re); + + return 0; +} + + +static void +run_engines(pcre *re, unsigned engine_types, int ncaps, + const char *input, size_t len) +{ + int i, n; + int rc; + int *ovector; + size_t ovecsize; + pcre_extra *extra; + struct timespec begin, end; + double elapsed; + const char *errstr = NULL; + + if (engine_types & ENGINE_DEFAULT) { + + ovecsize = (ncaps + 1) * 3; + ovector = malloc(ovecsize * sizeof(int)); + assert(ovector); + + printf("pcre default "); + + extra = pcre_study(re, 0, &errstr); + if (errstr != NULL) { + fprintf(stderr, "failed to study the regex: %s", errstr); + exit(2); + } + + TIMER_START + + rc = pcre_exec(re, extra, input, len, 0, 0, ovector, ovecsize); + + TIMER_STOP + + if (rc == 0) { + fprintf(stderr, "capture size too small"); + exit(2); + } + + if (rc == PCRE_ERROR_NOMATCH) { + printf("no match"); + + } else if (rc < 0) { + printf("error: %d", rc); + + } else if (rc > 0) { + printf("match"); + for (i = 0, n = 0; i < rc; i++, n += 2) { + printf(" (%d, %d)", ovector[n], ovector[n + 1]); + } + } + + printf(": %.02lf ms elapsed.\n", elapsed); + + if (extra) { + pcre_free_study(extra); + extra = NULL; + } + + free(ovector); + } + + if (engine_types & ENGINE_JIT) { + + ovecsize = (ncaps + 1) * 3; + ovector = malloc(ovecsize * sizeof(int)); + assert(ovector); + + printf("pcre JIT "); + + extra = pcre_study(re, PCRE_STUDY_JIT_COMPILE, &errstr); + if (errstr != NULL) { + fprintf(stderr, "failed to study the regex: %s", errstr); + exit(2); + } + + TIMER_START + + rc = pcre_exec(re, extra, input, len, 0, 0, ovector, ovecsize); + + TIMER_STOP + + if (rc == 0) { + fprintf(stderr, "capture size too small"); + exit(2); + } + + if (rc == PCRE_ERROR_NOMATCH) { + printf("no match"); + + } else if (rc < 0) { + printf("error: %d", rc); + + } else if (rc > 0) { + printf("match"); + for (i = 0, n = 0; i < rc; i++, n += 2) { + printf(" (%d, %d)", ovector[n], ovector[n + 1]); + } + } + + printf(": %.02lf ms elapsed.\n", elapsed); + + if (extra) { + pcre_free_study(extra); + extra = NULL; + } + + free(ovector); + } + + if (engine_types & ENGINE_DFA) { + int ws[100]; + + ovecsize = 2; + ovector = malloc(ovecsize * sizeof(int)); + assert(ovector); + + printf("pcre DFA "); + + extra = pcre_study(re, 0, &errstr); + if (errstr != NULL) { + fprintf(stderr, "failed to study the regex: %s", errstr); + exit(2); + } + + TIMER_START + + rc = pcre_dfa_exec(re, extra, input, len, 0, 0, ovector, ovecsize, + ws, sizeof(ws)/sizeof(ws[0])); + + TIMER_STOP + + if (rc == 0) { + rc = 1; + } + + if (rc == PCRE_ERROR_NOMATCH) { + printf("no match"); + + } else if (rc < 0) { + printf("error: %d", rc); + + } else if (rc > 0) { + printf("match"); + for (i = 0, n = 0; i < rc; i++, n += 2) { + printf(" (%d, %d)", ovector[n], ovector[n + 1]); + } + } + + printf(": %.02lf ms elapsed.\n", elapsed); + + if (extra) { + pcre_free_study(extra); + extra = NULL; + } + + free(ovector); + } +} + + +static void +usage(int rc) +{ + fprintf(stderr, "usage: pcre [options] \n" + "options:\n" + " -i use case insensitive matching\n" + " --default use the default PCRE engine\n" + " --dfa use the PCRE DFA engine\n" + " --jit use the PCRE JIT engine\n"); + exit(rc); +} diff --git a/lib/sregex/bench/re1.c b/lib/sregex/bench/re1.c new file mode 100644 index 0000000..b26279a --- /dev/null +++ b/lib/sregex/bench/re1.c @@ -0,0 +1,244 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static void usage(int rc); +static void run_engines(Prog *prog, unsigned engine_types, char *input); + + +enum { + ENGINE_THOMPSON = (1 << 0), + ENGINE_PIKE = (1 << 1) +}; + + +#define TIMER_START \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &begin) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } + + +#define TIMER_STOP \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } \ + elapsed = (end.tv_sec - begin.tv_sec) * 1e3 + (end.tv_nsec - begin.tv_nsec) * 1e-6; + + +int +main(int argc, char **argv) +{ + unsigned engine_types = 0; + unsigned i; + Regexp *re; + Prog *prog; + char *input; + FILE *f; + size_t len; + long rc; + + if (argc < 3) { + usage(1); + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + break; + } + + if (strncmp(argv[i], "--thompson", sizeof("--thompson") - 1) == 0) { + engine_types |= ENGINE_THOMPSON; + + } else if (strncmp(argv[i], "--pike", sizeof("--pike") - 1) + == 0) + { + engine_types |= ENGINE_PIKE; + + } else { + fprintf(stderr, "unknown option: %s\n", argv[i]); + exit(1); + } + } + + if (engine_types == 0) { + fprintf(stderr, "No engine specified.\n"); + exit(1); + } + + if (argc - i != 2) { + usage(1); + } + + re = parse(argv[i++]); + if (re == NULL) { + fprintf(stderr, "failed to parse the regex.\n"); + return 2; + } + + prog = compile(re); + if (prog == NULL) { + fprintf(stderr, "failed to compile the regex.\n"); + return 2; + } + + errno = 0; + + f = fopen(argv[i], "rb"); + if (f == NULL) { + perror("open file"); + return 1; + } + + if (fseek(f, 0L, SEEK_END) != 0) { + perror("seek to file end"); + return 1; + } + + rc = ftell(f); + if (rc == -1) { + perror("get file offset by ftell"); + return 1; + } + + len = (size_t) rc; + + if (fseek(f, 0L, SEEK_SET) != 0) { + perror("seek to file beginning"); + return 1; + } + + input = malloc(len + 1); + if (input == NULL) { + fprintf(stderr, "failed to allocate %ld bytes.\n", len); + return 1; + } + + if (fread(input, 1, len, f) < len) { + if (feof(f)) { + fprintf(stderr, "file truncated.\n"); + return 1; + + } else { + perror("read file"); + } + } + + input[len] = '\0'; + + if (fclose(f) != 0) { + perror("close file"); + return 1; + } + + run_engines(prog, engine_types, input); + + free(re); + free(prog); + return 0; +} + + +static void +run_engines(Prog *prog, unsigned engine_types, char *input) +{ + unsigned i; + int rc; + char *ovector[MAXSUB]; + size_t ovecsize; + struct timespec begin, end; + double elapsed; + long from, to; + + if (engine_types & ENGINE_THOMPSON) { + + printf("re1 Thompson "); + + memset(ovector, 0, sizeof(ovector)); + + TIMER_START + + rc = thompsonvm(prog, input, ovector, nelem(ovector)); + + TIMER_STOP + + if (!rc) { + printf("no match"); + + } else { + printf("match"); + } + + printf(": %.02lf ms elapsed.\n", elapsed); + } + + if (engine_types & ENGINE_PIKE) { + printf("re1 Pike "); + + memset(ovector, 0, sizeof(ovector)); + + TIMER_START + + rc = pikevm(prog, input, ovector, nelem(ovector)); + + TIMER_STOP + + if (!rc) { + printf("no match"); + + } else { + printf("match"); + + for (ovecsize = MAXSUB; ovecsize > 0; ovecsize--) { + if (ovector[ovecsize - 1]) { + break; + } + } + + for (i = 0; i < ovecsize; i += 2) { + if (ovector[i] == NULL) { + from = -1; + + } else { + from = ovector[i] - input; + } + + if (ovector[i + 1] == NULL) { + to = -1; + + } else { + to = ovector[i] - input; + } + + printf(" (%ld, %ld)", from, to); + } + } + + printf(": %.02lf ms elapsed.\n", elapsed); + } +} + + +static void +usage(int rc) +{ + fprintf(stderr, "usage: re1 [options] \n" + "options:\n" + " --pike use the Pike VM interpreter\n" + " --thompson use the Thompson VM interpreter\n"); + exit(rc); +} diff --git a/lib/sregex/bench/re2.cc b/lib/sregex/bench/re2.cc new file mode 100644 index 0000000..8374f8c --- /dev/null +++ b/lib/sregex/bench/re2.cc @@ -0,0 +1,185 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +static void usage(int rc); +static void run_engine(RE2 *re, char *input); + + +#define TIMER_START \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &begin) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } + + +#define TIMER_STOP \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } \ + elapsed = (end.tv_sec - begin.tv_sec) * 1e3 + (end.tv_nsec - begin.tv_nsec) * 1e-6; + + +int +main(int argc, char **argv) +{ + int i; + RE2 *re; + char *re_str, *p; + char *input; + FILE *f; + size_t len; + long rc; + + if (argc < 3) { + usage(1); + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + break; + } + + fprintf(stderr, "unknown option: %s\n", argv[i]); + exit(1); + } + + if (argc - i != 2) { + usage(1); + } + + re_str = argv[i++]; + len = strlen(re_str); + + p = (char *) malloc(len + 1 + sizeof("()") - 1); + if (p == NULL) { + return 2; + } + + p[0] = '('; + memcpy(&p[1], re_str, len); + p[len + 1] = ')'; + p[len + 2] = '\0'; + + //printf("regex: %s\n", p); + + re = new RE2(p); + if (re == NULL) { + return 2; + } + + free(p); + + if (!re->ok()) { + delete re; + return 2; + } + + errno = 0; + + f = fopen(argv[i], "rb"); + if (f == NULL) { + perror("open file"); + return 1; + } + + if (fseek(f, 0L, SEEK_END) != 0) { + perror("seek to file end"); + return 1; + } + + rc = ftell(f); + if (rc == -1) { + perror("get file offset by ftell"); + return 1; + } + + len = (size_t) rc; + + if (fseek(f, 0L, SEEK_SET) != 0) { + perror("seek to file beginning"); + return 1; + } + + input = (char *) malloc(len + 1); + if (input == NULL) { + fprintf(stderr, "failed to allocate %ld bytes.\n", len); + return 1; + } + + if (fread(input, 1, len, f) < len) { + if (feof(f)) { + fprintf(stderr, "file truncated.\n"); + return 1; + + } else { + perror("read file"); + } + } + + input[len] = '\0'; + + if (fclose(f) != 0) { + perror("close file"); + return 1; + } + + run_engine(re, input); + + delete re; + free(input); + return 0; +} + + +static void +run_engine(RE2 *re, char *input) +{ + bool rc; + re2::StringPiece cap; + struct timespec begin, end; + double elapsed; + const char *p; + + printf("re2 "); + + TIMER_START + + rc = RE2::PartialMatch(input, *re, &cap); + + TIMER_STOP + + if (rc) { + p = cap.data(); + printf("match (%ld, %ld)", (long) (p - input), + (long) (p - input + cap.size())); + + } else { + printf("no match"); + } + + printf(": %.02lf ms elapsed.\n", elapsed); +} + + +static void +usage(int rc) +{ + fprintf(stderr, "usage: re2 \n"); + exit(rc); +} diff --git a/lib/sregex/bench/sregex.c b/lib/sregex/bench/sregex.c new file mode 100644 index 0000000..d9f5926 --- /dev/null +++ b/lib/sregex/bench/sregex.c @@ -0,0 +1,399 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#include +#include +#include +#include +#include +#include +#include + + +static void usage(int rc); +static void run_engines(sre_program_t *prog, unsigned engine_types, + sre_uint_t ncaps, sre_char *input, size_t len); +static void alloc_error(void); +sre_int_t run_jitted_thompson(sre_vm_thompson_exec_pt handler, + sre_vm_thompson_ctx_t *ctx, sre_char *input, size_t size, unsigned eof); + + +enum { + ENGINE_THOMPSON = (1 << 0), + ENGINE_THOMPSON_JIT = (1 << 1), + ENGINE_PIKE = (1 << 2) +}; + + +#define TIMER_START \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &begin) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } + + +#define TIMER_STOP \ + if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end) == -1) { \ + perror("clock_gettime"); \ + exit(2); \ + } \ + elapsed = (end.tv_sec - begin.tv_sec) * 1e3 + (end.tv_nsec - begin.tv_nsec) * 1e-6; + + +int +main(int argc, char **argv) +{ + int flags = 0; + unsigned engine_types = 0; + sre_uint_t i; + sre_int_t err_offset = -1; + sre_pool_t *ppool; /* parser pool */ + sre_pool_t *cpool; /* compiler pool */ + sre_regex_t *re; + sre_program_t *prog; + sre_uint_t ncaps; + sre_char *input; + FILE *f; + size_t len; + long rc; + + if (argc < 3) { + usage(1); + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + break; + } + + if (strncmp(argv[i], "--thompson-jit", + sizeof("--thompson-jit") - 1) == 0) + { + engine_types |= ENGINE_THOMPSON_JIT; + + } else if (strncmp(argv[i], "--thompson", sizeof("--thompson") - 1) + == 0) + { + engine_types |= ENGINE_THOMPSON; + + } else if (strncmp(argv[i], "--pike", sizeof("--pike") - 1) + == 0) + { + engine_types |= ENGINE_PIKE; + + } else if (strncmp(argv[i], "-i", 2) == 0) { + flags |= SRE_REGEX_CASELESS; + + } else { + fprintf(stderr, "unknown option: %s\n", argv[i]); + exit(1); + } + } + + if (engine_types == 0) { + fprintf(stderr, "No engine specified.\n"); + exit(1); + } + + if (argc - i != 2) { + usage(1); + } + + ppool = sre_create_pool(1024); + if (ppool == NULL) { + return 2; + } + + re = sre_regex_parse(ppool, (sre_char *) argv[i++], &ncaps, flags, &err_offset); + if (re == NULL) { + if (err_offset >= 0) { + fprintf(stderr, "[error] syntax error at pos %lld\n", + (long long) err_offset); + } + + fprintf(stderr, "unknown error\n"); + return 2; + } + + cpool = sre_create_pool(1024); + if (cpool == NULL) { + return 2; + } + + prog = sre_regex_compile(cpool, re); + if (prog == NULL) { + fprintf(stderr, "failed to compile the regex.\n"); + return 2; + } + + sre_destroy_pool(ppool); + ppool = NULL; + re = NULL; + + errno = 0; + + f = fopen(argv[i], "rb"); + if (f == NULL) { + perror("open file"); + return 1; + } + + if (fseek(f, 0L, SEEK_END) != 0) { + perror("seek to file end"); + return 1; + } + + rc = ftell(f); + if (rc == -1) { + perror("get file offset by ftell"); + return 1; + } + + len = (size_t) rc; + + if (fseek(f, 0L, SEEK_SET) != 0) { + perror("seek to file beginning"); + return 1; + } + + input = malloc(len); + if (input == NULL) { + fprintf(stderr, "failed to allocate %ld bytes.\n", len); + return 1; + } + + if (fread(input, 1, len, f) < len) { + if (feof(f)) { + fprintf(stderr, "file truncated.\n"); + return 1; + + } else { + perror("read file"); + } + } + + if (fclose(f) != 0) { + perror("close file"); + return 1; + } + + run_engines(prog, engine_types, ncaps, input, len); + + free(input); + sre_destroy_pool(cpool); + return 0; +} + + +static void +run_engines(sre_program_t *prog, unsigned engine_types, sre_uint_t ncaps, + sre_char *input, size_t len) +{ + sre_uint_t i; + sre_int_t rc; + sre_int_t *ovector; + size_t ovecsize; + sre_pool_t *pool; + struct timespec begin, end; + double elapsed; + + sre_vm_thompson_ctx_t *tctx; + sre_vm_pike_ctx_t *pctx; + sre_vm_thompson_code_t *tcode; + sre_vm_thompson_exec_pt texec; + + pool = sre_create_pool(1024); + if (pool == NULL) { + exit(2); + } + + if (engine_types & ENGINE_THOMPSON) { + + printf("sregex Thompson "); + + tctx = sre_vm_thompson_create_ctx(pool, prog); + if (tctx == NULL) { + alloc_error(); + } + + TIMER_START + + rc = sre_vm_thompson_exec(tctx, input, len, 1); + + TIMER_STOP + + switch (rc) { + case SRE_OK: + printf("match"); + break; + + case SRE_DECLINED: + printf("no match"); + break; + + case SRE_AGAIN: + printf("again"); + break; + + case SRE_ERROR: + printf("error"); + break; + + default: + printf("bad retval: %lx\n", (unsigned long) rc); + exit(2); + } + + printf(": %.02lf ms elapsed.\n", elapsed); + + sre_reset_pool(pool); + } + + if (engine_types & ENGINE_THOMPSON_JIT) { + rc = sre_vm_thompson_jit_compile(pool, prog, &tcode); + + if (rc == SRE_DECLINED) { + printf("sregex thompson JIT disabled\n"); + exit(2); + } + + if (rc != SRE_OK) { + fprintf(stderr, "failed to run thompson jit compile: %ld\n", (long) rc); + exit(2); + } + + texec = sre_vm_thompson_jit_get_handler(tcode); + if (texec == NULL) { + fprintf(stderr, "failed to get Thompson JIT handler.\n"); + exit(2); + } + + printf("sregex Thompson JIT "); + + tctx = sre_vm_thompson_jit_create_ctx(pool, prog); + if (tctx == NULL) { + alloc_error(); + } + + TIMER_START + + rc = run_jitted_thompson(texec, tctx, input, len, 1); + + TIMER_STOP + + switch (rc) { + case SRE_OK: + printf("match"); + break; + + case SRE_DECLINED: + printf("no match"); + break; + + case SRE_AGAIN: + printf("again"); + break; + + case SRE_ERROR: + printf("error"); + break; + + default: + printf("bad retval: %lx\n", (unsigned long) rc); + exit(2); + } + + printf(": %.02lf ms elapsed.\n", elapsed); + + sre_reset_pool(pool); + } + + if (engine_types & ENGINE_PIKE) { + ovecsize = 2 * (ncaps + 1) * sizeof(sre_int_t); + ovector = malloc(ovecsize); + if (ovector == NULL) { + alloc_error(); + } + + printf("sregex Pike "); + + pctx = sre_vm_pike_create_ctx(pool, prog, ovector, ovecsize); + if (pctx == NULL) { + alloc_error(); + } + + TIMER_START + + rc = sre_vm_pike_exec(pctx, input, len, 1 /* eof */, NULL); + + TIMER_STOP + + switch (rc) { + case SRE_OK: + printf("match"); + + for (i = 0; i < 2 * (ncaps + 1); i += 2) { + printf(" (%ld, %ld)", (long) ovector[i], (long) ovector[i + 1]); + } + + break; + + case SRE_AGAIN: + printf("again"); + break; + + case SRE_DECLINED: + printf("no match"); + break; + + case SRE_ERROR: + printf("error"); + break; + + default: + assert(rc); + break; + } + + printf(": %.02lf ms elapsed.\n", elapsed); + + free(ovector); + sre_reset_pool(pool); + } + + sre_destroy_pool(pool); +} + + +static void +alloc_error(void) +{ + fprintf(stderr, "failed to allocate memory"); + exit(2); +} + + +static void +usage(int rc) +{ + fprintf(stderr, "usage: sregex [options] \n" + "options:\n" + " -i use case insensitive matching\n" + " --pike use the Pike VM interpreter\n" + " --thompson use the Thompson VM interpreter\n" + " --thompson-jit use the Thompson VM JIT compiler\n"); + exit(rc); +} + + +sre_int_t +run_jitted_thompson(sre_vm_thompson_exec_pt handler, sre_vm_thompson_ctx_t *ctx, + sre_char *input, size_t size, unsigned eof) +{ + return handler(ctx, input, size, eof); +} diff --git a/lib/sregex/dynasm/dasm_arm.h b/lib/sregex/dynasm/dasm_arm.h new file mode 100644 index 0000000..d49ecae --- /dev/null +++ b/lib/sregex/dynasm/dasm_arm.h @@ -0,0 +1,455 @@ +/* +** DynASM ARM encoding engine. +** Copyright (C) 2005-2012 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "arm" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. */ +enum { + DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, + /* The following actions need a buffer position. */ + DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, + /* The following actions also have an argument. */ + DASM_REL_PC, DASM_LABEL_PC, + DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, + DASM__MAX +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_REL 0x15000000 +#define DASM_S_UNDEF_LG 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned int *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList)actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +static int dasm_imm12(unsigned int n) +{ + int i; + for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) + if (n <= 255) return (int)(n + (i << 8)); + return -1; +} + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + if (action >= DASM__MAX) { + ofs += 4; + } else { + int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; + switch (action) { + case DASM_STOP: goto stop; + case DASM_SECTION: + n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); + D->section = &D->sections[n]; goto stop; + case DASM_ESC: p++; ofs += 4; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; + case DASM_REL_LG: + n = (ins & 2047) - 10; pl = D->lglabels + n; + if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + pl += 10; n = *pl; + if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + pos++; + break; + case DASM_LABEL_LG: + pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; + case DASM_LABEL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; + } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_IMM: + case DASM_IMM16: +#ifdef DASM_CHECKS + CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); + if ((ins & 0x8000)) + CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); + else + CK((n>>((ins>>5)&31)) == 0, RANGE_I); +#endif + b[pos++] = n; + break; + case DASM_IMMV8: + CK((n & 3) == 0, RANGE_I); + n >>= 2; + case DASM_IMML8: + case DASM_IMML12: + CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : + (((-n)>>((ins>>5)&31)) == 0), RANGE_I); + b[pos++] = n; + break; + case DASM_IMM12: + CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); + b[pos++] = n; + break; + } + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} +#undef CK + +/* Pass 2: Link sections, shrink aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t *szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) return D->status; + { + int pc; + for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: p++; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; + case DASM_REL_LG: case DASM_REL_PC: pos++; break; + case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; + case DASM_IMM: case DASM_IMM12: case DASM_IMM16: + case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; + } + } + stop: (void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) +#else +#define CK(x, st) ((void)0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + char *base = (char *)buffer; + unsigned int *cp = (unsigned int *)buffer; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: *cp++ = *p++; break; + case DASM_REL_EXT: + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); + goto patchrel; + case DASM_ALIGN: + ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; + break; + case DASM_REL_LG: + CK(n >= 0, UNDEF_LG); + case DASM_REL_PC: + CK(n >= 0, UNDEF_PC); + n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; + patchrel: + if ((ins & 0x800) == 0) { + CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); + cp[-1] |= ((n >> 2) & 0x00ffffff); + } else if ((ins & 0x1000)) { + CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); + goto patchimml8; + } else if ((ins & 0x2000) == 0) { + CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); + goto patchimml; + } else { + CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); + n >>= 2; + goto patchimml; + } + break; + case DASM_LABEL_LG: + ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); + break; + case DASM_LABEL_PC: break; + case DASM_IMM: + cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); + break; + case DASM_IMM12: + cp[-1] |= dasm_imm12((unsigned int)n); + break; + case DASM_IMM16: + cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); + break; + case DASM_IMML8: patchimml8: + cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : + ((-n & 0x0f) | ((-n & 0xf0) << 4)); + break; + case DASM_IMML12: case DASM_IMMV8: patchimml: + cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); + break; + default: *cp++ = ins; break; + } + } + stop: (void)0; + } + } + + if (base + D->codesize != (char *)cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} +#undef CK + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc*sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) return *DASM_POS2PTR(D, -pos); + if (pos > 0) return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC|(D->section-D->sections); + return D->status; +} +#endif + diff --git a/lib/sregex/dynasm/dasm_arm.lua b/lib/sregex/dynasm/dasm_arm.lua new file mode 100644 index 0000000..8984aab --- /dev/null +++ b/lib/sregex/dynasm/dasm_arm.lua @@ -0,0 +1,1122 @@ +------------------------------------------------------------------------------ +-- DynASM ARM module. +-- +-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ + +-- Module information: +local _info = { + arch = "arm", + description = "DynASM ARM module", + version = "1.3.0", + vernum = 10300, + release = "2011-05-05", + author = "Mike Pall", + license = "MIT", +} + +-- Exported glue functions for the arch-specific module. +local _M = { _info = _info } + +-- Cache library functions. +local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs +local assert, setmetatable, rawget = assert, setmetatable, rawget +local _s = string +local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char +local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub +local concat, sort, insert = table.concat, table.sort, table.insert +local bit = bit or require("bit") +local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift +local ror, tohex = bit.ror, bit.tohex + +-- Inherited tables and callbacks. +local g_opt, g_arch +local wline, werror, wfatal, wwarn + +-- Action name list. +-- CHECK: Keep this in sync with the C code! +local action_names = { + "STOP", "SECTION", "ESC", "REL_EXT", + "ALIGN", "REL_LG", "LABEL_LG", + "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8", +} + +-- Maximum number of section buffer positions for dasm_put(). +-- CHECK: Keep this in sync with the C code! +local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. + +-- Action name -> action number. +local map_action = {} +for n,name in ipairs(action_names) do + map_action[name] = n-1 +end + +-- Action list buffer. +local actlist = {} + +-- Argument list for next dasm_put(). Start with offset 0 into action list. +local actargs = { 0 } + +-- Current number of section buffer positions for dasm_put(). +local secpos = 1 + +------------------------------------------------------------------------------ + +-- Dump action names and numbers. +local function dumpactions(out) + out:write("DynASM encoding engine action codes:\n") + for n,name in ipairs(action_names) do + local num = map_action[name] + out:write(format(" %-10s %02X %d\n", name, num, num)) + end + out:write("\n") +end + +-- Write action list buffer as a huge static C array. +local function writeactions(out, name) + local nn = #actlist + if nn == 0 then nn = 1; actlist[0] = map_action.STOP end + out:write("static const unsigned int ", name, "[", nn, "] = {\n") + for i = 1,nn-1 do + assert(out:write("0x", tohex(actlist[i]), ",\n")) + end + assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) +end + +------------------------------------------------------------------------------ + +-- Add word to action list. +local function wputxw(n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[#actlist+1] = n +end + +-- Add action to list with optional arg. Advance buffer pos, too. +local function waction(action, val, a, num) + local w = assert(map_action[action], "bad action name `"..action.."'") + wputxw(w * 0x10000 + (val or 0)) + if a then actargs[#actargs+1] = a end + if a or num then secpos = secpos + (num or 1) end +end + +-- Flush action list (intervening C code or buffer pos overflow). +local function wflush(term) + if #actlist == actargs[1] then return end -- Nothing to flush. + if not term then waction("STOP") end -- Terminate action list. + wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) + actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). + secpos = 1 -- The actionlist offset occupies a buffer position, too. +end + +-- Put escaped word. +local function wputw(n) + if n <= 0x000fffff then waction("ESC") end + wputxw(n) +end + +-- Reserve position for word. +local function wpos() + local pos = #actlist+1 + actlist[pos] = "" + return pos +end + +-- Store word to reserved position. +local function wputpos(pos, n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + if n <= 0x000fffff then + insert(actlist, pos+1, n) + n = map_action.ESC * 0x10000 + end + actlist[pos] = n +end + +------------------------------------------------------------------------------ + +-- Global label name -> global label number. With auto assignment on 1st use. +local next_global = 20 +local map_global = setmetatable({}, { __index = function(t, name) + if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end + local n = next_global + if n > 2047 then werror("too many global labels") end + next_global = n + 1 + t[name] = n + return n +end}) + +-- Dump global labels. +local function dumpglobals(out, lvl) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("Global labels:\n") + for i=20,next_global-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write global label enum. +local function writeglobals(out, prefix) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("enum {\n") + for i=20,next_global-1 do + out:write(" ", prefix, t[i], ",\n") + end + out:write(" ", prefix, "_MAX\n};\n") +end + +-- Write global label names. +local function writeglobalnames(out, name) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=20,next_global-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Extern label name -> extern label number. With auto assignment on 1st use. +local next_extern = 0 +local map_extern_ = {} +local map_extern = setmetatable({}, { __index = function(t, name) + -- No restrictions on the name for now. + local n = next_extern + if n > 2047 then werror("too many extern labels") end + next_extern = n + 1 + t[name] = n + map_extern_[n] = name + return n +end}) + +-- Dump extern labels. +local function dumpexterns(out, lvl) + out:write("Extern labels:\n") + for i=0,next_extern-1 do + out:write(format(" %s\n", map_extern_[i])) + end + out:write("\n") +end + +-- Write extern label names. +local function writeexternnames(out, name) + out:write("static const char *const ", name, "[] = {\n") + for i=0,next_extern-1 do + out:write(" \"", map_extern_[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Arch-specific maps. + +-- Ext. register name -> int. name. +local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } + +-- Int. register name -> ext. name. +local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } + +local map_type = {} -- Type name -> { ctype, reg } +local ctypenum = 0 -- Type number (for Dt... macros). + +-- Reverse defines for registers. +function _M.revdef(s) + return map_reg_rev[s] or s +end + +local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } + +local map_cond = { + eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, + hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, + hs = 2, lo = 3, +} + +------------------------------------------------------------------------------ + +-- Template strings for ARM instructions. +local map_op = { + -- Basic data processing instructions. + and_3 = "e0000000DNPs", + eor_3 = "e0200000DNPs", + sub_3 = "e0400000DNPs", + rsb_3 = "e0600000DNPs", + add_3 = "e0800000DNPs", + adc_3 = "e0a00000DNPs", + sbc_3 = "e0c00000DNPs", + rsc_3 = "e0e00000DNPs", + tst_2 = "e1100000NP", + teq_2 = "e1300000NP", + cmp_2 = "e1500000NP", + cmn_2 = "e1700000NP", + orr_3 = "e1800000DNPs", + mov_2 = "e1a00000DPs", + bic_3 = "e1c00000DNPs", + mvn_2 = "e1e00000DPs", + + and_4 = "e0000000DNMps", + eor_4 = "e0200000DNMps", + sub_4 = "e0400000DNMps", + rsb_4 = "e0600000DNMps", + add_4 = "e0800000DNMps", + adc_4 = "e0a00000DNMps", + sbc_4 = "e0c00000DNMps", + rsc_4 = "e0e00000DNMps", + tst_3 = "e1100000NMp", + teq_3 = "e1300000NMp", + cmp_3 = "e1500000NMp", + cmn_3 = "e1700000NMp", + orr_4 = "e1800000DNMps", + mov_3 = "e1a00000DMps", + bic_4 = "e1c00000DNMps", + mvn_3 = "e1e00000DMps", + + lsl_3 = "e1a00000DMws", + lsr_3 = "e1a00020DMws", + asr_3 = "e1a00040DMws", + ror_3 = "e1a00060DMws", + rrx_2 = "e1a00060DMs", + + -- Multiply and multiply-accumulate. + mul_3 = "e0000090NMSs", + mla_4 = "e0200090NMSDs", + umaal_4 = "e0400090DNMSs", -- v6 + mls_4 = "e0600090DNMSs", -- v6T2 + umull_4 = "e0800090DNMSs", + umlal_4 = "e0a00090DNMSs", + smull_4 = "e0c00090DNMSs", + smlal_4 = "e0e00090DNMSs", + + -- Halfword multiply and multiply-accumulate. + smlabb_4 = "e1000080NMSD", -- v5TE + smlatb_4 = "e10000a0NMSD", -- v5TE + smlabt_4 = "e10000c0NMSD", -- v5TE + smlatt_4 = "e10000e0NMSD", -- v5TE + smlawb_4 = "e1200080NMSD", -- v5TE + smulwb_3 = "e12000a0NMS", -- v5TE + smlawt_4 = "e12000c0NMSD", -- v5TE + smulwt_3 = "e12000e0NMS", -- v5TE + smlalbb_4 = "e1400080NMSD", -- v5TE + smlaltb_4 = "e14000a0NMSD", -- v5TE + smlalbt_4 = "e14000c0NMSD", -- v5TE + smlaltt_4 = "e14000e0NMSD", -- v5TE + smulbb_3 = "e1600080NMS", -- v5TE + smultb_3 = "e16000a0NMS", -- v5TE + smulbt_3 = "e16000c0NMS", -- v5TE + smultt_3 = "e16000e0NMS", -- v5TE + + -- Miscellaneous data processing instructions. + clz_2 = "e16f0f10DM", -- v5T + rev_2 = "e6bf0f30DM", -- v6 + rev16_2 = "e6bf0fb0DM", -- v6 + revsh_2 = "e6ff0fb0DM", -- v6 + sel_3 = "e6800fb0DNM", -- v6 + usad8_3 = "e780f010NMS", -- v6 + usada8_4 = "e7800010NMSD", -- v6 + rbit_2 = "e6ff0f30DM", -- v6T2 + movw_2 = "e3000000DW", -- v6T2 + movt_2 = "e3400000DW", -- v6T2 + -- Note: the X encodes width-1, not width. + sbfx_4 = "e7a00050DMvX", -- v6T2 + ubfx_4 = "e7e00050DMvX", -- v6T2 + -- Note: the X encodes the msb field, not the width. + bfc_3 = "e7c0001fDvX", -- v6T2 + bfi_4 = "e7c00010DMvX", -- v6T2 + + -- Packing and unpacking instructions. + pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 + pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 + sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 + sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 + sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 + sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 + sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 + sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 + uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 + uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 + uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 + uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 + uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 + uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 + + -- Saturating instructions. + qadd_3 = "e1000050DMN", -- v5TE + qsub_3 = "e1200050DMN", -- v5TE + qdadd_3 = "e1400050DMN", -- v5TE + qdsub_3 = "e1600050DMN", -- v5TE + -- Note: the X for ssat* encodes sat_imm-1, not sat_imm. + ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 + usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 + ssat16_3 = "e6a00f30DXM", -- v6 + usat16_3 = "e6e00f30DXM", -- v6 + + -- Parallel addition and subtraction. + sadd16_3 = "e6100f10DNM", -- v6 + sasx_3 = "e6100f30DNM", -- v6 + ssax_3 = "e6100f50DNM", -- v6 + ssub16_3 = "e6100f70DNM", -- v6 + sadd8_3 = "e6100f90DNM", -- v6 + ssub8_3 = "e6100ff0DNM", -- v6 + qadd16_3 = "e6200f10DNM", -- v6 + qasx_3 = "e6200f30DNM", -- v6 + qsax_3 = "e6200f50DNM", -- v6 + qsub16_3 = "e6200f70DNM", -- v6 + qadd8_3 = "e6200f90DNM", -- v6 + qsub8_3 = "e6200ff0DNM", -- v6 + shadd16_3 = "e6300f10DNM", -- v6 + shasx_3 = "e6300f30DNM", -- v6 + shsax_3 = "e6300f50DNM", -- v6 + shsub16_3 = "e6300f70DNM", -- v6 + shadd8_3 = "e6300f90DNM", -- v6 + shsub8_3 = "e6300ff0DNM", -- v6 + uadd16_3 = "e6500f10DNM", -- v6 + uasx_3 = "e6500f30DNM", -- v6 + usax_3 = "e6500f50DNM", -- v6 + usub16_3 = "e6500f70DNM", -- v6 + uadd8_3 = "e6500f90DNM", -- v6 + usub8_3 = "e6500ff0DNM", -- v6 + uqadd16_3 = "e6600f10DNM", -- v6 + uqasx_3 = "e6600f30DNM", -- v6 + uqsax_3 = "e6600f50DNM", -- v6 + uqsub16_3 = "e6600f70DNM", -- v6 + uqadd8_3 = "e6600f90DNM", -- v6 + uqsub8_3 = "e6600ff0DNM", -- v6 + uhadd16_3 = "e6700f10DNM", -- v6 + uhasx_3 = "e6700f30DNM", -- v6 + uhsax_3 = "e6700f50DNM", -- v6 + uhsub16_3 = "e6700f70DNM", -- v6 + uhadd8_3 = "e6700f90DNM", -- v6 + uhsub8_3 = "e6700ff0DNM", -- v6 + + -- Load/store instructions. + str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", + strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", + ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", + ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", + strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", + ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", + ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE + ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", + strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE + ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", + + ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR", + ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR", + ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR", + ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR", + stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR", + stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR", + stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR", + stmib_2 = "e9800000oR", stmed_2 = "e9800000oR", + pop_1 = "e8bd0000R", push_1 = "e92d0000R", + + -- Branch instructions. + b_1 = "ea000000B", + bl_1 = "eb000000B", + blx_1 = "e12fff30C", + bx_1 = "e12fff10M", + + -- Miscellaneous instructions. + nop_0 = "e1a00000", + mrs_1 = "e10f0000D", + bkpt_1 = "e1200070K", -- v5T + svc_1 = "ef000000T", swi_1 = "ef000000T", + ud_0 = "e7f001f0", + + -- VFP instructions. + ["vadd.f32_3"] = "ee300a00dnm", + ["vadd.f64_3"] = "ee300b00Gdnm", + ["vsub.f32_3"] = "ee300a40dnm", + ["vsub.f64_3"] = "ee300b40Gdnm", + ["vmul.f32_3"] = "ee200a00dnm", + ["vmul.f64_3"] = "ee200b00Gdnm", + ["vnmul.f32_3"] = "ee200a40dnm", + ["vnmul.f64_3"] = "ee200b40Gdnm", + ["vmla.f32_3"] = "ee000a00dnm", + ["vmla.f64_3"] = "ee000b00Gdnm", + ["vmls.f32_3"] = "ee000a40dnm", + ["vmls.f64_3"] = "ee000b40Gdnm", + ["vnmla.f32_3"] = "ee100a40dnm", + ["vnmla.f64_3"] = "ee100b40Gdnm", + ["vnmls.f32_3"] = "ee100a00dnm", + ["vnmls.f64_3"] = "ee100b00Gdnm", + ["vdiv.f32_3"] = "ee800a00dnm", + ["vdiv.f64_3"] = "ee800b00Gdnm", + + ["vabs.f32_2"] = "eeb00ac0dm", + ["vabs.f64_2"] = "eeb00bc0Gdm", + ["vneg.f32_2"] = "eeb10a40dm", + ["vneg.f64_2"] = "eeb10b40Gdm", + ["vsqrt.f32_2"] = "eeb10ac0dm", + ["vsqrt.f64_2"] = "eeb10bc0Gdm", + ["vcmp.f32_2"] = "eeb40a40dm", + ["vcmp.f64_2"] = "eeb40b40Gdm", + ["vcmpe.f32_2"] = "eeb40ac0dm", + ["vcmpe.f64_2"] = "eeb40bc0Gdm", + ["vcmpz.f32_1"] = "eeb50a40d", + ["vcmpz.f64_1"] = "eeb50b40Gd", + ["vcmpze.f32_1"] = "eeb50ac0d", + ["vcmpze.f64_1"] = "eeb50bc0Gd", + + vldr_2 = "ed100a00dl|ed100b00Gdl", + vstr_2 = "ed000a00dl|ed000b00Gdl", + vldm_2 = "ec900a00or", + vldmia_2 = "ec900a00or", + vldmdb_2 = "ed100a00or", + vpop_1 = "ecbd0a00r", + vstm_2 = "ec800a00or", + vstmia_2 = "ec800a00or", + vstmdb_2 = "ed000a00or", + vpush_1 = "ed2d0a00r", + + ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only + ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only + vmov_2 = "ee100a10Dn|ee000a10nD", + vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN", + + vmrs_0 = "eef1fa10", + vmrs_1 = "eef10a10D", + vmsr_1 = "eee10a10D", + + ["vcvt.s32.f32_2"] = "eebd0ac0dm", + ["vcvt.s32.f64_2"] = "eebd0bc0dGm", + ["vcvt.u32.f32_2"] = "eebc0ac0dm", + ["vcvt.u32.f64_2"] = "eebc0bc0dGm", + ["vcvtr.s32.f32_2"] = "eebd0a40dm", + ["vcvtr.s32.f64_2"] = "eebd0b40dGm", + ["vcvtr.u32.f32_2"] = "eebc0a40dm", + ["vcvtr.u32.f64_2"] = "eebc0b40dGm", + ["vcvt.f32.s32_2"] = "eeb80ac0dm", + ["vcvt.f64.s32_2"] = "eeb80bc0GdFm", + ["vcvt.f32.u32_2"] = "eeb80a40dm", + ["vcvt.f64.u32_2"] = "eeb80b40GdFm", + ["vcvt.f32.f64_2"] = "eeb70bc0dGm", + ["vcvt.f64.f32_2"] = "eeb70ac0GdFm", + + -- VFPv4 only: + ["vfma.f32_3"] = "eea00a00dnm", + ["vfma.f64_3"] = "eea00b00Gdnm", + ["vfms.f32_3"] = "eea00a40dnm", + ["vfms.f64_3"] = "eea00b40Gdnm", + ["vfnma.f32_3"] = "ee900a40dnm", + ["vfnma.f64_3"] = "ee900b40Gdnm", + ["vfnms.f32_3"] = "ee900a00dnm", + ["vfnms.f64_3"] = "ee900b00Gdnm", + + -- NYI: Advanced SIMD instructions. + + -- NYI: I have no need for these instructions right now: + -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh + -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe + -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb + -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 +} + +-- Add mnemonics for "s" variants. +do + local t = {} + for k,v in pairs(map_op) do + if sub(v, -1) == "s" then + local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) + t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 + end + end + for k,v in pairs(t) do + map_op[k] = v + end +end + +------------------------------------------------------------------------------ + +local function parse_gpr(expr) + local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + if not reg then + werror("type `"..(tname or expr).."' needs a register override") + end + expr = reg + end + local r = match(expr, "^r(1?[0-9])$") + if r then + r = tonumber(r) + if r <= 15 then return r, tp end + end + werror("bad register name `"..expr.."'") +end + +local function parse_gpr_pm(expr) + local pm, expr2 = match(expr, "^([+-]?)(.*)$") + return parse_gpr(expr2), (pm == "-") +end + +local function parse_vr(expr, tp) + local t, r = match(expr, "^([sd])([0-9]+)$") + if t == tp then + r = tonumber(r) + if r <= 31 then + if t == "s" then return shr(r, 1), band(r, 1) end + return band(r, 15), shr(r, 4) + end + end + werror("bad register name `"..expr.."'") +end + +local function parse_reglist(reglist) + reglist = match(reglist, "^{%s*([^}]*)}$") + if not reglist then werror("register list expected") end + local rr = 0 + for p in gmatch(reglist..",", "%s*([^,]*),") do + local rbit = shl(1, parse_gpr(gsub(p, "%s+$", ""))) + if band(rr, rbit) ~= 0 then + werror("duplicate register `"..p.."'") + end + rr = rr + rbit + end + return rr +end + +local function parse_vrlist(reglist) + local ta, ra, tb, rb = match(reglist, + "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$") + ra, rb = tonumber(ra), tonumber(rb) + if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then + local nr = rb+1 - ra + if ta == "s" then + return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr + else + return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100 + end + end + werror("register list expected") +end + +local function parse_imm(imm, bits, shift, scale, signed) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = tonumber(imm) + if n then + local m = sar(n, scale) + if shl(m, scale) == n then + if signed then + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end + else + if sar(m, bits) == 0 then return shl(m, shift) end + end + end + werror("out of range immediate `"..imm.."'") + else + waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) + return 0 + end +end + +local function parse_imm12(imm) + local n = tonumber(imm) + if n then + local m = band(n) + for i=0,-15,-1 do + if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end + m = ror(m, 2) + end + werror("out of range immediate `"..imm.."'") + else + waction("IMM12", 0, imm) + return 0 + end +end + +local function parse_imm16(imm) + imm = match(imm, "^#(.*)$") + if not imm then werror("expected immediate operand") end + local n = tonumber(imm) + if n then + if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end + werror("out of range immediate `"..imm.."'") + else + waction("IMM16", 32*16, imm) + return 0 + end +end + +local function parse_imm_load(imm, ext) + local n = tonumber(imm) + if n then + if ext then + if n >= -255 and n <= 255 then + local up = 0x00800000 + if n < 0 then n = -n; up = 0 end + return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up + end + else + if n >= -4095 and n <= 4095 then + if n >= 0 then return n+0x00800000 end + return -n + end + end + werror("out of range immediate `"..imm.."'") + else + waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm) + return 0 + end +end + +local function parse_shift(shift, gprok) + if shift == "rrx" then + return 3 * 32 + else + local s, s2 = match(shift, "^(%S+)%s*(.*)$") + s = map_shift[s] + if not s then werror("expected shift operand") end + if sub(s2, 1, 1) == "#" then + return parse_imm(s2, 5, 7, 0, false) + shl(s, 5) + else + if not gprok then werror("expected immediate shift operand") end + return shl(parse_gpr(s2), 8) + shl(s, 5) + 16 + end + end +end + +local function parse_label(label, def) + local prefix = sub(label, 1, 2) + -- =>label (pc label reference) + if prefix == "=>" then + return "PC", 0, sub(label, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "LG", map_global[sub(label, 3)] + end + if def then + -- [1-9] (local label definition) + if match(label, "^[1-9]$") then + return "LG", 10+tonumber(label) + end + else + -- [<>][1-9] (local label reference) + local dir, lnum = match(label, "^([<>])([1-9])$") + if dir then -- Fwd: 1-9, Bkwd: 11-19. + return "LG", lnum + (dir == ">" and 0 or 10) + end + -- extern label (extern label reference) + local extname = match(label, "^extern%s+(%S+)$") + if extname then + return "EXT", map_extern[extname] + end + end + werror("bad label `"..label.."'") +end + +local function parse_load(params, nparams, n, op) + local oplo = band(op, 255) + local ext, ldrd = (oplo ~= 0), (oplo == 208) + local d + if (ldrd or oplo == 240) then + d = band(shr(op, 12), 15) + if band(d, 1) ~= 0 then werror("odd destination register") end + end + local pn = params[n] + local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") + local p2 = params[n+1] + if not p1 then + if not p2 then + if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then + local mode, n, s = parse_label(pn, false) + waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) + return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) + end + local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local d, tp = parse_gpr(reg) + if tp then + waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), + format(tp.ctypefmt, tailr)) + return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0) + end + end + end + werror("expected address operand") + end + if wb == "!" then op = op + 0x00200000 end + if p2 then + if wb == "!" then werror("bad use of '!'") end + local p3 = params[n+2] + op = op + shl(parse_gpr(p1), 16) + local imm = match(p2, "^#(.*)$") + if imm then + local m = parse_imm_load(imm, ext) + if p3 then werror("too many parameters") end + op = op + m + (ext and 0x00400000 or 0) + else + local m, neg = parse_gpr_pm(p2) + if ldrd and (m == d or m-1 == d) then werror("register conflict") end + op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) + if p3 then op = op + parse_shift(p3) end + end + else + local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") + op = op + shl(parse_gpr(p1a), 16) + 0x01000000 + if p2 ~= "" then + local imm = match(p2, "^,%s*#(.*)$") + if imm then + local m = parse_imm_load(imm, ext) + op = op + m + (ext and 0x00400000 or 0) + else + local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") + local m, neg = parse_gpr_pm(p2a) + if ldrd and (m == d or m-1 == d) then werror("register conflict") end + op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) + if p3 ~= "" then + if ext then werror("too many parameters") end + op = op + parse_shift(p3) + end + end + else + if wb == "!" then werror("bad use of '!'") end + op = op + (ext and 0x00c00000 or 0x00800000) + end + end + return op +end + +local function parse_vload(q) + local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$") + if reg then + local d = shl(parse_gpr(reg), 16) + if imm == "" then return d end + imm = match(imm, "^,%s*#(.*)$") + if imm then + local n = tonumber(imm) + if n then + if n >= -1020 and n <= 1020 and n%4 == 0 then + return d + (n >= 0 and n/4+0x00800000 or -n/4) + end + werror("out of range immediate `"..imm.."'") + else + waction("IMMV8", 32768 + 32*8, imm) + return d + end + end + else + if match(q, "^[<>=%-]") or match(q, "^extern%s+") then + local mode, n, s = parse_label(q, false) + waction("REL_"..mode, n + 0x2800, s, 1) + return 15 * 65536 + end + local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local d, tp = parse_gpr(reg) + if tp then + waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr)) + return shl(d, 16) + end + end + end + werror("expected address operand") +end + +------------------------------------------------------------------------------ + +-- Handle opcodes defined with template strings. +local function parse_template(params, template, nparams, pos) + local op = tonumber(sub(template, 1, 8), 16) + local n = 1 + local vr = "s" + + -- Process each character. + for p in gmatch(sub(template, 9), ".") do + local q = params[n] + if p == "D" then + op = op + shl(parse_gpr(q), 12); n = n + 1 + elseif p == "N" then + op = op + shl(parse_gpr(q), 16); n = n + 1 + elseif p == "S" then + op = op + shl(parse_gpr(q), 8); n = n + 1 + elseif p == "M" then + op = op + parse_gpr(q); n = n + 1 + elseif p == "d" then + local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1 + elseif p == "n" then + local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1 + elseif p == "m" then + local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1 + elseif p == "P" then + local imm = match(q, "^#(.*)$") + if imm then + op = op + parse_imm12(imm) + 0x02000000 + else + op = op + parse_gpr(q) + end + n = n + 1 + elseif p == "p" then + op = op + parse_shift(q, true); n = n + 1 + elseif p == "L" then + op = parse_load(params, nparams, n, op) + elseif p == "l" then + op = op + parse_vload(q) + elseif p == "B" then + local mode, n, s = parse_label(q, false) + waction("REL_"..mode, n, s, 1) + elseif p == "C" then -- blx gpr vs. blx label. + if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then + op = op + parse_gpr(q) + else + if op < 0xe0000000 then werror("unconditional instruction") end + local mode, n, s = parse_label(q, false) + waction("REL_"..mode, n, s, 1) + op = 0xfa000000 + end + elseif p == "F" then + vr = "s" + elseif p == "G" then + vr = "d" + elseif p == "o" then + local r, wb = match(q, "^([^!]*)(!?)$") + op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0) + n = n + 1 + elseif p == "R" then + op = op + parse_reglist(q); n = n + 1 + elseif p == "r" then + op = op + parse_vrlist(q); n = n + 1 + elseif p == "W" then + op = op + parse_imm16(q); n = n + 1 + elseif p == "v" then + op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 + elseif p == "w" then + local imm = match(q, "^#(.*)$") + if imm then + op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 + else + op = op + shl(parse_gpr(q), 8) + 16 + end + elseif p == "X" then + op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 + elseif p == "Y" then + local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 + if not imm or shr(imm, 8) ~= 0 then + werror("bad immediate operand") + end + op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f) + elseif p == "K" then + local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 + if not imm or shr(imm, 16) ~= 0 then + werror("bad immediate operand") + end + op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f) + elseif p == "T" then + op = op + parse_imm(q, 24, 0, 0, false); n = n + 1 + elseif p == "s" then + -- Ignored. + else + assert(false) + end + end + wputpos(pos, op) +end + +map_op[".template__"] = function(params, template, nparams) + if not params then return sub(template, 9) end + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 3 positions. + if secpos+3 > maxsecpos then wflush() end + local pos = wpos() + local apos, spos = #actargs, secpos + + local ok, err + for t in gmatch(template, "[^|]+") do + ok, err = pcall(parse_template, params, t, nparams, pos) + if ok then return end + secpos = spos + actargs[apos+1] = nil + actargs[apos+2] = nil + actargs[apos+3] = nil + end + error(err, 0) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode to mark the position where the action list is to be emitted. +map_op[".actionlist_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeactions(out, name) end) +end + +-- Pseudo-opcode to mark the position where the global enum is to be emitted. +map_op[".globals_1"] = function(params) + if not params then return "prefix" end + local prefix = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobals(out, prefix) end) +end + +-- Pseudo-opcode to mark the position where the global names are to be emitted. +map_op[".globalnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobalnames(out, name) end) +end + +-- Pseudo-opcode to mark the position where the extern names are to be emitted. +map_op[".externnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeexternnames(out, name) end) +end + +------------------------------------------------------------------------------ + +-- Label pseudo-opcode (converted from trailing colon form). +map_op[".label_1"] = function(params) + if not params then return "[1-9] | ->global | =>pcexpr" end + if secpos+1 > maxsecpos then wflush() end + local mode, n, s = parse_label(params[1], true) + if mode == "EXT" then werror("bad label definition") end + waction("LABEL_"..mode, n, s, 1) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcodes for data storage. +map_op[".long_*"] = function(params) + if not params then return "imm..." end + for _,p in ipairs(params) do + local n = tonumber(p) + if not n then werror("bad immediate `"..p.."'") end + if n < 0 then n = n + 2^32 end + wputw(n) + if secpos+2 > maxsecpos then wflush() end + end +end + +-- Alignment pseudo-opcode. +map_op[".align_1"] = function(params) + if not params then return "numpow2" end + if secpos+1 > maxsecpos then wflush() end + local align = tonumber(params[1]) + if align then + local x = align + -- Must be a power of 2 in the range (2 ... 256). + for i=1,8 do + x = x / 2 + if x == 1 then + waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. + return + end + end + end + werror("bad alignment") +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode for (primitive) type definitions (map to C types). +map_op[".type_3"] = function(params, nparams) + if not params then + return nparams == 2 and "name, ctype" or "name, ctype, reg" + end + local name, ctype, reg = params[1], params[2], params[3] + if not match(name, "^[%a_][%w_]*$") then + werror("bad type name `"..name.."'") + end + local tp = map_type[name] + if tp then + werror("duplicate type `"..name.."'") + end + -- Add #type to defines. A bit unclean to put it in map_archdef. + map_archdef["#"..name] = "sizeof("..ctype..")" + -- Add new type and emit shortcut define. + local num = ctypenum + 1 + map_type[name] = { + ctype = ctype, + ctypefmt = format("Dt%X(%%s)", num), + reg = reg, + } + wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) + ctypenum = num +end +map_op[".type_2"] = map_op[".type_3"] + +-- Dump type definitions. +local function dumptypes(out, lvl) + local t = {} + for name in pairs(map_type) do t[#t+1] = name end + sort(t) + out:write("Type definitions:\n") + for _,name in ipairs(t) do + local tp = map_type[name] + local reg = tp.reg or "" + out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Set the current section. +function _M.section(num) + waction("SECTION", num) + wflush(true) -- SECTION is a terminal action. +end + +------------------------------------------------------------------------------ + +-- Dump architecture description. +function _M.dumparch(out) + out:write(format("DynASM %s version %s, released %s\n\n", + _info.arch, _info.version, _info.release)) + dumpactions(out) +end + +-- Dump all user defined elements. +function _M.dumpdef(out, lvl) + dumptypes(out, lvl) + dumpglobals(out, lvl) + dumpexterns(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Pass callbacks from/to the DynASM core. +function _M.passcb(wl, we, wf, ww) + wline, werror, wfatal, wwarn = wl, we, wf, ww + return wflush +end + +-- Setup the arch-specific module. +function _M.setup(arch, opt) + g_arch, g_opt = arch, opt +end + +-- Merge the core maps and the arch-specific maps. +function _M.mergemaps(map_coreop, map_def) + setmetatable(map_op, { __index = function(t, k) + local v = map_coreop[k] + if v then return v end + local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$") + local cv = map_cond[cc] + if cv then + local v = rawget(t, k1..k2) + if type(v) == "string" then + local scv = format("%x", cv) + return gsub(scv..sub(v, 2), "|e", "|"..scv) + end + end + end }) + setmetatable(map_def, { __index = map_archdef }) + return map_op, map_def +end + +return _M + +------------------------------------------------------------------------------ + diff --git a/lib/sregex/dynasm/dasm_mips.h b/lib/sregex/dynasm/dasm_mips.h new file mode 100644 index 0000000..af87d99 --- /dev/null +++ b/lib/sregex/dynasm/dasm_mips.h @@ -0,0 +1,415 @@ +/* +** DynASM MIPS encoding engine. +** Copyright (C) 2005-2012 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "mips" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. */ +enum { + DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, + /* The following actions need a buffer position. */ + DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, + /* The following actions also have an argument. */ + DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, + DASM__MAX +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_REL 0x15000000 +#define DASM_S_UNDEF_LG 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned int *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList)actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16) - 0xff00; + if (action >= DASM__MAX) { + ofs += 4; + } else { + int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; + switch (action) { + case DASM_STOP: goto stop; + case DASM_SECTION: + n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); + D->section = &D->sections[n]; goto stop; + case DASM_ESC: p++; ofs += 4; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; + case DASM_REL_LG: + n = (ins & 2047) - 10; pl = D->lglabels + n; + if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + pl += 10; n = *pl; + if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + pos++; + break; + case DASM_LABEL_LG: + pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; + case DASM_LABEL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; + } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_IMM: +#ifdef DASM_CHECKS + CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); +#endif + n >>= ((ins>>10)&31); +#ifdef DASM_CHECKS + if (ins & 0x8000) + CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); + else + CK((n>>((ins>>5)&31)) == 0, RANGE_I); +#endif + b[pos++] = n; + break; + } + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} +#undef CK + +/* Pass 2: Link sections, shrink aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t *szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) return D->status; + { + int pc; + for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16) - 0xff00; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: p++; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; + case DASM_REL_LG: case DASM_REL_PC: pos++; break; + case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; + case DASM_IMM: pos++; break; + } + } + stop: (void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) +#else +#define CK(x, st) ((void)0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + char *base = (char *)buffer; + unsigned int *cp = (unsigned int *)buffer; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16) - 0xff00; + int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: *cp++ = *p++; break; + case DASM_REL_EXT: + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); + goto patchrel; + case DASM_ALIGN: + ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; + break; + case DASM_REL_LG: + CK(n >= 0, UNDEF_LG); + case DASM_REL_PC: + CK(n >= 0, UNDEF_PC); + n = *DASM_POS2PTR(D, n); + if (ins & 2048) + n = n - (int)((char *)cp - base); + else + n = (n + (int)base) & 0x0fffffff; + patchrel: + CK((n & 3) == 0 && + ((n + ((ins & 2048) ? 0x00020000 : 0)) >> + ((ins & 2048) ? 18 : 28)) == 0, RANGE_REL); + cp[-1] |= ((n>>2) & ((ins & 2048) ? 0x0000ffff: 0x03ffffff)); + break; + case DASM_LABEL_LG: + ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); + break; + case DASM_LABEL_PC: break; + case DASM_IMM: + cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); + break; + default: *cp++ = ins; break; + } + } + stop: (void)0; + } + } + + if (base + D->codesize != (char *)cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} +#undef CK + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc*sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) return *DASM_POS2PTR(D, -pos); + if (pos > 0) return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC|(D->section-D->sections); + return D->status; +} +#endif + diff --git a/lib/sregex/dynasm/dasm_mips.lua b/lib/sregex/dynasm/dasm_mips.lua new file mode 100644 index 0000000..c387d29 --- /dev/null +++ b/lib/sregex/dynasm/dasm_mips.lua @@ -0,0 +1,953 @@ +------------------------------------------------------------------------------ +-- DynASM MIPS module. +-- +-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ + +-- Module information: +local _info = { + arch = "mips", + description = "DynASM MIPS module", + version = "1.3.0", + vernum = 10300, + release = "2012-01-23", + author = "Mike Pall", + license = "MIT", +} + +-- Exported glue functions for the arch-specific module. +local _M = { _info = _info } + +-- Cache library functions. +local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs +local assert, setmetatable = assert, setmetatable +local _s = string +local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char +local match, gmatch = _s.match, _s.gmatch +local concat, sort = table.concat, table.sort +local bit = bit or require("bit") +local band, shl, sar, tohex = bit.band, bit.lshift, bit.arshift, bit.tohex + +-- Inherited tables and callbacks. +local g_opt, g_arch +local wline, werror, wfatal, wwarn + +-- Action name list. +-- CHECK: Keep this in sync with the C code! +local action_names = { + "STOP", "SECTION", "ESC", "REL_EXT", + "ALIGN", "REL_LG", "LABEL_LG", + "REL_PC", "LABEL_PC", "IMM", +} + +-- Maximum number of section buffer positions for dasm_put(). +-- CHECK: Keep this in sync with the C code! +local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. + +-- Action name -> action number. +local map_action = {} +for n,name in ipairs(action_names) do + map_action[name] = n-1 +end + +-- Action list buffer. +local actlist = {} + +-- Argument list for next dasm_put(). Start with offset 0 into action list. +local actargs = { 0 } + +-- Current number of section buffer positions for dasm_put(). +local secpos = 1 + +------------------------------------------------------------------------------ + +-- Dump action names and numbers. +local function dumpactions(out) + out:write("DynASM encoding engine action codes:\n") + for n,name in ipairs(action_names) do + local num = map_action[name] + out:write(format(" %-10s %02X %d\n", name, num, num)) + end + out:write("\n") +end + +-- Write action list buffer as a huge static C array. +local function writeactions(out, name) + local nn = #actlist + if nn == 0 then nn = 1; actlist[0] = map_action.STOP end + out:write("static const unsigned int ", name, "[", nn, "] = {\n") + for i = 1,nn-1 do + assert(out:write("0x", tohex(actlist[i]), ",\n")) + end + assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) +end + +------------------------------------------------------------------------------ + +-- Add word to action list. +local function wputxw(n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[#actlist+1] = n +end + +-- Add action to list with optional arg. Advance buffer pos, too. +local function waction(action, val, a, num) + local w = assert(map_action[action], "bad action name `"..action.."'") + wputxw(0xff000000 + w * 0x10000 + (val or 0)) + if a then actargs[#actargs+1] = a end + if a or num then secpos = secpos + (num or 1) end +end + +-- Flush action list (intervening C code or buffer pos overflow). +local function wflush(term) + if #actlist == actargs[1] then return end -- Nothing to flush. + if not term then waction("STOP") end -- Terminate action list. + wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) + actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). + secpos = 1 -- The actionlist offset occupies a buffer position, too. +end + +-- Put escaped word. +local function wputw(n) + if n >= 0xff000000 then waction("ESC") end + wputxw(n) +end + +-- Reserve position for word. +local function wpos() + local pos = #actlist+1 + actlist[pos] = "" + return pos +end + +-- Store word to reserved position. +local function wputpos(pos, n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[pos] = n +end + +------------------------------------------------------------------------------ + +-- Global label name -> global label number. With auto assignment on 1st use. +local next_global = 20 +local map_global = setmetatable({}, { __index = function(t, name) + if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end + local n = next_global + if n > 2047 then werror("too many global labels") end + next_global = n + 1 + t[name] = n + return n +end}) + +-- Dump global labels. +local function dumpglobals(out, lvl) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("Global labels:\n") + for i=20,next_global-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write global label enum. +local function writeglobals(out, prefix) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("enum {\n") + for i=20,next_global-1 do + out:write(" ", prefix, t[i], ",\n") + end + out:write(" ", prefix, "_MAX\n};\n") +end + +-- Write global label names. +local function writeglobalnames(out, name) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=20,next_global-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Extern label name -> extern label number. With auto assignment on 1st use. +local next_extern = 0 +local map_extern_ = {} +local map_extern = setmetatable({}, { __index = function(t, name) + -- No restrictions on the name for now. + local n = next_extern + if n > 2047 then werror("too many extern labels") end + next_extern = n + 1 + t[name] = n + map_extern_[n] = name + return n +end}) + +-- Dump extern labels. +local function dumpexterns(out, lvl) + out:write("Extern labels:\n") + for i=0,next_extern-1 do + out:write(format(" %s\n", map_extern_[i])) + end + out:write("\n") +end + +-- Write extern label names. +local function writeexternnames(out, name) + out:write("static const char *const ", name, "[] = {\n") + for i=0,next_extern-1 do + out:write(" \"", map_extern_[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Arch-specific maps. +local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. + +local map_type = {} -- Type name -> { ctype, reg } +local ctypenum = 0 -- Type number (for Dt... macros). + +-- Reverse defines for registers. +function _M.revdef(s) + if s == "r29" then return "sp" + elseif s == "r31" then return "ra" end + return s +end + +------------------------------------------------------------------------------ + +-- Template strings for MIPS instructions. +local map_op = { + -- First-level opcodes. + j_1 = "08000000J", + jal_1 = "0c000000J", + b_1 = "10000000B", + beqz_2 = "10000000SB", + beq_3 = "10000000STB", + bnez_2 = "14000000SB", + bne_3 = "14000000STB", + blez_2 = "18000000SB", + bgtz_2 = "1c000000SB", + addi_3 = "20000000TSI", + li_2 = "24000000TI", + addiu_3 = "24000000TSI", + slti_3 = "28000000TSI", + sltiu_3 = "2c000000TSI", + andi_3 = "30000000TSU", + lu_2 = "34000000TU", + ori_3 = "34000000TSU", + xori_3 = "38000000TSU", + lui_2 = "3c000000TU", + beqzl_2 = "50000000SB", + beql_3 = "50000000STB", + bnezl_2 = "54000000SB", + bnel_3 = "54000000STB", + blezl_2 = "58000000SB", + bgtzl_2 = "5c000000SB", + lb_2 = "80000000TO", + lh_2 = "84000000TO", + lwl_2 = "88000000TO", + lw_2 = "8c000000TO", + lbu_2 = "90000000TO", + lhu_2 = "94000000TO", + lwr_2 = "98000000TO", + sb_2 = "a0000000TO", + sh_2 = "a4000000TO", + swl_2 = "a8000000TO", + sw_2 = "ac000000TO", + swr_2 = "b8000000TO", + cache_2 = "bc000000NO", + ll_2 = "c0000000TO", + lwc1_2 = "c4000000HO", + pref_2 = "cc000000NO", + ldc1_2 = "d4000000HO", + sc_2 = "e0000000TO", + swc1_2 = "e4000000HO", + sdc1_2 = "f4000000HO", + + -- Opcode SPECIAL. + nop_0 = "00000000", + sll_3 = "00000000DTA", + movf_2 = "00000001DS", + movf_3 = "00000001DSC", + movt_2 = "00010001DS", + movt_3 = "00010001DSC", + srl_3 = "00000002DTA", + rotr_3 = "00200002DTA", + sra_3 = "00000003DTA", + sllv_3 = "00000004DTS", + srlv_3 = "00000006DTS", + rotrv_3 = "00000046DTS", + srav_3 = "00000007DTS", + jr_1 = "00000008S", + jalr_1 = "0000f809S", + jalr_2 = "00000009DS", + movz_3 = "0000000aDST", + movn_3 = "0000000bDST", + syscall_0 = "0000000c", + syscall_1 = "0000000cY", + break_0 = "0000000d", + break_1 = "0000000dY", + sync_0 = "0000000f", + mfhi_1 = "00000010D", + mthi_1 = "00000011S", + mflo_1 = "00000012D", + mtlo_1 = "00000013S", + mult_2 = "00000018ST", + multu_2 = "00000019ST", + div_2 = "0000001aST", + divu_2 = "0000001bST", + add_3 = "00000020DST", + move_2 = "00000021DS", + addu_3 = "00000021DST", + sub_3 = "00000022DST", + negu_2 = "00000023DT", + subu_3 = "00000023DST", + and_3 = "00000024DST", + or_3 = "00000025DST", + xor_3 = "00000026DST", + not_2 = "00000027DS", + nor_3 = "00000027DST", + slt_3 = "0000002aDST", + sltu_3 = "0000002bDST", + tge_2 = "00000030ST", + tge_3 = "00000030STZ", + tgeu_2 = "00000031ST", + tgeu_3 = "00000031STZ", + tlt_2 = "00000032ST", + tlt_3 = "00000032STZ", + tltu_2 = "00000033ST", + tltu_3 = "00000033STZ", + teq_2 = "00000034ST", + teq_3 = "00000034STZ", + tne_2 = "00000036ST", + tne_3 = "00000036STZ", + + -- Opcode REGIMM. + bltz_2 = "04000000SB", + bgez_2 = "04010000SB", + bltzl_2 = "04020000SB", + bgezl_2 = "04030000SB", + tgei_2 = "04080000SI", + tgeiu_2 = "04090000SI", + tlti_2 = "040a0000SI", + tltiu_2 = "040b0000SI", + teqi_2 = "040c0000SI", + tnei_2 = "040e0000SI", + bltzal_2 = "04100000SB", + bal_1 = "04110000B", + bgezal_2 = "04110000SB", + bltzall_2 = "04120000SB", + bgezall_2 = "04130000SB", + synci_1 = "041f0000O", + + -- Opcode SPECIAL2. + madd_2 = "70000000ST", + maddu_2 = "70000001ST", + mul_3 = "70000002DST", + msub_2 = "70000004ST", + msubu_2 = "70000005ST", + clz_2 = "70000020DS=", + clo_2 = "70000021DS=", + sdbbp_0 = "7000003f", + sdbbp_1 = "7000003fY", + + -- Opcode SPECIAL3. + ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 + ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 + wsbh_2 = "7c0000a0DT", + seb_2 = "7c000420DT", + seh_2 = "7c000620DT", + rdhwr_2 = "7c00003bTD", + + -- Opcode COP0. + mfc0_2 = "40000000TD", + mfc0_3 = "40000000TDW", + mtc0_2 = "40800000TD", + mtc0_3 = "40800000TDW", + rdpgpr_2 = "41400000DT", + di_0 = "41606000", + di_1 = "41606000T", + ei_0 = "41606020", + ei_1 = "41606020T", + wrpgpr_2 = "41c00000DT", + tlbr_0 = "42000001", + tlbwi_0 = "42000002", + tlbwr_0 = "42000006", + tlbp_0 = "42000008", + eret_0 = "42000018", + deret_0 = "4200001f", + wait_0 = "42000020", + + -- Opcode COP1. + mfc1_2 = "44000000TG", + cfc1_2 = "44400000TG", + mfhc1_2 = "44600000TG", + mtc1_2 = "44800000TG", + ctc1_2 = "44c00000TG", + mthc1_2 = "44e00000TG", + + bc1f_1 = "45000000B", + bc1f_2 = "45000000CB", + bc1t_1 = "45010000B", + bc1t_2 = "45010000CB", + bc1fl_1 = "45020000B", + bc1fl_2 = "45020000CB", + bc1tl_1 = "45030000B", + bc1tl_2 = "45030000CB", + + ["add.s_3"] = "46000000FGH", + ["sub.s_3"] = "46000001FGH", + ["mul.s_3"] = "46000002FGH", + ["div.s_3"] = "46000003FGH", + ["sqrt.s_2"] = "46000004FG", + ["abs.s_2"] = "46000005FG", + ["mov.s_2"] = "46000006FG", + ["neg.s_2"] = "46000007FG", + ["round.l.s_2"] = "46000008FG", + ["trunc.l.s_2"] = "46000009FG", + ["ceil.l.s_2"] = "4600000aFG", + ["floor.l.s_2"] = "4600000bFG", + ["round.w.s_2"] = "4600000cFG", + ["trunc.w.s_2"] = "4600000dFG", + ["ceil.w.s_2"] = "4600000eFG", + ["floor.w.s_2"] = "4600000fFG", + ["movf.s_2"] = "46000011FG", + ["movf.s_3"] = "46000011FGC", + ["movt.s_2"] = "46010011FG", + ["movt.s_3"] = "46010011FGC", + ["movz.s_3"] = "46000012FGT", + ["movn.s_3"] = "46000013FGT", + ["recip.s_2"] = "46000015FG", + ["rsqrt.s_2"] = "46000016FG", + ["cvt.d.s_2"] = "46000021FG", + ["cvt.w.s_2"] = "46000024FG", + ["cvt.l.s_2"] = "46000025FG", + ["cvt.ps.s_3"] = "46000026FGH", + ["c.f.s_2"] = "46000030GH", + ["c.f.s_3"] = "46000030VGH", + ["c.un.s_2"] = "46000031GH", + ["c.un.s_3"] = "46000031VGH", + ["c.eq.s_2"] = "46000032GH", + ["c.eq.s_3"] = "46000032VGH", + ["c.ueq.s_2"] = "46000033GH", + ["c.ueq.s_3"] = "46000033VGH", + ["c.olt.s_2"] = "46000034GH", + ["c.olt.s_3"] = "46000034VGH", + ["c.ult.s_2"] = "46000035GH", + ["c.ult.s_3"] = "46000035VGH", + ["c.ole.s_2"] = "46000036GH", + ["c.ole.s_3"] = "46000036VGH", + ["c.ule.s_2"] = "46000037GH", + ["c.ule.s_3"] = "46000037VGH", + ["c.sf.s_2"] = "46000038GH", + ["c.sf.s_3"] = "46000038VGH", + ["c.ngle.s_2"] = "46000039GH", + ["c.ngle.s_3"] = "46000039VGH", + ["c.seq.s_2"] = "4600003aGH", + ["c.seq.s_3"] = "4600003aVGH", + ["c.ngl.s_2"] = "4600003bGH", + ["c.ngl.s_3"] = "4600003bVGH", + ["c.lt.s_2"] = "4600003cGH", + ["c.lt.s_3"] = "4600003cVGH", + ["c.nge.s_2"] = "4600003dGH", + ["c.nge.s_3"] = "4600003dVGH", + ["c.le.s_2"] = "4600003eGH", + ["c.le.s_3"] = "4600003eVGH", + ["c.ngt.s_2"] = "4600003fGH", + ["c.ngt.s_3"] = "4600003fVGH", + + ["add.d_3"] = "46200000FGH", + ["sub.d_3"] = "46200001FGH", + ["mul.d_3"] = "46200002FGH", + ["div.d_3"] = "46200003FGH", + ["sqrt.d_2"] = "46200004FG", + ["abs.d_2"] = "46200005FG", + ["mov.d_2"] = "46200006FG", + ["neg.d_2"] = "46200007FG", + ["round.l.d_2"] = "46200008FG", + ["trunc.l.d_2"] = "46200009FG", + ["ceil.l.d_2"] = "4620000aFG", + ["floor.l.d_2"] = "4620000bFG", + ["round.w.d_2"] = "4620000cFG", + ["trunc.w.d_2"] = "4620000dFG", + ["ceil.w.d_2"] = "4620000eFG", + ["floor.w.d_2"] = "4620000fFG", + ["movf.d_2"] = "46200011FG", + ["movf.d_3"] = "46200011FGC", + ["movt.d_2"] = "46210011FG", + ["movt.d_3"] = "46210011FGC", + ["movz.d_3"] = "46200012FGT", + ["movn.d_3"] = "46200013FGT", + ["recip.d_2"] = "46200015FG", + ["rsqrt.d_2"] = "46200016FG", + ["cvt.s.d_2"] = "46200020FG", + ["cvt.w.d_2"] = "46200024FG", + ["cvt.l.d_2"] = "46200025FG", + ["c.f.d_2"] = "46200030GH", + ["c.f.d_3"] = "46200030VGH", + ["c.un.d_2"] = "46200031GH", + ["c.un.d_3"] = "46200031VGH", + ["c.eq.d_2"] = "46200032GH", + ["c.eq.d_3"] = "46200032VGH", + ["c.ueq.d_2"] = "46200033GH", + ["c.ueq.d_3"] = "46200033VGH", + ["c.olt.d_2"] = "46200034GH", + ["c.olt.d_3"] = "46200034VGH", + ["c.ult.d_2"] = "46200035GH", + ["c.ult.d_3"] = "46200035VGH", + ["c.ole.d_2"] = "46200036GH", + ["c.ole.d_3"] = "46200036VGH", + ["c.ule.d_2"] = "46200037GH", + ["c.ule.d_3"] = "46200037VGH", + ["c.sf.d_2"] = "46200038GH", + ["c.sf.d_3"] = "46200038VGH", + ["c.ngle.d_2"] = "46200039GH", + ["c.ngle.d_3"] = "46200039VGH", + ["c.seq.d_2"] = "4620003aGH", + ["c.seq.d_3"] = "4620003aVGH", + ["c.ngl.d_2"] = "4620003bGH", + ["c.ngl.d_3"] = "4620003bVGH", + ["c.lt.d_2"] = "4620003cGH", + ["c.lt.d_3"] = "4620003cVGH", + ["c.nge.d_2"] = "4620003dGH", + ["c.nge.d_3"] = "4620003dVGH", + ["c.le.d_2"] = "4620003eGH", + ["c.le.d_3"] = "4620003eVGH", + ["c.ngt.d_2"] = "4620003fGH", + ["c.ngt.d_3"] = "4620003fVGH", + + ["add.ps_3"] = "46c00000FGH", + ["sub.ps_3"] = "46c00001FGH", + ["mul.ps_3"] = "46c00002FGH", + ["abs.ps_2"] = "46c00005FG", + ["mov.ps_2"] = "46c00006FG", + ["neg.ps_2"] = "46c00007FG", + ["movf.ps_2"] = "46c00011FG", + ["movf.ps_3"] = "46c00011FGC", + ["movt.ps_2"] = "46c10011FG", + ["movt.ps_3"] = "46c10011FGC", + ["movz.ps_3"] = "46c00012FGT", + ["movn.ps_3"] = "46c00013FGT", + ["cvt.s.pu_2"] = "46c00020FG", + ["cvt.s.pl_2"] = "46c00028FG", + ["pll.ps_3"] = "46c0002cFGH", + ["plu.ps_3"] = "46c0002dFGH", + ["pul.ps_3"] = "46c0002eFGH", + ["puu.ps_3"] = "46c0002fFGH", + ["c.f.ps_2"] = "46c00030GH", + ["c.f.ps_3"] = "46c00030VGH", + ["c.un.ps_2"] = "46c00031GH", + ["c.un.ps_3"] = "46c00031VGH", + ["c.eq.ps_2"] = "46c00032GH", + ["c.eq.ps_3"] = "46c00032VGH", + ["c.ueq.ps_2"] = "46c00033GH", + ["c.ueq.ps_3"] = "46c00033VGH", + ["c.olt.ps_2"] = "46c00034GH", + ["c.olt.ps_3"] = "46c00034VGH", + ["c.ult.ps_2"] = "46c00035GH", + ["c.ult.ps_3"] = "46c00035VGH", + ["c.ole.ps_2"] = "46c00036GH", + ["c.ole.ps_3"] = "46c00036VGH", + ["c.ule.ps_2"] = "46c00037GH", + ["c.ule.ps_3"] = "46c00037VGH", + ["c.sf.ps_2"] = "46c00038GH", + ["c.sf.ps_3"] = "46c00038VGH", + ["c.ngle.ps_2"] = "46c00039GH", + ["c.ngle.ps_3"] = "46c00039VGH", + ["c.seq.ps_2"] = "46c0003aGH", + ["c.seq.ps_3"] = "46c0003aVGH", + ["c.ngl.ps_2"] = "46c0003bGH", + ["c.ngl.ps_3"] = "46c0003bVGH", + ["c.lt.ps_2"] = "46c0003cGH", + ["c.lt.ps_3"] = "46c0003cVGH", + ["c.nge.ps_2"] = "46c0003dGH", + ["c.nge.ps_3"] = "46c0003dVGH", + ["c.le.ps_2"] = "46c0003eGH", + ["c.le.ps_3"] = "46c0003eVGH", + ["c.ngt.ps_2"] = "46c0003fGH", + ["c.ngt.ps_3"] = "46c0003fVGH", + + ["cvt.s.w_2"] = "46800020FG", + ["cvt.d.w_2"] = "46800021FG", + + ["cvt.s.l_2"] = "46a00020FG", + ["cvt.d.l_2"] = "46a00021FG", + + -- Opcode COP1X. + lwxc1_2 = "4c000000FX", + ldxc1_2 = "4c000001FX", + luxc1_2 = "4c000005FX", + swxc1_2 = "4c000008FX", + sdxc1_2 = "4c000009FX", + suxc1_2 = "4c00000dFX", + prefx_2 = "4c00000fMX", + ["alnv.ps_4"] = "4c00001eFGHS", + ["madd.s_4"] = "4c000020FRGH", + ["madd.d_4"] = "4c000021FRGH", + ["madd.ps_4"] = "4c000026FRGH", + ["msub.s_4"] = "4c000028FRGH", + ["msub.d_4"] = "4c000029FRGH", + ["msub.ps_4"] = "4c00002eFRGH", + ["nmadd.s_4"] = "4c000030FRGH", + ["nmadd.d_4"] = "4c000031FRGH", + ["nmadd.ps_4"] = "4c000036FRGH", + ["nmsub.s_4"] = "4c000038FRGH", + ["nmsub.d_4"] = "4c000039FRGH", + ["nmsub.ps_4"] = "4c00003eFRGH", +} + +------------------------------------------------------------------------------ + +local function parse_gpr(expr) + local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + if not reg then + werror("type `"..(tname or expr).."' needs a register override") + end + expr = reg + end + local r = match(expr, "^r([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r, tp end + end + werror("bad register name `"..expr.."'") +end + +local function parse_fpr(expr) + local r = match(expr, "^f([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r end + end + werror("bad register name `"..expr.."'") +end + +local function parse_imm(imm, bits, shift, scale, signed) + local n = tonumber(imm) + if n then + local m = sar(n, scale) + if shl(m, scale) == n then + if signed then + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end + else + if sar(m, bits) == 0 then return shl(m, shift) end + end + end + werror("out of range immediate `"..imm.."'") + elseif match(imm, "^[rf]([1-3]?[0-9])$") or + match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then + werror("expected immediate operand, got register") + else + waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) + return 0 + end +end + +local function parse_disp(disp) + local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") + if imm then + local r = shl(parse_gpr(reg), 21) + local extname = match(imm, "^extern%s+(%S+)$") + if extname then + waction("REL_EXT", map_extern[extname], nil, 1) + return r + else + return r + parse_imm(imm, 16, 0, 0, true) + end + end + local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local r, tp = parse_gpr(reg) + if tp then + waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) + return shl(r, 21) + end + end + werror("bad displacement `"..disp.."'") +end + +local function parse_index(idx) + local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") + if rt then + rt = parse_gpr(rt) + rs = parse_gpr(rs) + return shl(rt, 16) + shl(rs, 21) + end + werror("bad index `"..idx.."'") +end + +local function parse_label(label, def) + local prefix = sub(label, 1, 2) + -- =>label (pc label reference) + if prefix == "=>" then + return "PC", 0, sub(label, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "LG", map_global[sub(label, 3)] + end + if def then + -- [1-9] (local label definition) + if match(label, "^[1-9]$") then + return "LG", 10+tonumber(label) + end + else + -- [<>][1-9] (local label reference) + local dir, lnum = match(label, "^([<>])([1-9])$") + if dir then -- Fwd: 1-9, Bkwd: 11-19. + return "LG", lnum + (dir == ">" and 0 or 10) + end + -- extern label (extern label reference) + local extname = match(label, "^extern%s+(%S+)$") + if extname then + return "EXT", map_extern[extname] + end + end + werror("bad label `"..label.."'") +end + +------------------------------------------------------------------------------ + +-- Handle opcodes defined with template strings. +map_op[".template__"] = function(params, template, nparams) + if not params then return sub(template, 9) end + local op = tonumber(sub(template, 1, 8), 16) + local n = 1 + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 2 positions (ins/ext). + if secpos+2 > maxsecpos then wflush() end + local pos = wpos() + + -- Process each character. + for p in gmatch(sub(template, 9), ".") do + if p == "D" then + op = op + shl(parse_gpr(params[n]), 11); n = n + 1 + elseif p == "T" then + op = op + shl(parse_gpr(params[n]), 16); n = n + 1 + elseif p == "S" then + op = op + shl(parse_gpr(params[n]), 21); n = n + 1 + elseif p == "F" then + op = op + shl(parse_fpr(params[n]), 6); n = n + 1 + elseif p == "G" then + op = op + shl(parse_fpr(params[n]), 11); n = n + 1 + elseif p == "H" then + op = op + shl(parse_fpr(params[n]), 16); n = n + 1 + elseif p == "R" then + op = op + shl(parse_fpr(params[n]), 21); n = n + 1 + elseif p == "I" then + op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 + elseif p == "U" then + op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 + elseif p == "O" then + op = op + parse_disp(params[n]); n = n + 1 + elseif p == "X" then + op = op + parse_index(params[n]); n = n + 1 + elseif p == "B" or p == "J" then + local mode, n, s = parse_label(params[n], false) + if p == "B" then n = n + 2048 end + waction("REL_"..mode, n, s, 1) + n = n + 1 + elseif p == "A" then + op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 + elseif p == "M" then + op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 + elseif p == "N" then + op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 + elseif p == "C" then + op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 + elseif p == "V" then + op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 + elseif p == "W" then + op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 + elseif p == "Y" then + op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 + elseif p == "Z" then + op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 + elseif p == "=" then + op = op + shl(band(op, 0xf800), 5) -- Copy D to T for clz, clo. + else + assert(false) + end + end + wputpos(pos, op) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode to mark the position where the action list is to be emitted. +map_op[".actionlist_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeactions(out, name) end) +end + +-- Pseudo-opcode to mark the position where the global enum is to be emitted. +map_op[".globals_1"] = function(params) + if not params then return "prefix" end + local prefix = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobals(out, prefix) end) +end + +-- Pseudo-opcode to mark the position where the global names are to be emitted. +map_op[".globalnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobalnames(out, name) end) +end + +-- Pseudo-opcode to mark the position where the extern names are to be emitted. +map_op[".externnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeexternnames(out, name) end) +end + +------------------------------------------------------------------------------ + +-- Label pseudo-opcode (converted from trailing colon form). +map_op[".label_1"] = function(params) + if not params then return "[1-9] | ->global | =>pcexpr" end + if secpos+1 > maxsecpos then wflush() end + local mode, n, s = parse_label(params[1], true) + if mode == "EXT" then werror("bad label definition") end + waction("LABEL_"..mode, n, s, 1) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcodes for data storage. +map_op[".long_*"] = function(params) + if not params then return "imm..." end + for _,p in ipairs(params) do + local n = tonumber(p) + if not n then werror("bad immediate `"..p.."'") end + if n < 0 then n = n + 2^32 end + wputw(n) + if secpos+2 > maxsecpos then wflush() end + end +end + +-- Alignment pseudo-opcode. +map_op[".align_1"] = function(params) + if not params then return "numpow2" end + if secpos+1 > maxsecpos then wflush() end + local align = tonumber(params[1]) + if align then + local x = align + -- Must be a power of 2 in the range (2 ... 256). + for i=1,8 do + x = x / 2 + if x == 1 then + waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. + return + end + end + end + werror("bad alignment") +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode for (primitive) type definitions (map to C types). +map_op[".type_3"] = function(params, nparams) + if not params then + return nparams == 2 and "name, ctype" or "name, ctype, reg" + end + local name, ctype, reg = params[1], params[2], params[3] + if not match(name, "^[%a_][%w_]*$") then + werror("bad type name `"..name.."'") + end + local tp = map_type[name] + if tp then + werror("duplicate type `"..name.."'") + end + -- Add #type to defines. A bit unclean to put it in map_archdef. + map_archdef["#"..name] = "sizeof("..ctype..")" + -- Add new type and emit shortcut define. + local num = ctypenum + 1 + map_type[name] = { + ctype = ctype, + ctypefmt = format("Dt%X(%%s)", num), + reg = reg, + } + wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) + ctypenum = num +end +map_op[".type_2"] = map_op[".type_3"] + +-- Dump type definitions. +local function dumptypes(out, lvl) + local t = {} + for name in pairs(map_type) do t[#t+1] = name end + sort(t) + out:write("Type definitions:\n") + for _,name in ipairs(t) do + local tp = map_type[name] + local reg = tp.reg or "" + out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Set the current section. +function _M.section(num) + waction("SECTION", num) + wflush(true) -- SECTION is a terminal action. +end + +------------------------------------------------------------------------------ + +-- Dump architecture description. +function _M.dumparch(out) + out:write(format("DynASM %s version %s, released %s\n\n", + _info.arch, _info.version, _info.release)) + dumpactions(out) +end + +-- Dump all user defined elements. +function _M.dumpdef(out, lvl) + dumptypes(out, lvl) + dumpglobals(out, lvl) + dumpexterns(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Pass callbacks from/to the DynASM core. +function _M.passcb(wl, we, wf, ww) + wline, werror, wfatal, wwarn = wl, we, wf, ww + return wflush +end + +-- Setup the arch-specific module. +function _M.setup(arch, opt) + g_arch, g_opt = arch, opt +end + +-- Merge the core maps and the arch-specific maps. +function _M.mergemaps(map_coreop, map_def) + setmetatable(map_op, { __index = map_coreop }) + setmetatable(map_def, { __index = map_archdef }) + return map_op, map_def +end + +return _M + +------------------------------------------------------------------------------ + diff --git a/lib/sregex/dynasm/dasm_ppc.h b/lib/sregex/dynasm/dasm_ppc.h new file mode 100644 index 0000000..bf5957e --- /dev/null +++ b/lib/sregex/dynasm/dasm_ppc.h @@ -0,0 +1,411 @@ +/* +** DynASM PPC encoding engine. +** Copyright (C) 2005-2012 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "ppc" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. */ +enum { + DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, + /* The following actions need a buffer position. */ + DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, + /* The following actions also have an argument. */ + DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, + DASM__MAX +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_REL 0x15000000 +#define DASM_S_UNDEF_LG 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned int *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList)actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + if (action >= DASM__MAX) { + ofs += 4; + } else { + int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; + switch (action) { + case DASM_STOP: goto stop; + case DASM_SECTION: + n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); + D->section = &D->sections[n]; goto stop; + case DASM_ESC: p++; ofs += 4; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; + case DASM_REL_LG: + n = (ins & 2047) - 10; pl = D->lglabels + n; + if (n >= 0) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + pl += 10; n = *pl; + if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + pos++; + break; + case DASM_LABEL_LG: + pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; + case DASM_LABEL_PC: + pl = D->pclabels + n; CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; + } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_IMM: +#ifdef DASM_CHECKS + CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); +#endif + n >>= ((ins>>10)&31); +#ifdef DASM_CHECKS + if (ins & 0x8000) + CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); + else + CK((n>>((ins>>5)&31)) == 0, RANGE_I); +#endif + b[pos++] = n; + break; + } + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} +#undef CK + +/* Pass 2: Link sections, shrink aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t *szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) return D->status; + { + int pc; + for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 20; idx*sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: p++; break; + case DASM_REL_EXT: break; + case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; + case DASM_REL_LG: case DASM_REL_PC: pos++; break; + case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; + case DASM_IMM: pos++; break; + } + } + stop: (void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) +#else +#define CK(x, st) ((void)0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + char *base = (char *)buffer; + unsigned int *cp = (unsigned int *)buffer; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + while (1) { + unsigned int ins = *p++; + unsigned int action = (ins >> 16); + int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; + switch (action) { + case DASM_STOP: case DASM_SECTION: goto stop; + case DASM_ESC: *cp++ = *p++; break; + case DASM_REL_EXT: + n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; + goto patchrel; + case DASM_ALIGN: + ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; + break; + case DASM_REL_LG: + CK(n >= 0, UNDEF_LG); + case DASM_REL_PC: + CK(n >= 0, UNDEF_PC); + n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); + patchrel: + CK((n & 3) == 0 && + (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> + ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); + cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); + break; + case DASM_LABEL_LG: + ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); + break; + case DASM_LABEL_PC: break; + case DASM_IMM: + cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); + break; + default: *cp++ = ins; break; + } + } + stop: (void)0; + } + } + + if (base + D->codesize != (char *)cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} +#undef CK + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc*sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) return *DASM_POS2PTR(D, -pos); + if (pos > 0) return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC|(D->section-D->sections); + return D->status; +} +#endif + diff --git a/lib/sregex/dynasm/dasm_ppc.lua b/lib/sregex/dynasm/dasm_ppc.lua new file mode 100644 index 0000000..020ef0d --- /dev/null +++ b/lib/sregex/dynasm/dasm_ppc.lua @@ -0,0 +1,1249 @@ +------------------------------------------------------------------------------ +-- DynASM PPC module. +-- +-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ + +-- Module information: +local _info = { + arch = "ppc", + description = "DynASM PPC module", + version = "1.3.0", + vernum = 10300, + release = "2011-05-05", + author = "Mike Pall", + license = "MIT", +} + +-- Exported glue functions for the arch-specific module. +local _M = { _info = _info } + +-- Cache library functions. +local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs +local assert, setmetatable = assert, setmetatable +local _s = string +local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char +local match, gmatch = _s.match, _s.gmatch +local concat, sort = table.concat, table.sort +local bit = bit or require("bit") +local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift +local tohex = bit.tohex + +-- Inherited tables and callbacks. +local g_opt, g_arch +local wline, werror, wfatal, wwarn + +-- Action name list. +-- CHECK: Keep this in sync with the C code! +local action_names = { + "STOP", "SECTION", "ESC", "REL_EXT", + "ALIGN", "REL_LG", "LABEL_LG", + "REL_PC", "LABEL_PC", "IMM", +} + +-- Maximum number of section buffer positions for dasm_put(). +-- CHECK: Keep this in sync with the C code! +local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. + +-- Action name -> action number. +local map_action = {} +for n,name in ipairs(action_names) do + map_action[name] = n-1 +end + +-- Action list buffer. +local actlist = {} + +-- Argument list for next dasm_put(). Start with offset 0 into action list. +local actargs = { 0 } + +-- Current number of section buffer positions for dasm_put(). +local secpos = 1 + +------------------------------------------------------------------------------ + +-- Dump action names and numbers. +local function dumpactions(out) + out:write("DynASM encoding engine action codes:\n") + for n,name in ipairs(action_names) do + local num = map_action[name] + out:write(format(" %-10s %02X %d\n", name, num, num)) + end + out:write("\n") +end + +-- Write action list buffer as a huge static C array. +local function writeactions(out, name) + local nn = #actlist + if nn == 0 then nn = 1; actlist[0] = map_action.STOP end + out:write("static const unsigned int ", name, "[", nn, "] = {\n") + for i = 1,nn-1 do + assert(out:write("0x", tohex(actlist[i]), ",\n")) + end + assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) +end + +------------------------------------------------------------------------------ + +-- Add word to action list. +local function wputxw(n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[#actlist+1] = n +end + +-- Add action to list with optional arg. Advance buffer pos, too. +local function waction(action, val, a, num) + local w = assert(map_action[action], "bad action name `"..action.."'") + wputxw(w * 0x10000 + (val or 0)) + if a then actargs[#actargs+1] = a end + if a or num then secpos = secpos + (num or 1) end +end + +-- Flush action list (intervening C code or buffer pos overflow). +local function wflush(term) + if #actlist == actargs[1] then return end -- Nothing to flush. + if not term then waction("STOP") end -- Terminate action list. + wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) + actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). + secpos = 1 -- The actionlist offset occupies a buffer position, too. +end + +-- Put escaped word. +local function wputw(n) + if n <= 0xffffff then waction("ESC") end + wputxw(n) +end + +-- Reserve position for word. +local function wpos() + local pos = #actlist+1 + actlist[pos] = "" + return pos +end + +-- Store word to reserved position. +local function wputpos(pos, n) + assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") + actlist[pos] = n +end + +------------------------------------------------------------------------------ + +-- Global label name -> global label number. With auto assignment on 1st use. +local next_global = 20 +local map_global = setmetatable({}, { __index = function(t, name) + if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end + local n = next_global + if n > 2047 then werror("too many global labels") end + next_global = n + 1 + t[name] = n + return n +end}) + +-- Dump global labels. +local function dumpglobals(out, lvl) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("Global labels:\n") + for i=20,next_global-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write global label enum. +local function writeglobals(out, prefix) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("enum {\n") + for i=20,next_global-1 do + out:write(" ", prefix, t[i], ",\n") + end + out:write(" ", prefix, "_MAX\n};\n") +end + +-- Write global label names. +local function writeglobalnames(out, name) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=20,next_global-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Extern label name -> extern label number. With auto assignment on 1st use. +local next_extern = 0 +local map_extern_ = {} +local map_extern = setmetatable({}, { __index = function(t, name) + -- No restrictions on the name for now. + local n = next_extern + if n > 2047 then werror("too many extern labels") end + next_extern = n + 1 + t[name] = n + map_extern_[n] = name + return n +end}) + +-- Dump extern labels. +local function dumpexterns(out, lvl) + out:write("Extern labels:\n") + for i=0,next_extern-1 do + out:write(format(" %s\n", map_extern_[i])) + end + out:write("\n") +end + +-- Write extern label names. +local function writeexternnames(out, name) + out:write("static const char *const ", name, "[] = {\n") + for i=0,next_extern-1 do + out:write(" \"", map_extern_[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Arch-specific maps. +local map_archdef = { sp = "r1" } -- Ext. register name -> int. name. + +local map_type = {} -- Type name -> { ctype, reg } +local ctypenum = 0 -- Type number (for Dt... macros). + +-- Reverse defines for registers. +function _M.revdef(s) + if s == "r1" then return "sp" end + return s +end + +local map_cond = { + lt = 0, gt = 1, eq = 2, so = 3, + ge = 4, le = 5, ne = 6, ns = 7, +} + +------------------------------------------------------------------------------ + +-- Template strings for PPC instructions. +local map_op = { + tdi_3 = "08000000ARI", + twi_3 = "0c000000ARI", + mulli_3 = "1c000000RRI", + subfic_3 = "20000000RRI", + cmplwi_3 = "28000000XRU", + cmplwi_2 = "28000000-RU", + cmpldi_3 = "28200000XRU", + cmpldi_2 = "28200000-RU", + cmpwi_3 = "2c000000XRI", + cmpwi_2 = "2c000000-RI", + cmpdi_3 = "2c200000XRI", + cmpdi_2 = "2c200000-RI", + addic_3 = "30000000RRI", + ["addic._3"] = "34000000RRI", + addi_3 = "38000000RR0I", + li_2 = "38000000RI", + la_2 = "38000000RD", + addis_3 = "3c000000RR0I", + lis_2 = "3c000000RI", + lus_2 = "3c000000RU", + bc_3 = "40000000AAK", + bcl_3 = "40000001AAK", + bdnz_1 = "42000000K", + bdz_1 = "42400000K", + sc_0 = "44000000", + b_1 = "48000000J", + bl_1 = "48000001J", + rlwimi_5 = "50000000RR~AAA.", + rlwinm_5 = "54000000RR~AAA.", + rlwnm_5 = "5c000000RR~RAA.", + ori_3 = "60000000RR~U", + nop_0 = "60000000", + oris_3 = "64000000RR~U", + xori_3 = "68000000RR~U", + xoris_3 = "6c000000RR~U", + ["andi._3"] = "70000000RR~U", + ["andis._3"] = "74000000RR~U", + lwz_2 = "80000000RD", + lwzu_2 = "84000000RD", + lbz_2 = "88000000RD", + lbzu_2 = "8c000000RD", + stw_2 = "90000000RD", + stwu_2 = "94000000RD", + stb_2 = "98000000RD", + stbu_2 = "9c000000RD", + lhz_2 = "a0000000RD", + lhzu_2 = "a4000000RD", + lha_2 = "a8000000RD", + lhau_2 = "ac000000RD", + sth_2 = "b0000000RD", + sthu_2 = "b4000000RD", + lmw_2 = "b8000000RD", + stmw_2 = "bc000000RD", + lfs_2 = "c0000000FD", + lfsu_2 = "c4000000FD", + lfd_2 = "c8000000FD", + lfdu_2 = "cc000000FD", + stfs_2 = "d0000000FD", + stfsu_2 = "d4000000FD", + stfd_2 = "d8000000FD", + stfdu_2 = "dc000000FD", + ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4. + ldu_2 = "e8000001RD", + lwa_2 = "e8000002RD", + std_2 = "f8000000RD", + stdu_2 = "f8000001RD", + + -- Primary opcode 19: + mcrf_2 = "4c000000XX", + isync_0 = "4c00012c", + crnor_3 = "4c000042CCC", + crnot_2 = "4c000042CC=", + crandc_3 = "4c000102CCC", + crxor_3 = "4c000182CCC", + crclr_1 = "4c000182C==", + crnand_3 = "4c0001c2CCC", + crand_3 = "4c000202CCC", + creqv_3 = "4c000242CCC", + crset_1 = "4c000242C==", + crorc_3 = "4c000342CCC", + cror_3 = "4c000382CCC", + crmove_2 = "4c000382CC=", + bclr_2 = "4c000020AA", + bclrl_2 = "4c000021AA", + bcctr_2 = "4c000420AA", + bcctrl_2 = "4c000421AA", + blr_0 = "4e800020", + blrl_0 = "4e800021", + bctr_0 = "4e800420", + bctrl_0 = "4e800421", + + -- Primary opcode 31: + cmpw_3 = "7c000000XRR", + cmpw_2 = "7c000000-RR", + cmpd_3 = "7c200000XRR", + cmpd_2 = "7c200000-RR", + tw_3 = "7c000008ARR", + subfc_3 = "7c000010RRR.", + subc_3 = "7c000010RRR~.", + mulhdu_3 = "7c000012RRR.", + addc_3 = "7c000014RRR.", + mulhwu_3 = "7c000016RRR.", + isel_4 = "7c00001eRRRC", + isellt_3 = "7c00001eRRR", + iselgt_3 = "7c00005eRRR", + iseleq_3 = "7c00009eRRR", + mfcr_1 = "7c000026R", + mfocrf_2 = "7c100026RG", + mtcrf_2 = "7c000120GR", + mtocrf_2 = "7c100120GR", + lwarx_3 = "7c000028RR0R", + ldx_3 = "7c00002aRR0R", + lwzx_3 = "7c00002eRR0R", + slw_3 = "7c000030RR~R.", + cntlzw_2 = "7c000034RR~", + sld_3 = "7c000036RR~R.", + and_3 = "7c000038RR~R.", + cmplw_3 = "7c000040XRR", + cmplw_2 = "7c000040-RR", + cmpld_3 = "7c200040XRR", + cmpld_2 = "7c200040-RR", + subf_3 = "7c000050RRR.", + sub_3 = "7c000050RRR~.", + ldux_3 = "7c00006aRR0R", + dcbst_2 = "7c00006c-RR", + lwzux_3 = "7c00006eRR0R", + cntlzd_2 = "7c000074RR~", + andc_3 = "7c000078RR~R.", + td_3 = "7c000088ARR", + mulhd_3 = "7c000092RRR.", + mulhw_3 = "7c000096RRR.", + ldarx_3 = "7c0000a8RR0R", + dcbf_2 = "7c0000ac-RR", + lbzx_3 = "7c0000aeRR0R", + neg_2 = "7c0000d0RR.", + lbzux_3 = "7c0000eeRR0R", + popcntb_2 = "7c0000f4RR~", + not_2 = "7c0000f8RR~%.", + nor_3 = "7c0000f8RR~R.", + subfe_3 = "7c000110RRR.", + sube_3 = "7c000110RRR~.", + adde_3 = "7c000114RRR.", + stdx_3 = "7c00012aRR0R", + stwcx_3 = "7c00012cRR0R.", + stwx_3 = "7c00012eRR0R", + prtyw_2 = "7c000134RR~", + stdux_3 = "7c00016aRR0R", + stwux_3 = "7c00016eRR0R", + prtyd_2 = "7c000174RR~", + subfze_2 = "7c000190RR.", + addze_2 = "7c000194RR.", + stdcx_3 = "7c0001acRR0R.", + stbx_3 = "7c0001aeRR0R", + subfme_2 = "7c0001d0RR.", + mulld_3 = "7c0001d2RRR.", + addme_2 = "7c0001d4RR.", + mullw_3 = "7c0001d6RRR.", + dcbtst_2 = "7c0001ec-RR", + stbux_3 = "7c0001eeRR0R", + add_3 = "7c000214RRR.", + dcbt_2 = "7c00022c-RR", + lhzx_3 = "7c00022eRR0R", + eqv_3 = "7c000238RR~R.", + eciwx_3 = "7c00026cRR0R", + lhzux_3 = "7c00026eRR0R", + xor_3 = "7c000278RR~R.", + mfspefscr_1 = "7c0082a6R", + mfxer_1 = "7c0102a6R", + mflr_1 = "7c0802a6R", + mfctr_1 = "7c0902a6R", + lwax_3 = "7c0002aaRR0R", + lhax_3 = "7c0002aeRR0R", + mftb_1 = "7c0c42e6R", + mftbu_1 = "7c0d42e6R", + lwaux_3 = "7c0002eaRR0R", + lhaux_3 = "7c0002eeRR0R", + sthx_3 = "7c00032eRR0R", + orc_3 = "7c000338RR~R.", + ecowx_3 = "7c00036cRR0R", + sthux_3 = "7c00036eRR0R", + or_3 = "7c000378RR~R.", + mr_2 = "7c000378RR~%.", + divdu_3 = "7c000392RRR.", + divwu_3 = "7c000396RRR.", + mtspefscr_1 = "7c0083a6R", + mtxer_1 = "7c0103a6R", + mtlr_1 = "7c0803a6R", + mtctr_1 = "7c0903a6R", + dcbi_2 = "7c0003ac-RR", + nand_3 = "7c0003b8RR~R.", + divd_3 = "7c0003d2RRR.", + divw_3 = "7c0003d6RRR.", + cmpb_3 = "7c0003f8RR~R.", + mcrxr_1 = "7c000400X", + subfco_3 = "7c000410RRR.", + subco_3 = "7c000410RRR~.", + addco_3 = "7c000414RRR.", + ldbrx_3 = "7c000428RR0R", + lswx_3 = "7c00042aRR0R", + lwbrx_3 = "7c00042cRR0R", + lfsx_3 = "7c00042eFR0R", + srw_3 = "7c000430RR~R.", + srd_3 = "7c000436RR~R.", + subfo_3 = "7c000450RRR.", + subo_3 = "7c000450RRR~.", + lfsux_3 = "7c00046eFR0R", + lswi_3 = "7c0004aaRR0A", + sync_0 = "7c0004ac", + lwsync_0 = "7c2004ac", + ptesync_0 = "7c4004ac", + lfdx_3 = "7c0004aeFR0R", + nego_2 = "7c0004d0RR.", + lfdux_3 = "7c0004eeFR0R", + subfeo_3 = "7c000510RRR.", + subeo_3 = "7c000510RRR~.", + addeo_3 = "7c000514RRR.", + stdbrx_3 = "7c000528RR0R", + stswx_3 = "7c00052aRR0R", + stwbrx_3 = "7c00052cRR0R", + stfsx_3 = "7c00052eFR0R", + stfsux_3 = "7c00056eFR0R", + subfzeo_2 = "7c000590RR.", + addzeo_2 = "7c000594RR.", + stswi_3 = "7c0005aaRR0A", + stfdx_3 = "7c0005aeFR0R", + subfmeo_2 = "7c0005d0RR.", + mulldo_3 = "7c0005d2RRR.", + addmeo_2 = "7c0005d4RR.", + mullwo_3 = "7c0005d6RRR.", + dcba_2 = "7c0005ec-RR", + stfdux_3 = "7c0005eeFR0R", + addo_3 = "7c000614RRR.", + lhbrx_3 = "7c00062cRR0R", + sraw_3 = "7c000630RR~R.", + srad_3 = "7c000634RR~R.", + srawi_3 = "7c000670RR~A.", + sradi_3 = "7c000674RR~H.", + eieio_0 = "7c0006ac", + lfiwax_3 = "7c0006aeFR0R", + sthbrx_3 = "7c00072cRR0R", + extsh_2 = "7c000734RR~.", + extsb_2 = "7c000774RR~.", + divduo_3 = "7c000792RRR.", + divwou_3 = "7c000796RRR.", + icbi_2 = "7c0007ac-RR", + stfiwx_3 = "7c0007aeFR0R", + extsw_2 = "7c0007b4RR~.", + divdo_3 = "7c0007d2RRR.", + divwo_3 = "7c0007d6RRR.", + dcbz_2 = "7c0007ec-RR", + + -- Primary opcode 30: + rldicl_4 = "78000000RR~HM.", + rldicr_4 = "78000004RR~HM.", + rldic_4 = "78000008RR~HM.", + rldimi_4 = "7800000cRR~HM.", + rldcl_4 = "78000010RR~RM.", + rldcr_4 = "78000012RR~RM.", + + -- Primary opcode 59: + fdivs_3 = "ec000024FFF.", + fsubs_3 = "ec000028FFF.", + fadds_3 = "ec00002aFFF.", + fsqrts_2 = "ec00002cF-F.", + fres_2 = "ec000030F-F.", + fmuls_3 = "ec000032FF-F.", + frsqrtes_2 = "ec000034F-F.", + fmsubs_4 = "ec000038FFFF~.", + fmadds_4 = "ec00003aFFFF~.", + fnmsubs_4 = "ec00003cFFFF~.", + fnmadds_4 = "ec00003eFFFF~.", + + -- Primary opcode 63: + fdiv_3 = "fc000024FFF.", + fsub_3 = "fc000028FFF.", + fadd_3 = "fc00002aFFF.", + fsqrt_2 = "fc00002cF-F.", + fsel_4 = "fc00002eFFFF~.", + fre_2 = "fc000030F-F.", + fmul_3 = "fc000032FF-F.", + frsqrte_2 = "fc000034F-F.", + fmsub_4 = "fc000038FFFF~.", + fmadd_4 = "fc00003aFFFF~.", + fnmsub_4 = "fc00003cFFFF~.", + fnmadd_4 = "fc00003eFFFF~.", + fcmpu_3 = "fc000000XFF", + fcpsgn_3 = "fc000010FFF.", + fcmpo_3 = "fc000040XFF", + mtfsb1_1 = "fc00004cA", + fneg_2 = "fc000050F-F.", + mcrfs_2 = "fc000080XX", + mtfsb0_1 = "fc00008cA", + fmr_2 = "fc000090F-F.", + frsp_2 = "fc000018F-F.", + fctiw_2 = "fc00001cF-F.", + fctiwz_2 = "fc00001eF-F.", + mtfsfi_2 = "fc00010cAA", -- NYI: upshift. + fnabs_2 = "fc000110F-F.", + fabs_2 = "fc000210F-F.", + frin_2 = "fc000310F-F.", + friz_2 = "fc000350F-F.", + frip_2 = "fc000390F-F.", + frim_2 = "fc0003d0F-F.", + mffs_1 = "fc00048eF.", + -- NYI: mtfsf, mtfsb0, mtfsb1. + fctid_2 = "fc00065cF-F.", + fctidz_2 = "fc00065eF-F.", + fcfid_2 = "fc00069cF-F.", + + -- Primary opcode 4, SPE APU extension: + evaddw_3 = "10000200RRR", + evaddiw_3 = "10000202RAR~", + evsubw_3 = "10000204RRR~", + evsubiw_3 = "10000206RAR~", + evabs_2 = "10000208RR", + evneg_2 = "10000209RR", + evextsb_2 = "1000020aRR", + evextsh_2 = "1000020bRR", + evrndw_2 = "1000020cRR", + evcntlzw_2 = "1000020dRR", + evcntlsw_2 = "1000020eRR", + brinc_3 = "1000020fRRR", + evand_3 = "10000211RRR", + evandc_3 = "10000212RRR", + evxor_3 = "10000216RRR", + evor_3 = "10000217RRR", + evmr_2 = "10000217RR=", + evnor_3 = "10000218RRR", + evnot_2 = "10000218RR=", + eveqv_3 = "10000219RRR", + evorc_3 = "1000021bRRR", + evnand_3 = "1000021eRRR", + evsrwu_3 = "10000220RRR", + evsrws_3 = "10000221RRR", + evsrwiu_3 = "10000222RRA", + evsrwis_3 = "10000223RRA", + evslw_3 = "10000224RRR", + evslwi_3 = "10000226RRA", + evrlw_3 = "10000228RRR", + evsplati_2 = "10000229RS", + evrlwi_3 = "1000022aRRA", + evsplatfi_2 = "1000022bRS", + evmergehi_3 = "1000022cRRR", + evmergelo_3 = "1000022dRRR", + evcmpgtu_3 = "10000230XRR", + evcmpgtu_2 = "10000230-RR", + evcmpgts_3 = "10000231XRR", + evcmpgts_2 = "10000231-RR", + evcmpltu_3 = "10000232XRR", + evcmpltu_2 = "10000232-RR", + evcmplts_3 = "10000233XRR", + evcmplts_2 = "10000233-RR", + evcmpeq_3 = "10000234XRR", + evcmpeq_2 = "10000234-RR", + evsel_4 = "10000278RRRW", + evsel_3 = "10000278RRR", + evfsadd_3 = "10000280RRR", + evfssub_3 = "10000281RRR", + evfsabs_2 = "10000284RR", + evfsnabs_2 = "10000285RR", + evfsneg_2 = "10000286RR", + evfsmul_3 = "10000288RRR", + evfsdiv_3 = "10000289RRR", + evfscmpgt_3 = "1000028cXRR", + evfscmpgt_2 = "1000028c-RR", + evfscmplt_3 = "1000028dXRR", + evfscmplt_2 = "1000028d-RR", + evfscmpeq_3 = "1000028eXRR", + evfscmpeq_2 = "1000028e-RR", + evfscfui_2 = "10000290R-R", + evfscfsi_2 = "10000291R-R", + evfscfuf_2 = "10000292R-R", + evfscfsf_2 = "10000293R-R", + evfsctui_2 = "10000294R-R", + evfsctsi_2 = "10000295R-R", + evfsctuf_2 = "10000296R-R", + evfsctsf_2 = "10000297R-R", + evfsctuiz_2 = "10000298R-R", + evfsctsiz_2 = "1000029aR-R", + evfststgt_3 = "1000029cXRR", + evfststgt_2 = "1000029c-RR", + evfststlt_3 = "1000029dXRR", + evfststlt_2 = "1000029d-RR", + evfststeq_3 = "1000029eXRR", + evfststeq_2 = "1000029e-RR", + efsadd_3 = "100002c0RRR", + efssub_3 = "100002c1RRR", + efsabs_2 = "100002c4RR", + efsnabs_2 = "100002c5RR", + efsneg_2 = "100002c6RR", + efsmul_3 = "100002c8RRR", + efsdiv_3 = "100002c9RRR", + efscmpgt_3 = "100002ccXRR", + efscmpgt_2 = "100002cc-RR", + efscmplt_3 = "100002cdXRR", + efscmplt_2 = "100002cd-RR", + efscmpeq_3 = "100002ceXRR", + efscmpeq_2 = "100002ce-RR", + efscfd_2 = "100002cfR-R", + efscfui_2 = "100002d0R-R", + efscfsi_2 = "100002d1R-R", + efscfuf_2 = "100002d2R-R", + efscfsf_2 = "100002d3R-R", + efsctui_2 = "100002d4R-R", + efsctsi_2 = "100002d5R-R", + efsctuf_2 = "100002d6R-R", + efsctsf_2 = "100002d7R-R", + efsctuiz_2 = "100002d8R-R", + efsctsiz_2 = "100002daR-R", + efststgt_3 = "100002dcXRR", + efststgt_2 = "100002dc-RR", + efststlt_3 = "100002ddXRR", + efststlt_2 = "100002dd-RR", + efststeq_3 = "100002deXRR", + efststeq_2 = "100002de-RR", + efdadd_3 = "100002e0RRR", + efdsub_3 = "100002e1RRR", + efdcfuid_2 = "100002e2R-R", + efdcfsid_2 = "100002e3R-R", + efdabs_2 = "100002e4RR", + efdnabs_2 = "100002e5RR", + efdneg_2 = "100002e6RR", + efdmul_3 = "100002e8RRR", + efddiv_3 = "100002e9RRR", + efdctuidz_2 = "100002eaR-R", + efdctsidz_2 = "100002ebR-R", + efdcmpgt_3 = "100002ecXRR", + efdcmpgt_2 = "100002ec-RR", + efdcmplt_3 = "100002edXRR", + efdcmplt_2 = "100002ed-RR", + efdcmpeq_3 = "100002eeXRR", + efdcmpeq_2 = "100002ee-RR", + efdcfs_2 = "100002efR-R", + efdcfui_2 = "100002f0R-R", + efdcfsi_2 = "100002f1R-R", + efdcfuf_2 = "100002f2R-R", + efdcfsf_2 = "100002f3R-R", + efdctui_2 = "100002f4R-R", + efdctsi_2 = "100002f5R-R", + efdctuf_2 = "100002f6R-R", + efdctsf_2 = "100002f7R-R", + efdctuiz_2 = "100002f8R-R", + efdctsiz_2 = "100002faR-R", + efdtstgt_3 = "100002fcXRR", + efdtstgt_2 = "100002fc-RR", + efdtstlt_3 = "100002fdXRR", + efdtstlt_2 = "100002fd-RR", + efdtsteq_3 = "100002feXRR", + efdtsteq_2 = "100002fe-RR", + evlddx_3 = "10000300RR0R", + evldd_2 = "10000301R8", + evldwx_3 = "10000302RR0R", + evldw_2 = "10000303R8", + evldhx_3 = "10000304RR0R", + evldh_2 = "10000305R8", + evlwhex_3 = "10000310RR0R", + evlwhe_2 = "10000311R4", + evlwhoux_3 = "10000314RR0R", + evlwhou_2 = "10000315R4", + evlwhosx_3 = "10000316RR0R", + evlwhos_2 = "10000317R4", + evstddx_3 = "10000320RR0R", + evstdd_2 = "10000321R8", + evstdwx_3 = "10000322RR0R", + evstdw_2 = "10000323R8", + evstdhx_3 = "10000324RR0R", + evstdh_2 = "10000325R8", + evstwhex_3 = "10000330RR0R", + evstwhe_2 = "10000331R4", + evstwhox_3 = "10000334RR0R", + evstwho_2 = "10000335R4", + evstwwex_3 = "10000338RR0R", + evstwwe_2 = "10000339R4", + evstwwox_3 = "1000033cRR0R", + evstwwo_2 = "1000033dR4", + evmhessf_3 = "10000403RRR", + evmhossf_3 = "10000407RRR", + evmheumi_3 = "10000408RRR", + evmhesmi_3 = "10000409RRR", + evmhesmf_3 = "1000040bRRR", + evmhoumi_3 = "1000040cRRR", + evmhosmi_3 = "1000040dRRR", + evmhosmf_3 = "1000040fRRR", + evmhessfa_3 = "10000423RRR", + evmhossfa_3 = "10000427RRR", + evmheumia_3 = "10000428RRR", + evmhesmia_3 = "10000429RRR", + evmhesmfa_3 = "1000042bRRR", + evmhoumia_3 = "1000042cRRR", + evmhosmia_3 = "1000042dRRR", + evmhosmfa_3 = "1000042fRRR", + evmwhssf_3 = "10000447RRR", + evmwlumi_3 = "10000448RRR", + evmwhumi_3 = "1000044cRRR", + evmwhsmi_3 = "1000044dRRR", + evmwhsmf_3 = "1000044fRRR", + evmwssf_3 = "10000453RRR", + evmwumi_3 = "10000458RRR", + evmwsmi_3 = "10000459RRR", + evmwsmf_3 = "1000045bRRR", + evmwhssfa_3 = "10000467RRR", + evmwlumia_3 = "10000468RRR", + evmwhumia_3 = "1000046cRRR", + evmwhsmia_3 = "1000046dRRR", + evmwhsmfa_3 = "1000046fRRR", + evmwssfa_3 = "10000473RRR", + evmwumia_3 = "10000478RRR", + evmwsmia_3 = "10000479RRR", + evmwsmfa_3 = "1000047bRRR", + evmra_2 = "100004c4RR", + evdivws_3 = "100004c6RRR", + evdivwu_3 = "100004c7RRR", + evmwssfaa_3 = "10000553RRR", + evmwumiaa_3 = "10000558RRR", + evmwsmiaa_3 = "10000559RRR", + evmwsmfaa_3 = "1000055bRRR", + evmwssfan_3 = "100005d3RRR", + evmwumian_3 = "100005d8RRR", + evmwsmian_3 = "100005d9RRR", + evmwsmfan_3 = "100005dbRRR", + evmergehilo_3 = "1000022eRRR", + evmergelohi_3 = "1000022fRRR", + evlhhesplatx_3 = "10000308RR0R", + evlhhesplat_2 = "10000309R2", + evlhhousplatx_3 = "1000030cRR0R", + evlhhousplat_2 = "1000030dR2", + evlhhossplatx_3 = "1000030eRR0R", + evlhhossplat_2 = "1000030fR2", + evlwwsplatx_3 = "10000318RR0R", + evlwwsplat_2 = "10000319R4", + evlwhsplatx_3 = "1000031cRR0R", + evlwhsplat_2 = "1000031dR4", + evaddusiaaw_2 = "100004c0RR", + evaddssiaaw_2 = "100004c1RR", + evsubfusiaaw_2 = "100004c2RR", + evsubfssiaaw_2 = "100004c3RR", + evaddumiaaw_2 = "100004c8RR", + evaddsmiaaw_2 = "100004c9RR", + evsubfumiaaw_2 = "100004caRR", + evsubfsmiaaw_2 = "100004cbRR", + evmheusiaaw_3 = "10000500RRR", + evmhessiaaw_3 = "10000501RRR", + evmhessfaaw_3 = "10000503RRR", + evmhousiaaw_3 = "10000504RRR", + evmhossiaaw_3 = "10000505RRR", + evmhossfaaw_3 = "10000507RRR", + evmheumiaaw_3 = "10000508RRR", + evmhesmiaaw_3 = "10000509RRR", + evmhesmfaaw_3 = "1000050bRRR", + evmhoumiaaw_3 = "1000050cRRR", + evmhosmiaaw_3 = "1000050dRRR", + evmhosmfaaw_3 = "1000050fRRR", + evmhegumiaa_3 = "10000528RRR", + evmhegsmiaa_3 = "10000529RRR", + evmhegsmfaa_3 = "1000052bRRR", + evmhogumiaa_3 = "1000052cRRR", + evmhogsmiaa_3 = "1000052dRRR", + evmhogsmfaa_3 = "1000052fRRR", + evmwlusiaaw_3 = "10000540RRR", + evmwlssiaaw_3 = "10000541RRR", + evmwlumiaaw_3 = "10000548RRR", + evmwlsmiaaw_3 = "10000549RRR", + evmheusianw_3 = "10000580RRR", + evmhessianw_3 = "10000581RRR", + evmhessfanw_3 = "10000583RRR", + evmhousianw_3 = "10000584RRR", + evmhossianw_3 = "10000585RRR", + evmhossfanw_3 = "10000587RRR", + evmheumianw_3 = "10000588RRR", + evmhesmianw_3 = "10000589RRR", + evmhesmfanw_3 = "1000058bRRR", + evmhoumianw_3 = "1000058cRRR", + evmhosmianw_3 = "1000058dRRR", + evmhosmfanw_3 = "1000058fRRR", + evmhegumian_3 = "100005a8RRR", + evmhegsmian_3 = "100005a9RRR", + evmhegsmfan_3 = "100005abRRR", + evmhogumian_3 = "100005acRRR", + evmhogsmian_3 = "100005adRRR", + evmhogsmfan_3 = "100005afRRR", + evmwlusianw_3 = "100005c0RRR", + evmwlssianw_3 = "100005c1RRR", + evmwlumianw_3 = "100005c8RRR", + evmwlsmianw_3 = "100005c9RRR", + + -- NYI: Book E instructions. +} + +-- Add mnemonics for "." variants. +do + local t = {} + for k,v in pairs(map_op) do + if sub(v, -1) == "." then + local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2) + t[sub(k, 1, -3).."."..sub(k, -2)] = v2 + end + end + for k,v in pairs(t) do + map_op[k] = v + end +end + +-- Add more branch mnemonics. +for cond,c in pairs(map_cond) do + local b1 = "b"..cond + local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0) + -- bX[l] + map_op[b1.."_1"] = tohex(0x40800000 + c1).."K" + map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K" + map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K" + map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK" + map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK" + map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK" + -- bXlr[l] + map_op[b1.."lr_0"] = tohex(0x4c800020 + c1) + map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1) + map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1) + map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1) + -- bXctr[l] + map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X" + map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X" + map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X" + map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X" +end + +------------------------------------------------------------------------------ + +local function parse_gpr(expr) + local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + if not reg then + werror("type `"..(tname or expr).."' needs a register override") + end + expr = reg + end + local r = match(expr, "^r([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r, tp end + end + werror("bad register name `"..expr.."'") +end + +local function parse_fpr(expr) + local r = match(expr, "^f([1-3]?[0-9])$") + if r then + r = tonumber(r) + if r <= 31 then return r end + end + werror("bad register name `"..expr.."'") +end + +local function parse_cr(expr) + local r = match(expr, "^cr([0-7])$") + if r then return tonumber(r) end + werror("bad condition register name `"..expr.."'") +end + +local function parse_cond(expr) + local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$") + if r then + r = tonumber(r) + local c = map_cond[cond] + if c and c < 4 then return r*4+c end + end + werror("bad condition bit name `"..expr.."'") +end + +local function parse_imm(imm, bits, shift, scale, signed) + local n = tonumber(imm) + if n then + local m = sar(n, scale) + if shl(m, scale) == n then + if signed then + local s = sar(m, bits-1) + if s == 0 then return shl(m, shift) + elseif s == -1 then return shl(m + shl(1, bits), shift) end + else + if sar(m, bits) == 0 then return shl(m, shift) end + end + end + werror("out of range immediate `"..imm.."'") + elseif match(imm, "^r([1-3]?[0-9])$") or + match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then + werror("expected immediate operand, got register") + else + waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) + return 0 + end +end + +local function parse_shiftmask(imm, isshift) + local n = tonumber(imm) + if n then + if shr(n, 6) == 0 then + local lsb = band(imm, 31) + local msb = imm - lsb + return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb) + end + werror("out of range immediate `"..imm.."'") + elseif match(imm, "^r([1-3]?[0-9])$") or + match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then + werror("expected immediate operand, got register") + else + werror("NYI: parameterized 64 bit shift/mask") + end +end + +local function parse_disp(disp) + local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") + if imm then + local r = parse_gpr(reg) + if r == 0 then werror("cannot use r0 in displacement") end + return shl(r, 16) + parse_imm(imm, 16, 0, 0, true) + end + local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local r, tp = parse_gpr(reg) + if r == 0 then werror("cannot use r0 in displacement") end + if tp then + waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) + return shl(r, 16) + end + end + werror("bad displacement `"..disp.."'") +end + +local function parse_u5disp(disp, scale) + local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") + if imm then + local r = parse_gpr(reg) + if r == 0 then werror("cannot use r0 in displacement") end + return shl(r, 16) + parse_imm(imm, 5, 11, scale, false) + end + local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") + if reg and tailr ~= "" then + local r, tp = parse_gpr(reg) + if r == 0 then werror("cannot use r0 in displacement") end + if tp then + waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr)) + return shl(r, 16) + end + end + werror("bad displacement `"..disp.."'") +end + +local function parse_label(label, def) + local prefix = sub(label, 1, 2) + -- =>label (pc label reference) + if prefix == "=>" then + return "PC", 0, sub(label, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "LG", map_global[sub(label, 3)] + end + if def then + -- [1-9] (local label definition) + if match(label, "^[1-9]$") then + return "LG", 10+tonumber(label) + end + else + -- [<>][1-9] (local label reference) + local dir, lnum = match(label, "^([<>])([1-9])$") + if dir then -- Fwd: 1-9, Bkwd: 11-19. + return "LG", lnum + (dir == ">" and 0 or 10) + end + -- extern label (extern label reference) + local extname = match(label, "^extern%s+(%S+)$") + if extname then + return "EXT", map_extern[extname] + end + end + werror("bad label `"..label.."'") +end + +------------------------------------------------------------------------------ + +-- Handle opcodes defined with template strings. +map_op[".template__"] = function(params, template, nparams) + if not params then return sub(template, 9) end + local op = tonumber(sub(template, 1, 8), 16) + local n, rs = 1, 26 + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 3 positions (rlwinm). + if secpos+3 > maxsecpos then wflush() end + local pos = wpos() + + -- Process each character. + for p in gmatch(sub(template, 9), ".") do + if p == "R" then + rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1 + elseif p == "F" then + rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1 + elseif p == "A" then + rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1 + elseif p == "S" then + rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1 + elseif p == "I" then + op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 + elseif p == "U" then + op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 + elseif p == "D" then + op = op + parse_disp(params[n]); n = n + 1 + elseif p == "2" then + op = op + parse_u5disp(params[n], 1); n = n + 1 + elseif p == "4" then + op = op + parse_u5disp(params[n], 2); n = n + 1 + elseif p == "8" then + op = op + parse_u5disp(params[n], 3); n = n + 1 + elseif p == "C" then + rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1 + elseif p == "X" then + rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1 + elseif p == "W" then + op = op + parse_cr(params[n]); n = n + 1 + elseif p == "G" then + op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1 + elseif p == "H" then + op = op + parse_shiftmask(params[n], true); n = n + 1 + elseif p == "M" then + op = op + parse_shiftmask(params[n], false); n = n + 1 + elseif p == "J" or p == "K" then + local mode, n, s = parse_label(params[n], false) + if p == "K" then n = n + 2048 end + waction("REL_"..mode, n, s, 1) + n = n + 1 + elseif p == "0" then + if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end + elseif p == "=" or p == "%" then + local t = band(shr(op, p == "%" and rs+5 or rs), 31) + rs = rs - 5 + op = op + shl(t, rs) + elseif p == "~" then + local mm = shl(31, rs) + local lo = band(op, mm) + local hi = band(op, shl(mm, 5)) + op = op - lo - hi + shl(lo, 5) + shr(hi, 5) + elseif p == "-" then + rs = rs - 5 + elseif p == "." then + -- Ignored. + else + assert(false) + end + end + wputpos(pos, op) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode to mark the position where the action list is to be emitted. +map_op[".actionlist_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeactions(out, name) end) +end + +-- Pseudo-opcode to mark the position where the global enum is to be emitted. +map_op[".globals_1"] = function(params) + if not params then return "prefix" end + local prefix = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobals(out, prefix) end) +end + +-- Pseudo-opcode to mark the position where the global names are to be emitted. +map_op[".globalnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobalnames(out, name) end) +end + +-- Pseudo-opcode to mark the position where the extern names are to be emitted. +map_op[".externnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeexternnames(out, name) end) +end + +------------------------------------------------------------------------------ + +-- Label pseudo-opcode (converted from trailing colon form). +map_op[".label_1"] = function(params) + if not params then return "[1-9] | ->global | =>pcexpr" end + if secpos+1 > maxsecpos then wflush() end + local mode, n, s = parse_label(params[1], true) + if mode == "EXT" then werror("bad label definition") end + waction("LABEL_"..mode, n, s, 1) +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcodes for data storage. +map_op[".long_*"] = function(params) + if not params then return "imm..." end + for _,p in ipairs(params) do + local n = tonumber(p) + if not n then werror("bad immediate `"..p.."'") end + if n < 0 then n = n + 2^32 end + wputw(n) + if secpos+2 > maxsecpos then wflush() end + end +end + +-- Alignment pseudo-opcode. +map_op[".align_1"] = function(params) + if not params then return "numpow2" end + if secpos+1 > maxsecpos then wflush() end + local align = tonumber(params[1]) + if align then + local x = align + -- Must be a power of 2 in the range (2 ... 256). + for i=1,8 do + x = x / 2 + if x == 1 then + waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. + return + end + end + end + werror("bad alignment") +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcode for (primitive) type definitions (map to C types). +map_op[".type_3"] = function(params, nparams) + if not params then + return nparams == 2 and "name, ctype" or "name, ctype, reg" + end + local name, ctype, reg = params[1], params[2], params[3] + if not match(name, "^[%a_][%w_]*$") then + werror("bad type name `"..name.."'") + end + local tp = map_type[name] + if tp then + werror("duplicate type `"..name.."'") + end + -- Add #type to defines. A bit unclean to put it in map_archdef. + map_archdef["#"..name] = "sizeof("..ctype..")" + -- Add new type and emit shortcut define. + local num = ctypenum + 1 + map_type[name] = { + ctype = ctype, + ctypefmt = format("Dt%X(%%s)", num), + reg = reg, + } + wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) + ctypenum = num +end +map_op[".type_2"] = map_op[".type_3"] + +-- Dump type definitions. +local function dumptypes(out, lvl) + local t = {} + for name in pairs(map_type) do t[#t+1] = name end + sort(t) + out:write("Type definitions:\n") + for _,name in ipairs(t) do + local tp = map_type[name] + local reg = tp.reg or "" + out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Set the current section. +function _M.section(num) + waction("SECTION", num) + wflush(true) -- SECTION is a terminal action. +end + +------------------------------------------------------------------------------ + +-- Dump architecture description. +function _M.dumparch(out) + out:write(format("DynASM %s version %s, released %s\n\n", + _info.arch, _info.version, _info.release)) + dumpactions(out) +end + +-- Dump all user defined elements. +function _M.dumpdef(out, lvl) + dumptypes(out, lvl) + dumpglobals(out, lvl) + dumpexterns(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Pass callbacks from/to the DynASM core. +function _M.passcb(wl, we, wf, ww) + wline, werror, wfatal, wwarn = wl, we, wf, ww + return wflush +end + +-- Setup the arch-specific module. +function _M.setup(arch, opt) + g_arch, g_opt = arch, opt +end + +-- Merge the core maps and the arch-specific maps. +function _M.mergemaps(map_coreop, map_def) + setmetatable(map_op, { __index = map_coreop }) + setmetatable(map_def, { __index = map_archdef }) + return map_op, map_def +end + +return _M + +------------------------------------------------------------------------------ + diff --git a/lib/sregex/dynasm/dasm_proto.h b/lib/sregex/dynasm/dasm_proto.h new file mode 100644 index 0000000..3002811 --- /dev/null +++ b/lib/sregex/dynasm/dasm_proto.h @@ -0,0 +1,83 @@ +/* +** DynASM encoding engine prototypes. +** Copyright (C) 2005-2012 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#ifndef _DASM_PROTO_H +#define _DASM_PROTO_H + +#include +#include + +#define DASM_IDENT "DynASM 1.3.0" +#define DASM_VERSION 10300 /* 1.3.0 */ + +#ifndef Dst_DECL +#define Dst_DECL dasm_State **Dst +#endif + +#ifndef Dst_REF +#define Dst_REF (*Dst) +#endif + +#ifndef DASM_FDEF +#define DASM_FDEF extern +#endif + +#ifndef DASM_M_GROW +#define DASM_M_GROW(ctx, t, p, sz, need) \ + do { \ + size_t _sz = (sz), _need = (need); \ + if (_sz < _need) { \ + if (_sz < 16) _sz = 16; \ + while (_sz < _need) _sz += _sz; \ + (p) = (t *)realloc((p), _sz); \ + if ((p) == NULL) exit(1); \ + (sz) = _sz; \ + } \ + } while(0) +#endif + +#ifndef DASM_M_FREE +#define DASM_M_FREE(ctx, p, sz) free(p) +#endif + +/* Internal DynASM encoder state. */ +typedef struct dasm_State dasm_State; + + +/* Initialize and free DynASM state. */ +DASM_FDEF void dasm_init(Dst_DECL, int maxsection); +DASM_FDEF void dasm_free(Dst_DECL); + +/* Setup global array. Must be called before dasm_setup(). */ +DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); + +/* Setup encoder. */ +DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); + +/* Feed encoder with actions. Calls are generated by pre-processor. */ +DASM_FDEF void dasm_put(Dst_DECL, int start, ...); + +/* Link sections and return the resulting size. */ +DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); + +/* Encode sections into buffer. */ +DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); + +/* Get PC label offset. */ +DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); +#else +#define dasm_checkstep(a, b) 0 +#endif + + +#endif /* _DASM_PROTO_H */ diff --git a/lib/sregex/dynasm/dasm_x64.lua b/lib/sregex/dynasm/dasm_x64.lua new file mode 100644 index 0000000..bae72ac --- /dev/null +++ b/lib/sregex/dynasm/dasm_x64.lua @@ -0,0 +1,12 @@ +------------------------------------------------------------------------------ +-- DynASM x64 module. +-- +-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ +-- This module just sets 64 bit mode for the combined x86/x64 module. +-- All the interesting stuff is there. +------------------------------------------------------------------------------ + +x64 = true -- Using a global is an ugly, but effective solution. +return require("dasm_x86") diff --git a/lib/sregex/dynasm/dasm_x86.h b/lib/sregex/dynasm/dasm_x86.h new file mode 100644 index 0000000..7c6dcd3 --- /dev/null +++ b/lib/sregex/dynasm/dasm_x86.h @@ -0,0 +1,470 @@ +/* +** DynASM x86 encoding engine. +** Copyright (C) 2005-2012 Mike Pall. All rights reserved. +** Released under the MIT license. See dynasm.lua for full copyright notice. +*/ + +#include +#include +#include +#include + +#define DASM_ARCH "x86" + +#ifndef DASM_EXTERN +#define DASM_EXTERN(a,b,c,d) 0 +#endif + +/* Action definitions. DASM_STOP must be 255. */ +enum { + DASM_DISP = 233, + DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, + DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, + DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, + DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP +}; + +/* Maximum number of section buffer positions for a single dasm_put() call. */ +#define DASM_MAXSECPOS 25 + +/* DynASM encoder status codes. Action list offset or number are or'ed in. */ +#define DASM_S_OK 0x00000000 +#define DASM_S_NOMEM 0x01000000 +#define DASM_S_PHASE 0x02000000 +#define DASM_S_MATCH_SEC 0x03000000 +#define DASM_S_RANGE_I 0x11000000 +#define DASM_S_RANGE_SEC 0x12000000 +#define DASM_S_RANGE_LG 0x13000000 +#define DASM_S_RANGE_PC 0x14000000 +#define DASM_S_RANGE_VREG 0x15000000 +#define DASM_S_UNDEF_L 0x21000000 +#define DASM_S_UNDEF_PC 0x22000000 + +/* Macros to convert positions (8 bit section + 24 bit index). */ +#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) +#define DASM_POS2BIAS(pos) ((pos)&0xff000000) +#define DASM_SEC2POS(sec) ((sec)<<24) +#define DASM_POS2SEC(pos) ((pos)>>24) +#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) + +/* Action list type. */ +typedef const unsigned char *dasm_ActList; + +/* Per-section structure. */ +typedef struct dasm_Section { + int *rbuf; /* Biased buffer pointer (negative section bias). */ + int *buf; /* True buffer pointer. */ + size_t bsize; /* Buffer size in bytes. */ + int pos; /* Biased buffer position. */ + int epos; /* End of biased buffer position - max single put. */ + int ofs; /* Byte offset into section. */ +} dasm_Section; + +/* Core structure holding the DynASM encoding state. */ +struct dasm_State { + size_t psize; /* Allocated size of this structure. */ + dasm_ActList actionlist; /* Current actionlist pointer. */ + int *lglabels; /* Local/global chain/pos ptrs. */ + size_t lgsize; + int *pclabels; /* PC label chains/pos ptrs. */ + size_t pcsize; + void **globals; /* Array of globals (bias -10). */ + dasm_Section *section; /* Pointer to active section. */ + size_t codesize; /* Total size of all code sections. */ + int maxsection; /* 0 <= sectionidx < maxsection. */ + int status; /* Status code. */ + dasm_Section sections[1]; /* All sections. Alloc-extended. */ +}; + +/* The size of the core structure depends on the max. number of sections. */ +#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) + + +/* Initialize DynASM state. */ +void dasm_init(Dst_DECL, int maxsection) +{ + dasm_State *D; + size_t psz = 0; + int i; + Dst_REF = NULL; + DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); + D = Dst_REF; + D->psize = psz; + D->lglabels = NULL; + D->lgsize = 0; + D->pclabels = NULL; + D->pcsize = 0; + D->globals = NULL; + D->maxsection = maxsection; + for (i = 0; i < maxsection; i++) { + D->sections[i].buf = NULL; /* Need this for pass3. */ + D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); + D->sections[i].bsize = 0; + D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ + } +} + +/* Free DynASM state. */ +void dasm_free(Dst_DECL) +{ + dasm_State *D = Dst_REF; + int i; + for (i = 0; i < D->maxsection; i++) + if (D->sections[i].buf) + DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); + if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); + if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); + DASM_M_FREE(Dst, D, D->psize); +} + +/* Setup global label array. Must be called before dasm_setup(). */ +void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) +{ + dasm_State *D = Dst_REF; + D->globals = gl - 10; /* Negative bias to compensate for locals. */ + DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); +} + +/* Grow PC label array. Can be called after dasm_setup(), too. */ +void dasm_growpc(Dst_DECL, unsigned int maxpc) +{ + dasm_State *D = Dst_REF; + size_t osz = D->pcsize; + DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); + memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); +} + +/* Setup encoder. */ +void dasm_setup(Dst_DECL, const void *actionlist) +{ + dasm_State *D = Dst_REF; + int i; + D->actionlist = (dasm_ActList)actionlist; + D->status = DASM_S_OK; + D->section = &D->sections[0]; + memset((void *)D->lglabels, 0, D->lgsize); + if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); + for (i = 0; i < D->maxsection; i++) { + D->sections[i].pos = DASM_SEC2POS(i); + D->sections[i].ofs = 0; + } +} + + +#ifdef DASM_CHECKS +#define CK(x, st) \ + do { if (!(x)) { \ + D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) +#define CKPL(kind, st) \ + do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ + D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) +#else +#define CK(x, st) ((void)0) +#define CKPL(kind, st) ((void)0) +#endif + +/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ +void dasm_put(Dst_DECL, int start, ...) +{ + va_list ap; + dasm_State *D = Dst_REF; + dasm_ActList p = D->actionlist + start; + dasm_Section *sec = D->section; + int pos = sec->pos, ofs = sec->ofs, mrm = 4; + int *b; + + if (pos >= sec->epos) { + DASM_M_GROW(Dst, int, sec->buf, sec->bsize, + sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); + sec->rbuf = sec->buf - DASM_POS2BIAS(pos); + sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); + } + + b = sec->rbuf; + b[pos++] = start; + + va_start(ap, start); + while (1) { + int action = *p++; + if (action < DASM_DISP) { + ofs++; + } else if (action <= DASM_REL_A) { + int n = va_arg(ap, int); + b[pos++] = n; + switch (action) { + case DASM_DISP: + if (n == 0) { if ((mrm&7) == 4) mrm = p[-2]; if ((mrm&7) != 5) break; } + case DASM_IMM_DB: if (((n+128)&-256) == 0) goto ob; + case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ + case DASM_IMM_D: ofs += 4; break; + case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; + case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; + case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; + case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; + case DASM_SPACE: p++; ofs += n; break; + case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ + case DASM_VREG: CK((n&-8) == 0 && (n != 4 || (*p&1) == 0), RANGE_VREG); + if (*p++ == 1 && *p == DASM_DISP) mrm = n; continue; + } + mrm = 4; + } else { + int *pl, n; + switch (action) { + case DASM_REL_LG: + case DASM_IMM_LG: + n = *p++; pl = D->lglabels + n; + if (n <= 246) { CKPL(lg, LG); goto putrel; } /* Bkwd rel or global. */ + pl -= 246; n = *pl; + if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ + goto linkrel; + case DASM_REL_PC: + case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); + putrel: + n = *pl; + if (n < 0) { /* Label exists. Get label pos and store it. */ + b[pos] = -n; + } else { + linkrel: + b[pos] = n; /* Else link to rel chain, anchored at label. */ + *pl = pos; + } + pos++; + ofs += 4; /* Maximum offset needed. */ + if (action == DASM_REL_LG || action == DASM_REL_PC) + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; + case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); + putlabel: + n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } + *pl = -pos; /* Label exists now. */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_ALIGN: + ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ + b[pos++] = ofs; /* Store pass1 offset estimate. */ + break; + case DASM_EXTERN: p += 2; ofs += 4; break; + case DASM_ESC: p++; ofs++; break; + case DASM_MARK: mrm = p[-2]; break; + case DASM_SECTION: + n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; + case DASM_STOP: goto stop; + } + } + } +stop: + va_end(ap); + sec->pos = pos; + sec->ofs = ofs; +} +#undef CK + +/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ +int dasm_link(Dst_DECL, size_t *szp) +{ + dasm_State *D = Dst_REF; + int secnum; + int ofs = 0; + +#ifdef DASM_CHECKS + *szp = 0; + if (D->status != DASM_S_OK) return D->status; + { + int pc; + for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) + if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; + } +#endif + + { /* Handle globals not defined in this translation unit. */ + int idx; + for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { + int n = D->lglabels[idx]; + /* Undefined label: Collapse rel chain and replace with marker (< 0). */ + while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } + } + } + + /* Combine all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->rbuf; + int pos = DASM_SEC2POS(secnum); + int lastpos = sec->pos; + + while (pos != lastpos) { + dasm_ActList p = D->actionlist + b[pos++]; + while (1) { + int op, action = *p++; + switch (action) { + case DASM_REL_LG: p++; op = p[-3]; goto rel_pc; + case DASM_REL_PC: op = p[-2]; rel_pc: { + int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); + if (shrink) { /* Shrinkable branch opcode? */ + int lofs, lpos = b[pos]; + if (lpos < 0) goto noshrink; /* Ext global? */ + lofs = *DASM_POS2PTR(D, lpos); + if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ + int i; + for (i = secnum; i < DASM_POS2SEC(lpos); i++) + lofs += D->sections[i].ofs; + } else { + lofs -= ofs; /* Bkwd label: unfix offset. */ + } + lofs -= b[pos+1]; /* Short branch ok? */ + if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ + else { noshrink: shrink = 0; } /* No, cannot shrink op. */ + } + b[pos+1] = shrink; + pos += 2; + break; + } + case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; + case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: + case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: + case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; + case DASM_LABEL_LG: p++; + case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ + case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ + case DASM_EXTERN: p += 2; break; + case DASM_ESC: p++; break; + case DASM_MARK: break; + case DASM_SECTION: case DASM_STOP: goto stop; + } + } + stop: (void)0; + } + ofs += sec->ofs; /* Next section starts right after current section. */ + } + + D->codesize = ofs; /* Total size of all code sections */ + *szp = ofs; + return DASM_S_OK; +} + +#define dasmb(x) *cp++ = (unsigned char)(x) +#ifndef DASM_ALIGNED_WRITES +#define dasmw(x) \ + do { *((unsigned short *)cp) = (unsigned short)(x); cp+=2; } while (0) +#define dasmd(x) \ + do { *((unsigned int *)cp) = (unsigned int)(x); cp+=4; } while (0) +#else +#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) +#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) +#endif + +/* Pass 3: Encode sections. */ +int dasm_encode(Dst_DECL, void *buffer) +{ + dasm_State *D = Dst_REF; + unsigned char *base = (unsigned char *)buffer; + unsigned char *cp = base; + int secnum; + + /* Encode all code sections. No support for data sections (yet). */ + for (secnum = 0; secnum < D->maxsection; secnum++) { + dasm_Section *sec = D->sections + secnum; + int *b = sec->buf; + int *endb = sec->rbuf + sec->pos; + + while (b != endb) { + dasm_ActList p = D->actionlist + *b++; + unsigned char *mark = NULL; + while (1) { + int action = *p++; + int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; + switch (action) { + case DASM_DISP: if (!mark) mark = cp; { + unsigned char *mm = mark; + if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; + if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; + if (mrm != 5) { mm[-1] -= 0x80; break; } } + if (((n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; + } + case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; + case DASM_IMM_DB: if (((n+128)&-256) == 0) { + db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; + } else mark = NULL; + case DASM_IMM_D: wd: dasmd(n); break; + case DASM_IMM_WB: if (((n+128)&-256) == 0) goto db; else mark = NULL; + case DASM_IMM_W: dasmw(n); break; + case DASM_VREG: { int t = *p++; if (t >= 2) n<<=3; cp[-1] |= n; break; } + case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; + b++; n = (int)(ptrdiff_t)D->globals[-n]; + case DASM_REL_A: rel_a: n -= (int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ + case DASM_REL_PC: rel_pc: { + int shrink = *b++; + int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } + n = *pb - ((int)(cp-base) + 4-shrink); + if (shrink == 0) goto wd; + if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; + goto wb; + } + case DASM_IMM_LG: + p++; if (n < 0) { n = (int)(ptrdiff_t)D->globals[-n]; goto wd; } + case DASM_IMM_PC: { + int *pb = DASM_POS2PTR(D, n); + n = *pb < 0 ? pb[1] : (*pb + (int)(ptrdiff_t)base); + goto wd; + } + case DASM_LABEL_LG: { + int idx = *p++; + if (idx >= 10) + D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); + break; + } + case DASM_LABEL_PC: case DASM_SETLABEL: break; + case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } + case DASM_ALIGN: + n = *p++; + while (((cp-base) & n)) *cp++ = 0x90; /* nop */ + break; + case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; + case DASM_MARK: mark = cp; break; + case DASM_ESC: action = *p++; + default: *cp++ = action; break; + case DASM_SECTION: case DASM_STOP: goto stop; + } + } + stop: (void)0; + } + } + + if (base + D->codesize != cp) /* Check for phase errors. */ + return DASM_S_PHASE; + return DASM_S_OK; +} + +/* Get PC label offset. */ +int dasm_getpclabel(Dst_DECL, unsigned int pc) +{ + dasm_State *D = Dst_REF; + if (pc*sizeof(int) < D->pcsize) { + int pos = D->pclabels[pc]; + if (pos < 0) return *DASM_POS2PTR(D, -pos); + if (pos > 0) return -1; /* Undefined. */ + } + return -2; /* Unused or out of range. */ +} + +#ifdef DASM_CHECKS +/* Optional sanity checker to call between isolated encoding steps. */ +int dasm_checkstep(Dst_DECL, int secmatch) +{ + dasm_State *D = Dst_REF; + if (D->status == DASM_S_OK) { + int i; + for (i = 1; i <= 9; i++) { + if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } + D->lglabels[i] = 0; + } + } + if (D->status == DASM_S_OK && secmatch >= 0 && + D->section != &D->sections[secmatch]) + D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); + return D->status; +} +#endif + diff --git a/lib/sregex/dynasm/dasm_x86.lua b/lib/sregex/dynasm/dasm_x86.lua new file mode 100644 index 0000000..a5f5c37 --- /dev/null +++ b/lib/sregex/dynasm/dasm_x86.lua @@ -0,0 +1,1931 @@ +------------------------------------------------------------------------------ +-- DynASM x86/x64 module. +-- +-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. +-- See dynasm.lua for full copyright notice. +------------------------------------------------------------------------------ + +local x64 = x64 + +-- Module information: +local _info = { + arch = x64 and "x64" or "x86", + description = "DynASM x86/x64 module", + version = "1.3.0", + vernum = 10300, + release = "2011-05-05", + author = "Mike Pall", + license = "MIT", +} + +-- Exported glue functions for the arch-specific module. +local _M = { _info = _info } + +-- Cache library functions. +local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs +local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable +local _s = string +local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char +local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub +local concat, sort = table.concat, table.sort +local bit = bit or require("bit") +local band, shl, shr = bit.band, bit.lshift, bit.rshift + +-- Inherited tables and callbacks. +local g_opt, g_arch +local wline, werror, wfatal, wwarn + +-- Action name list. +-- CHECK: Keep this in sync with the C code! +local action_names = { + -- int arg, 1 buffer pos: + "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB", + -- action arg (1 byte), int arg, 1 buffer pos (reg/num): + "VREG", "SPACE", -- !x64: VREG support NYI. + -- ptrdiff_t arg, 1 buffer pos (address): !x64 + "SETLABEL", "REL_A", + -- action arg (1 byte) or int arg, 2 buffer pos (link, offset): + "REL_LG", "REL_PC", + -- action arg (1 byte) or int arg, 1 buffer pos (link): + "IMM_LG", "IMM_PC", + -- action arg (1 byte) or int arg, 1 buffer pos (offset): + "LABEL_LG", "LABEL_PC", + -- action arg (1 byte), 1 buffer pos (offset): + "ALIGN", + -- action args (2 bytes), no buffer pos. + "EXTERN", + -- action arg (1 byte), no buffer pos. + "ESC", + -- no action arg, no buffer pos. + "MARK", + -- action arg (1 byte), no buffer pos, terminal action: + "SECTION", + -- no args, no buffer pos, terminal action: + "STOP" +} + +-- Maximum number of section buffer positions for dasm_put(). +-- CHECK: Keep this in sync with the C code! +local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. + +-- Action name -> action number (dynamically generated below). +local map_action = {} +-- First action number. Everything below does not need to be escaped. +local actfirst = 256-#action_names + +-- Action list buffer and string (only used to remove dupes). +local actlist = {} +local actstr = "" + +-- Argument list for next dasm_put(). Start with offset 0 into action list. +local actargs = { 0 } + +-- Current number of section buffer positions for dasm_put(). +local secpos = 1 + +------------------------------------------------------------------------------ + +-- Compute action numbers for action names. +for n,name in ipairs(action_names) do + local num = actfirst + n - 1 + map_action[name] = num +end + +-- Dump action names and numbers. +local function dumpactions(out) + out:write("DynASM encoding engine action codes:\n") + for n,name in ipairs(action_names) do + local num = map_action[name] + out:write(format(" %-10s %02X %d\n", name, num, num)) + end + out:write("\n") +end + +-- Write action list buffer as a huge static C array. +local function writeactions(out, name) + local nn = #actlist + local last = actlist[nn] or 255 + actlist[nn] = nil -- Remove last byte. + if nn == 0 then nn = 1 end + out:write("static const unsigned char ", name, "[", nn, "] = {\n") + local s = " " + for n,b in ipairs(actlist) do + s = s..b.."," + if #s >= 75 then + assert(out:write(s, "\n")) + s = " " + end + end + out:write(s, last, "\n};\n\n") -- Add last byte back. +end + +------------------------------------------------------------------------------ + +-- Add byte to action list. +local function wputxb(n) + assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range") + actlist[#actlist+1] = n +end + +-- Add action to list with optional arg. Advance buffer pos, too. +local function waction(action, a, num) + wputxb(assert(map_action[action], "bad action name `"..action.."'")) + if a then actargs[#actargs+1] = a end + if a or num then secpos = secpos + (num or 1) end +end + +-- Add call to embedded DynASM C code. +local function wcall(func, args) + wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true) +end + +-- Delete duplicate action list chunks. A tad slow, but so what. +local function dedupechunk(offset) + local al, as = actlist, actstr + local chunk = char(unpack(al, offset+1, #al)) + local orig = find(as, chunk, 1, true) + if orig then + actargs[1] = orig-1 -- Replace with original offset. + for i=offset+1,#al do al[i] = nil end -- Kill dupe. + else + actstr = as..chunk + end +end + +-- Flush action list (intervening C code or buffer pos overflow). +local function wflush(term) + local offset = actargs[1] + if #actlist == offset then return end -- Nothing to flush. + if not term then waction("STOP") end -- Terminate action list. + dedupechunk(offset) + wcall("put", actargs) -- Add call to dasm_put(). + actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). + secpos = 1 -- The actionlist offset occupies a buffer position, too. +end + +-- Put escaped byte. +local function wputb(n) + if n >= actfirst then waction("ESC") end -- Need to escape byte. + wputxb(n) +end + +------------------------------------------------------------------------------ + +-- Global label name -> global label number. With auto assignment on 1st use. +local next_global = 10 +local map_global = setmetatable({}, { __index = function(t, name) + if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end + local n = next_global + if n > 246 then werror("too many global labels") end + next_global = n + 1 + t[name] = n + return n +end}) + +-- Dump global labels. +local function dumpglobals(out, lvl) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("Global labels:\n") + for i=10,next_global-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write global label enum. +local function writeglobals(out, prefix) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("enum {\n") + for i=10,next_global-1 do + out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n") + end + out:write(" ", prefix, "_MAX\n};\n") +end + +-- Write global label names. +local function writeglobalnames(out, name) + local t = {} + for name, n in pairs(map_global) do t[n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=10,next_global-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Extern label name -> extern label number. With auto assignment on 1st use. +local next_extern = -1 +local map_extern = setmetatable({}, { __index = function(t, name) + -- No restrictions on the name for now. + local n = next_extern + if n < -256 then werror("too many extern labels") end + next_extern = n - 1 + t[name] = n + return n +end}) + +-- Dump extern labels. +local function dumpexterns(out, lvl) + local t = {} + for name, n in pairs(map_extern) do t[-n] = name end + out:write("Extern labels:\n") + for i=1,-next_extern-1 do + out:write(format(" %s\n", t[i])) + end + out:write("\n") +end + +-- Write extern label names. +local function writeexternnames(out, name) + local t = {} + for name, n in pairs(map_extern) do t[-n] = name end + out:write("static const char *const ", name, "[] = {\n") + for i=1,-next_extern-1 do + out:write(" \"", t[i], "\",\n") + end + out:write(" (const char *)0\n};\n") +end + +------------------------------------------------------------------------------ + +-- Arch-specific maps. +local map_archdef = {} -- Ext. register name -> int. name. +local map_reg_rev = {} -- Int. register name -> ext. name. +local map_reg_num = {} -- Int. register name -> register number. +local map_reg_opsize = {} -- Int. register name -> operand size. +local map_reg_valid_base = {} -- Int. register name -> valid base register? +local map_reg_valid_index = {} -- Int. register name -> valid index register? +local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex. +local reg_list = {} -- Canonical list of int. register names. + +local map_type = {} -- Type name -> { ctype, reg } +local ctypenum = 0 -- Type number (for _PTx macros). + +local addrsize = x64 and "q" or "d" -- Size for address operands. + +-- Helper functions to fill register maps. +local function mkrmap(sz, cl, names) + local cname = format("@%s", sz) + reg_list[#reg_list+1] = cname + map_archdef[cl] = cname + map_reg_rev[cname] = cl + map_reg_num[cname] = -1 + map_reg_opsize[cname] = sz + if sz == addrsize or sz == "d" then + map_reg_valid_base[cname] = true + map_reg_valid_index[cname] = true + end + if names then + for n,name in ipairs(names) do + local iname = format("@%s%x", sz, n-1) + reg_list[#reg_list+1] = iname + map_archdef[name] = iname + map_reg_rev[iname] = name + map_reg_num[iname] = n-1 + map_reg_opsize[iname] = sz + if sz == "b" and n > 4 then map_reg_needrex[iname] = false end + if sz == addrsize or sz == "d" then + map_reg_valid_base[iname] = true + map_reg_valid_index[iname] = true + end + end + end + for i=0,(x64 and sz ~= "f") and 15 or 7 do + local needrex = sz == "b" and i > 3 + local iname = format("@%s%x%s", sz, i, needrex and "R" or "") + if needrex then map_reg_needrex[iname] = true end + local name + if sz == "o" then name = format("xmm%d", i) + elseif sz == "f" then name = format("st%d", i) + else name = format("r%d%s", i, sz == addrsize and "" or sz) end + map_archdef[name] = iname + if not map_reg_rev[iname] then + reg_list[#reg_list+1] = iname + map_reg_rev[iname] = name + map_reg_num[iname] = i + map_reg_opsize[iname] = sz + if sz == addrsize or sz == "d" then + map_reg_valid_base[iname] = true + map_reg_valid_index[iname] = true + end + end + end + reg_list[#reg_list+1] = "" +end + +-- Integer registers (qword, dword, word and byte sized). +if x64 then + mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"}) +end +mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"}) +mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}) +mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}) +map_reg_valid_index[map_archdef.esp] = false +if x64 then map_reg_valid_index[map_archdef.rsp] = false end +map_archdef["Ra"] = "@"..addrsize + +-- FP registers (internally tword sized, but use "f" as operand size). +mkrmap("f", "Rf") + +-- SSE registers (oword sized, but qword and dword accessible). +mkrmap("o", "xmm") + +-- Operand size prefixes to codes. +local map_opsize = { + byte = "b", word = "w", dword = "d", qword = "q", oword = "o", tword = "t", + aword = addrsize, +} + +-- Operand size code to number. +local map_opsizenum = { + b = 1, w = 2, d = 4, q = 8, o = 16, t = 10, +} + +-- Operand size code to name. +local map_opsizename = { + b = "byte", w = "word", d = "dword", q = "qword", o = "oword", t = "tword", + f = "fpword", +} + +-- Valid index register scale factors. +local map_xsc = { + ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3, +} + +-- Condition codes. +local map_cc = { + o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7, + s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15, + c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7, + pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15, +} + + +-- Reverse defines for registers. +function _M.revdef(s) + return gsub(s, "@%w+", map_reg_rev) +end + +-- Dump register names and numbers +local function dumpregs(out) + out:write("Register names, sizes and internal numbers:\n") + for _,reg in ipairs(reg_list) do + if reg == "" then + out:write("\n") + else + local name = map_reg_rev[reg] + local num = map_reg_num[reg] + local opsize = map_opsizename[map_reg_opsize[reg]] + out:write(format(" %-5s %-8s %s\n", name, opsize, + num < 0 and "(variable)" or num)) + end + end +end + +------------------------------------------------------------------------------ + +-- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC). +local function wputlabel(aprefix, imm, num) + if type(imm) == "number" then + if imm < 0 then + waction("EXTERN") + wputxb(aprefix == "IMM_" and 0 or 1) + imm = -imm-1 + else + waction(aprefix.."LG", nil, num); + end + wputxb(imm) + else + waction(aprefix.."PC", imm, num) + end +end + +-- Put signed byte or arg. +local function wputsbarg(n) + if type(n) == "number" then + if n < -128 or n > 127 then + werror("signed immediate byte out of range") + end + if n < 0 then n = n + 256 end + wputb(n) + else waction("IMM_S", n) end +end + +-- Put unsigned byte or arg. +local function wputbarg(n) + if type(n) == "number" then + if n < 0 or n > 255 then + werror("unsigned immediate byte out of range") + end + wputb(n) + else waction("IMM_B", n) end +end + +-- Put unsigned word or arg. +local function wputwarg(n) + if type(n) == "number" then + if shr(n, 16) ~= 0 then + werror("unsigned immediate word out of range") + end + wputb(band(n, 255)); wputb(shr(n, 8)); + else waction("IMM_W", n) end +end + +-- Put signed or unsigned dword or arg. +local function wputdarg(n) + local tn = type(n) + if tn == "number" then + wputb(band(n, 255)) + wputb(band(shr(n, 8), 255)) + wputb(band(shr(n, 16), 255)) + wputb(shr(n, 24)) + elseif tn == "table" then + wputlabel("IMM_", n[1], 1) + else + waction("IMM_D", n) + end +end + +-- Put operand-size dependent number or arg (defaults to dword). +local function wputszarg(sz, n) + if not sz or sz == "d" or sz == "q" then wputdarg(n) + elseif sz == "w" then wputwarg(n) + elseif sz == "b" then wputbarg(n) + elseif sz == "s" then wputsbarg(n) + else werror("bad operand size") end +end + +-- Put multi-byte opcode with operand-size dependent modifications. +local function wputop(sz, op, rex) + local r + if rex ~= 0 and not x64 then werror("bad operand size") end + if sz == "w" then wputb(102) end + -- Needs >32 bit numbers, but only for crc32 eax, word [ebx] + if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end + if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end + if op >= 65536 then + if rex ~= 0 then + local opc3 = band(op, 0xffff00) + if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then + wputb(64 + band(rex, 15)); rex = 0 + end + end + wputb(shr(op, 16)); op = band(op, 0xffff) + end + if op >= 256 then + local b = shr(op, 8) + if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0 end + wputb(b) + op = band(op, 255) + end + if rex ~= 0 then wputb(64 + band(rex, 15)) end + if sz == "b" then op = op - 1 end + wputb(op) +end + +-- Put ModRM or SIB formatted byte. +local function wputmodrm(m, s, rm, vs, vrm) + assert(m < 4 and s < 16 and rm < 16, "bad modrm operands") + wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7)) +end + +-- Put ModRM/SIB plus optional displacement. +local function wputmrmsib(t, imark, s, vsreg) + local vreg, vxreg + local reg, xreg = t.reg, t.xreg + if reg and reg < 0 then reg = 0; vreg = t.vreg end + if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end + if s < 0 then s = 0 end + + -- Register mode. + if sub(t.mode, 1, 1) == "r" then + wputmodrm(3, s, reg) + if vsreg then waction("VREG", vsreg); wputxb(2) end + if vreg then waction("VREG", vreg); wputxb(0) end + return + end + + local disp = t.disp + local tdisp = type(disp) + -- No base register? + if not reg then + local riprel = false + if xreg then + -- Indexed mode with index register only. + -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp) + wputmodrm(0, s, 4) + if imark == "I" then waction("MARK") end + if vsreg then waction("VREG", vsreg); wputxb(2) end + wputmodrm(t.xsc, xreg, 5) + if vxreg then waction("VREG", vxreg); wputxb(3) end + else + -- Pure 32 bit displacement. + if x64 and tdisp ~= "table" then + wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp) + if imark == "I" then waction("MARK") end + wputmodrm(0, 4, 5) + else + riprel = x64 + wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp) + if imark == "I" then waction("MARK") end + end + if vsreg then waction("VREG", vsreg); wputxb(2) end + end + if riprel then -- Emit rip-relative displacement. + if match("UWSiI", imark) then + werror("NYI: rip-relative displacement followed by immediate") + end + -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f. + wputlabel("REL_", disp[1], 2) + else + wputdarg(disp) + end + return + end + + local m + if tdisp == "number" then -- Check displacement size at assembly time. + if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too) + if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0] + elseif disp >= -128 and disp <= 127 then m = 1 + else m = 2 end + elseif tdisp == "table" then + m = 2 + end + + -- Index register present or esp as base register: need SIB encoding. + if xreg or band(reg, 7) == 4 then + wputmodrm(m or 2, s, 4) -- ModRM. + if m == nil or imark == "I" then waction("MARK") end + if vsreg then waction("VREG", vsreg); wputxb(2) end + wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB. + if vxreg then waction("VREG", vxreg); wputxb(3) end + if vreg then waction("VREG", vreg); wputxb(1) end + else + wputmodrm(m or 2, s, reg) -- ModRM. + if (imark == "I" and (m == 1 or m == 2)) or + (m == nil and (vsreg or vreg)) then waction("MARK") end + if vsreg then waction("VREG", vsreg); wputxb(2) end + if vreg then waction("VREG", vreg); wputxb(1) end + end + + -- Put displacement. + if m == 1 then wputsbarg(disp) + elseif m == 2 then wputdarg(disp) + elseif m == nil then waction("DISP", disp) end +end + +------------------------------------------------------------------------------ + +-- Return human-readable operand mode string. +local function opmodestr(op, args) + local m = {} + for i=1,#args do + local a = args[i] + m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?") + end + return op.." "..concat(m, ",") +end + +-- Convert number to valid integer or nil. +local function toint(expr) + local n = tonumber(expr) + if n then + if n % 1 ~= 0 or n < -2147483648 or n > 4294967295 then + werror("bad integer number `"..expr.."'") + end + return n + end +end + +-- Parse immediate expression. +local function immexpr(expr) + -- &expr (pointer) + if sub(expr, 1, 1) == "&" then + return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2)) + end + + local prefix = sub(expr, 1, 2) + -- =>expr (pc label reference) + if prefix == "=>" then + return "iJ", sub(expr, 3) + end + -- ->name (global label reference) + if prefix == "->" then + return "iJ", map_global[sub(expr, 3)] + end + + -- [<>][1-9] (local label reference) + local dir, lnum = match(expr, "^([<>])([1-9])$") + if dir then -- Fwd: 247-255, Bkwd: 1-9. + return "iJ", lnum + (dir == ">" and 246 or 0) + end + + local extname = match(expr, "^extern%s+(%S+)$") + if extname then + return "iJ", map_extern[extname] + end + + -- expr (interpreted as immediate) + return "iI", expr +end + +-- Parse displacement expression: +-num, +-expr, +-opsize*num +local function dispexpr(expr) + local disp = expr == "" and 0 or toint(expr) + if disp then return disp end + local c, dispt = match(expr, "^([+-])%s*(.+)$") + if c == "+" then + expr = dispt + elseif not c then + werror("bad displacement expression `"..expr.."'") + end + local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$") + local ops, imm = map_opsize[opsize], toint(tailops) + if ops and imm then + if c == "-" then imm = -imm end + return imm*map_opsizenum[ops] + end + local mode, iexpr = immexpr(dispt) + if mode == "iJ" then + if c == "-" then werror("cannot invert label reference") end + return { iexpr } + end + return expr -- Need to return original signed expression. +end + +-- Parse register or type expression. +local function rtexpr(expr) + if not expr then return end + local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$") + local tp = map_type[tname or expr] + if tp then + local reg = ovreg or tp.reg + local rnum = map_reg_num[reg] + if not rnum then + werror("type `"..(tname or expr).."' needs a register override") + end + if not map_reg_valid_base[reg] then + werror("bad base register override `"..(map_reg_rev[reg] or reg).."'") + end + return reg, rnum, tp + end + return expr, map_reg_num[expr] +end + +-- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }. +local function parseoperand(param) + local t = {} + + local expr = param + local opsize, tailops = match(param, "^(%w+)%s*(.+)$") + if opsize then + t.opsize = map_opsize[opsize] + if t.opsize then expr = tailops end + end + + local br = match(expr, "^%[%s*(.-)%s*%]$") + repeat + if br then + t.mode = "xm" + + -- [disp] + t.disp = toint(br) + if t.disp then + t.mode = x64 and "xm" or "xmO" + break + end + + -- [reg...] + local tp + local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$") + reg, t.reg, tp = rtexpr(reg) + if not t.reg then + -- [expr] + t.mode = x64 and "xm" or "xmO" + t.disp = dispexpr("+"..br) + break + end + + if t.reg == -1 then + t.vreg, tailr = match(tailr, "^(%b())(.*)$") + if not t.vreg then werror("bad variable register expression") end + end + + -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr] + local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$") + if xsc then + if not map_reg_valid_index[reg] then + werror("bad index register `"..map_reg_rev[reg].."'") + end + t.xsc = map_xsc[xsc] + t.xreg = t.reg + t.vxreg = t.vreg + t.reg = nil + t.vreg = nil + t.disp = dispexpr(tailsc) + break + end + if not map_reg_valid_base[reg] then + werror("bad base register `"..map_reg_rev[reg].."'") + end + + -- [reg] or [reg+-disp] + t.disp = toint(tailr) or (tailr == "" and 0) + if t.disp then break end + + -- [reg+xreg...] + local xreg, tailx = match(tailr, "^+%s*([@%w_:]+)%s*(.*)$") + xreg, t.xreg, tp = rtexpr(xreg) + if not t.xreg then + -- [reg+-expr] + t.disp = dispexpr(tailr) + break + end + if not map_reg_valid_index[xreg] then + werror("bad index register `"..map_reg_rev[xreg].."'") + end + + if t.xreg == -1 then + t.vxreg, tailx = match(tailx, "^(%b())(.*)$") + if not t.vxreg then werror("bad variable register expression") end + end + + -- [reg+xreg*xsc...] + local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$") + if xsc then + t.xsc = map_xsc[xsc] + tailx = tailsc + end + + -- [...] or [...+-disp] or [...+-expr] + t.disp = dispexpr(tailx) + else + -- imm or opsize*imm + local imm = toint(expr) + if not imm and sub(expr, 1, 1) == "*" and t.opsize then + imm = toint(sub(expr, 2)) + if imm then + imm = imm * map_opsizenum[t.opsize] + t.opsize = nil + end + end + if imm then + if t.opsize then werror("bad operand size override") end + local m = "i" + if imm == 1 then m = m.."1" end + if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end + if imm >= -128 and imm <= 127 then m = m.."S" end + t.imm = imm + t.mode = m + break + end + + local tp + local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$") + reg, t.reg, tp = rtexpr(reg) + if t.reg then + if t.reg == -1 then + t.vreg, tailr = match(tailr, "^(%b())(.*)$") + if not t.vreg then werror("bad variable register expression") end + end + -- reg + if tailr == "" then + if t.opsize then werror("bad operand size override") end + t.opsize = map_reg_opsize[reg] + if t.opsize == "f" then + t.mode = t.reg == 0 and "fF" or "f" + else + if reg == "@w4" or (x64 and reg == "@d4") then + wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'")) + end + t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm") + end + t.needrex = map_reg_needrex[reg] + break + end + + -- type[idx], type[idx].field, type->field -> [reg+offset_expr] + if not tp then werror("bad operand `"..param.."'") end + t.mode = "xm" + t.disp = format(tp.ctypefmt, tailr) + else + t.mode, t.imm = immexpr(expr) + if sub(t.mode, -1) == "J" then + if t.opsize and t.opsize ~= addrsize then + werror("bad operand size override") + end + t.opsize = addrsize + end + end + end + until true + return t +end + +------------------------------------------------------------------------------ +-- x86 Template String Description +-- =============================== +-- +-- Each template string is a list of [match:]pattern pairs, +-- separated by "|". The first match wins. No match means a +-- bad or unsupported combination of operand modes or sizes. +-- +-- The match part and the ":" is omitted if the operation has +-- no operands. Otherwise the first N characters are matched +-- against the mode strings of each of the N operands. +-- +-- The mode string for each operand type is (see parseoperand()): +-- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl +-- FP register: "f", +"F" for st0 +-- Index operand: "xm", +"O" for [disp] (pure offset) +-- Immediate: "i", +"S" for signed 8 bit, +"1" for 1, +-- +"I" for arg, +"P" for pointer +-- Any: +"J" for valid jump targets +-- +-- So a match character "m" (mixed) matches both an integer register +-- and an index operand (to be encoded with the ModRM/SIB scheme). +-- But "r" matches only a register and "x" only an index operand +-- (e.g. for FP memory access operations). +-- +-- The operand size match string starts right after the mode match +-- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty. +-- The effective data size of the operation is matched against this list. +-- +-- If only the regular "b", "w", "d", "q", "t" operand sizes are +-- present, then all operands must be the same size. Unspecified sizes +-- are ignored, but at least one operand must have a size or the pattern +-- won't match (use the "byte", "word", "dword", "qword", "tword" +-- operand size overrides. E.g.: mov dword [eax], 1). +-- +-- If the list has a "1" or "2" prefix, the operand size is taken +-- from the respective operand and any other operand sizes are ignored. +-- If the list contains only ".", all operand sizes are ignored. +-- If the list has a "/" prefix, the concatenated (mixed) operand sizes +-- are compared to the match. +-- +-- E.g. "rrdw" matches for either two dword registers or two word +-- registers. "Fx2dq" matches an st0 operand plus an index operand +-- pointing to a dword (float) or qword (double). +-- +-- Every character after the ":" is part of the pattern string: +-- Hex chars are accumulated to form the opcode (left to right). +-- "n" disables the standard opcode mods +-- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q") +-- "X" Force REX.W. +-- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode. +-- "m"/"M" generates ModRM/SIB from the 1st/2nd operand. +-- The spare 3 bits are either filled with the last hex digit or +-- the result from a previous "r"/"R". The opcode is restored. +-- +-- All of the following characters force a flush of the opcode: +-- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand. +-- "S" stores a signed 8 bit immediate from the last operand. +-- "U" stores an unsigned 8 bit immediate from the last operand. +-- "W" stores an unsigned 16 bit immediate from the last operand. +-- "i" stores an operand sized immediate from the last operand. +-- "I" dito, but generates an action code to optionally modify +-- the opcode (+2) for a signed 8 bit immediate. +-- "J" generates one of the REL action codes from the last operand. +-- +------------------------------------------------------------------------------ + +-- Template strings for x86 instructions. Ordered by first opcode byte. +-- Unimplemented opcodes (deliberate omissions) are marked with *. +local map_op = { + -- 00-05: add... + -- 06: *push es + -- 07: *pop es + -- 08-0D: or... + -- 0E: *push cs + -- 0F: two byte opcode prefix + -- 10-15: adc... + -- 16: *push ss + -- 17: *pop ss + -- 18-1D: sbb... + -- 1E: *push ds + -- 1F: *pop ds + -- 20-25: and... + es_0 = "26", + -- 27: *daa + -- 28-2D: sub... + cs_0 = "2E", + -- 2F: *das + -- 30-35: xor... + ss_0 = "36", + -- 37: *aaa + -- 38-3D: cmp... + ds_0 = "3E", + -- 3F: *aas + inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m", + dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m", + push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or + "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i", + pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m", + -- 60: *pusha, *pushad, *pushaw + -- 61: *popa, *popad, *popaw + -- 62: *bound rdw,x + -- 63: x86: *arpl mw,rw + movsxd_2 = x64 and "rm/qd:63rM", + fs_0 = "64", + gs_0 = "65", + o16_0 = "66", + a16_0 = not x64 and "67" or nil, + a32_0 = x64 and "67", + -- 68: push idw + -- 69: imul rdw,mdw,idw + -- 6A: push ib + -- 6B: imul rdw,mdw,S + -- 6C: *insb + -- 6D: *insd, *insw + -- 6E: *outsb + -- 6F: *outsd, *outsw + -- 70-7F: jcc lb + -- 80: add... mb,i + -- 81: add... mdw,i + -- 82: *undefined + -- 83: add... mdw,S + test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi", + -- 86: xchg rb,mb + -- 87: xchg rdw,mdw + -- 88: mov mb,r + -- 89: mov mdw,r + -- 8A: mov r,mb + -- 8B: mov r,mdw + -- 8C: *mov mdw,seg + lea_2 = "rx1dq:8DrM", + -- 8E: *mov seg,mdw + -- 8F: pop mdw + nop_0 = "90", + xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm", + cbw_0 = "6698", + cwde_0 = "98", + cdqe_0 = "4898", + cwd_0 = "6699", + cdq_0 = "99", + cqo_0 = "4899", + -- 9A: *call iw:idw + wait_0 = "9B", + fwait_0 = "9B", + pushf_0 = "9C", + pushfd_0 = not x64 and "9C", + pushfq_0 = x64 and "9C", + popf_0 = "9D", + popfd_0 = not x64 and "9D", + popfq_0 = x64 and "9D", + sahf_0 = "9E", + lahf_0 = "9F", + mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi", + movsb_0 = "A4", + movsw_0 = "66A5", + movsd_0 = "A5", + cmpsb_0 = "A6", + cmpsw_0 = "66A7", + cmpsd_0 = "A7", + -- A8: test Rb,i + -- A9: test Rdw,i + stosb_0 = "AA", + stosw_0 = "66AB", + stosd_0 = "AB", + lodsb_0 = "AC", + lodsw_0 = "66AD", + lodsd_0 = "AD", + scasb_0 = "AE", + scasw_0 = "66AF", + scasd_0 = "AF", + -- B0-B7: mov rb,i + -- B8-BF: mov rdw,i + -- C0: rol... mb,i + -- C1: rol... mdw,i + ret_1 = "i.:nC2W", + ret_0 = "C3", + -- C4: *les rdw,mq + -- C5: *lds rdw,mq + -- C6: mov mb,i + -- C7: mov mdw,i + -- C8: *enter iw,ib + leave_0 = "C9", + -- CA: *retf iw + -- CB: *retf + int3_0 = "CC", + int_1 = "i.:nCDU", + into_0 = "CE", + -- CF: *iret + -- D0: rol... mb,1 + -- D1: rol... mdw,1 + -- D2: rol... mb,cl + -- D3: rol... mb,cl + -- D4: *aam ib + -- D5: *aad ib + -- D6: *salc + -- D7: *xlat + -- D8-DF: floating point ops + -- E0: *loopne + -- E1: *loope + -- E2: *loop + -- E3: *jcxz, *jecxz + -- E4: *in Rb,ib + -- E5: *in Rdw,ib + -- E6: *out ib,Rb + -- E7: *out ib,Rdw + call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J", + jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB + -- EA: *jmp iw:idw + -- EB: jmp ib + -- EC: *in Rb,dx + -- ED: *in Rdw,dx + -- EE: *out dx,Rb + -- EF: *out dx,Rdw + -- F0: *lock + int1_0 = "F1", + repne_0 = "F2", + repnz_0 = "F2", + rep_0 = "F3", + repe_0 = "F3", + repz_0 = "F3", + -- F4: *hlt + cmc_0 = "F5", + -- F6: test... mb,i; div... mb + -- F7: test... mdw,i; div... mdw + clc_0 = "F8", + stc_0 = "F9", + -- FA: *cli + cld_0 = "FC", + std_0 = "FD", + -- FE: inc... mb + -- FF: inc... mdw + + -- misc ops + not_1 = "m:F72m", + neg_1 = "m:F73m", + mul_1 = "m:F74m", + imul_1 = "m:F75m", + div_1 = "m:F76m", + idiv_1 = "m:F77m", + + imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi", + imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi", + + movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:", + movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:", + + bswap_1 = "rqd:0FC8r", + bsf_2 = "rmqdw:0FBCrM", + bsr_2 = "rmqdw:0FBDrM", + bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU", + btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU", + btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU", + bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU", + + rdtsc_0 = "0F31", -- P1+ + cpuid_0 = "0FA2", -- P1+ + + -- floating point ops + fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m", + fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m", + fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m", + + fpop_0 = "DDD8", -- Alias for fstp st0. + + fist_1 = "xw:nDF2m|xd:DB2m", + fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m", + fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m", + + fxch_0 = "D9C9", + fxch_1 = "ff:D9C8r", + fxch_2 = "fFf:D9C8r|Fff:D9C8R", + + fucom_1 = "ff:DDE0r", + fucom_2 = "Fff:DDE0R", + fucomp_1 = "ff:DDE8r", + fucomp_2 = "Fff:DDE8R", + fucomi_1 = "ff:DBE8r", -- P6+ + fucomi_2 = "Fff:DBE8R", -- P6+ + fucomip_1 = "ff:DFE8r", -- P6+ + fucomip_2 = "Fff:DFE8R", -- P6+ + fcomi_1 = "ff:DBF0r", -- P6+ + fcomi_2 = "Fff:DBF0R", -- P6+ + fcomip_1 = "ff:DFF0r", -- P6+ + fcomip_2 = "Fff:DFF0R", -- P6+ + fucompp_0 = "DAE9", + fcompp_0 = "DED9", + + fldcw_1 = "xw:nD95m", + fstcw_1 = "xw:n9BD97m", + fnstcw_1 = "xw:nD97m", + fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m", + fnstsw_1 = "Rw:nDFE0|xw:nDD7m", + fclex_0 = "9BDBE2", + fnclex_0 = "DBE2", + + fnop_0 = "D9D0", + -- D9D1-D9DF: unassigned + + fchs_0 = "D9E0", + fabs_0 = "D9E1", + -- D9E2: unassigned + -- D9E3: unassigned + ftst_0 = "D9E4", + fxam_0 = "D9E5", + -- D9E6: unassigned + -- D9E7: unassigned + fld1_0 = "D9E8", + fldl2t_0 = "D9E9", + fldl2e_0 = "D9EA", + fldpi_0 = "D9EB", + fldlg2_0 = "D9EC", + fldln2_0 = "D9ED", + fldz_0 = "D9EE", + -- D9EF: unassigned + + f2xm1_0 = "D9F0", + fyl2x_0 = "D9F1", + fptan_0 = "D9F2", + fpatan_0 = "D9F3", + fxtract_0 = "D9F4", + fprem1_0 = "D9F5", + fdecstp_0 = "D9F6", + fincstp_0 = "D9F7", + fprem_0 = "D9F8", + fyl2xp1_0 = "D9F9", + fsqrt_0 = "D9FA", + fsincos_0 = "D9FB", + frndint_0 = "D9FC", + fscale_0 = "D9FD", + fsin_0 = "D9FE", + fcos_0 = "D9FF", + + -- SSE, SSE2 + andnpd_2 = "rmo:660F55rM", + andnps_2 = "rmo:0F55rM", + andpd_2 = "rmo:660F54rM", + andps_2 = "rmo:0F54rM", + clflush_1 = "x.:0FAE7m", + cmppd_3 = "rmio:660FC2rMU", + cmpps_3 = "rmio:0FC2rMU", + cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:", + cmpss_3 = "rrio:F30FC2rMU|rxi/od:", + comisd_2 = "rro:660F2FrM|rx/oq:", + comiss_2 = "rro:0F2FrM|rx/od:", + cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:", + cvtdq2ps_2 = "rmo:0F5BrM", + cvtpd2dq_2 = "rmo:F20FE6rM", + cvtpd2ps_2 = "rmo:660F5ArM", + cvtpi2pd_2 = "rx/oq:660F2ArM", + cvtpi2ps_2 = "rx/oq:0F2ArM", + cvtps2dq_2 = "rmo:660F5BrM", + cvtps2pd_2 = "rro:0F5ArM|rx/oq:", + cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:", + cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:", + cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM", + cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM", + cvtss2sd_2 = "rro:F30F5ArM|rx/od:", + cvtss2si_2 = "rr/do:F20F2CrM|rr/qo:|rxd:|rx/qd:", + cvttpd2dq_2 = "rmo:660FE6rM", + cvttps2dq_2 = "rmo:F30F5BrM", + cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:", + cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:", + ldmxcsr_1 = "xd:0FAE2m", + lfence_0 = "0FAEE8", + maskmovdqu_2 = "rro:660FF7rM", + mfence_0 = "0FAEF0", + movapd_2 = "rmo:660F28rM|mro:660F29Rm", + movaps_2 = "rmo:0F28rM|mro:0F29Rm", + movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:", + movdqa_2 = "rmo:660F6FrM|mro:660F7FRm", + movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm", + movhlps_2 = "rro:0F12rM", + movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm", + movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm", + movlhps_2 = "rro:0F16rM", + movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm", + movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm", + movmskpd_2 = "rr/do:660F50rM", + movmskps_2 = "rr/do:0F50rM", + movntdq_2 = "xro:660FE7Rm", + movnti_2 = "xrqd:0FC3Rm", + movntpd_2 = "xro:660F2BRm", + movntps_2 = "xro:0F2BRm", + movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm", + movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm", + movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm", + movupd_2 = "rmo:660F10rM|mro:660F11Rm", + movups_2 = "rmo:0F10rM|mro:0F11Rm", + orpd_2 = "rmo:660F56rM", + orps_2 = "rmo:0F56rM", + packssdw_2 = "rmo:660F6BrM", + packsswb_2 = "rmo:660F63rM", + packuswb_2 = "rmo:660F67rM", + paddb_2 = "rmo:660FFCrM", + paddd_2 = "rmo:660FFErM", + paddq_2 = "rmo:660FD4rM", + paddsb_2 = "rmo:660FECrM", + paddsw_2 = "rmo:660FEDrM", + paddusb_2 = "rmo:660FDCrM", + paddusw_2 = "rmo:660FDDrM", + paddw_2 = "rmo:660FFDrM", + pand_2 = "rmo:660FDBrM", + pandn_2 = "rmo:660FDFrM", + pause_0 = "F390", + pavgb_2 = "rmo:660FE0rM", + pavgw_2 = "rmo:660FE3rM", + pcmpeqb_2 = "rmo:660F74rM", + pcmpeqd_2 = "rmo:660F76rM", + pcmpeqw_2 = "rmo:660F75rM", + pcmpgtb_2 = "rmo:660F64rM", + pcmpgtd_2 = "rmo:660F66rM", + pcmpgtw_2 = "rmo:660F65rM", + pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nrMU", -- Mem op: SSE4.1 only. + pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:", + pmaddwd_2 = "rmo:660FF5rM", + pmaxsw_2 = "rmo:660FEErM", + pmaxub_2 = "rmo:660FDErM", + pminsw_2 = "rmo:660FEArM", + pminub_2 = "rmo:660FDArM", + pmovmskb_2 = "rr/do:660FD7rM", + pmulhuw_2 = "rmo:660FE4rM", + pmulhw_2 = "rmo:660FE5rM", + pmullw_2 = "rmo:660FD5rM", + pmuludq_2 = "rmo:660FF4rM", + por_2 = "rmo:660FEBrM", + prefetchnta_1 = "xb:n0F180m", + prefetcht0_1 = "xb:n0F181m", + prefetcht1_1 = "xb:n0F182m", + prefetcht2_1 = "xb:n0F183m", + psadbw_2 = "rmo:660FF6rM", + pshufd_3 = "rmio:660F70rMU", + pshufhw_3 = "rmio:F30F70rMU", + pshuflw_3 = "rmio:F20F70rMU", + pslld_2 = "rmo:660FF2rM|rio:660F726mU", + pslldq_2 = "rio:660F737mU", + psllq_2 = "rmo:660FF3rM|rio:660F736mU", + psllw_2 = "rmo:660FF1rM|rio:660F716mU", + psrad_2 = "rmo:660FE2rM|rio:660F724mU", + psraw_2 = "rmo:660FE1rM|rio:660F714mU", + psrld_2 = "rmo:660FD2rM|rio:660F722mU", + psrldq_2 = "rio:660F733mU", + psrlq_2 = "rmo:660FD3rM|rio:660F732mU", + psrlw_2 = "rmo:660FD1rM|rio:660F712mU", + psubb_2 = "rmo:660FF8rM", + psubd_2 = "rmo:660FFArM", + psubq_2 = "rmo:660FFBrM", + psubsb_2 = "rmo:660FE8rM", + psubsw_2 = "rmo:660FE9rM", + psubusb_2 = "rmo:660FD8rM", + psubusw_2 = "rmo:660FD9rM", + psubw_2 = "rmo:660FF9rM", + punpckhbw_2 = "rmo:660F68rM", + punpckhdq_2 = "rmo:660F6ArM", + punpckhqdq_2 = "rmo:660F6DrM", + punpckhwd_2 = "rmo:660F69rM", + punpcklbw_2 = "rmo:660F60rM", + punpckldq_2 = "rmo:660F62rM", + punpcklqdq_2 = "rmo:660F6CrM", + punpcklwd_2 = "rmo:660F61rM", + pxor_2 = "rmo:660FEFrM", + rcpps_2 = "rmo:0F53rM", + rcpss_2 = "rro:F30F53rM|rx/od:", + rsqrtps_2 = "rmo:0F52rM", + rsqrtss_2 = "rmo:F30F52rM", + sfence_0 = "0FAEF8", + shufpd_3 = "rmio:660FC6rMU", + shufps_3 = "rmio:0FC6rMU", + stmxcsr_1 = "xd:0FAE3m", + ucomisd_2 = "rro:660F2ErM|rx/oq:", + ucomiss_2 = "rro:0F2ErM|rx/od:", + unpckhpd_2 = "rmo:660F15rM", + unpckhps_2 = "rmo:0F15rM", + unpcklpd_2 = "rmo:660F14rM", + unpcklps_2 = "rmo:0F14rM", + xorpd_2 = "rmo:660F57rM", + xorps_2 = "rmo:0F57rM", + + -- SSE3 ops + fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m", + addsubpd_2 = "rmo:660FD0rM", + addsubps_2 = "rmo:F20FD0rM", + haddpd_2 = "rmo:660F7CrM", + haddps_2 = "rmo:F20F7CrM", + hsubpd_2 = "rmo:660F7DrM", + hsubps_2 = "rmo:F20F7DrM", + lddqu_2 = "rxo:F20FF0rM", + movddup_2 = "rmo:F20F12rM", + movshdup_2 = "rmo:F30F16rM", + movsldup_2 = "rmo:F30F12rM", + + -- SSSE3 ops + pabsb_2 = "rmo:660F381CrM", + pabsd_2 = "rmo:660F381ErM", + pabsw_2 = "rmo:660F381DrM", + palignr_3 = "rmio:660F3A0FrMU", + phaddd_2 = "rmo:660F3802rM", + phaddsw_2 = "rmo:660F3803rM", + phaddw_2 = "rmo:660F3801rM", + phsubd_2 = "rmo:660F3806rM", + phsubsw_2 = "rmo:660F3807rM", + phsubw_2 = "rmo:660F3805rM", + pmaddubsw_2 = "rmo:660F3804rM", + pmulhrsw_2 = "rmo:660F380BrM", + pshufb_2 = "rmo:660F3800rM", + psignb_2 = "rmo:660F3808rM", + psignd_2 = "rmo:660F380ArM", + psignw_2 = "rmo:660F3809rM", + + -- SSE4.1 ops + blendpd_3 = "rmio:660F3A0DrMU", + blendps_3 = "rmio:660F3A0CrMU", + blendvpd_3 = "rmRo:660F3815rM", + blendvps_3 = "rmRo:660F3814rM", + dppd_3 = "rmio:660F3A41rMU", + dpps_3 = "rmio:660F3A40rMU", + extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU", + insertps_3 = "rrio:660F3A41rMU|rxi/od:", + movntdqa_2 = "rmo:660F382ArM", + mpsadbw_3 = "rmio:660F3A42rMU", + packusdw_2 = "rmo:660F382BrM", + pblendvb_3 = "rmRo:660F3810rM", + pblendw_3 = "rmio:660F3A0ErMU", + pcmpeqq_2 = "rmo:660F3829rM", + pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:", + pextrd_3 = "mri/do:660F3A16RmU", + pextrq_3 = "mri/qo:660F3A16RmU", + -- pextrw is SSE2, mem operand is SSE4.1 only + phminposuw_2 = "rmo:660F3841rM", + pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:", + pinsrd_3 = "rmi/od:660F3A22rMU", + pinsrq_3 = "rmi/oq:660F3A22rXMU", + pmaxsb_2 = "rmo:660F383CrM", + pmaxsd_2 = "rmo:660F383DrM", + pmaxud_2 = "rmo:660F383FrM", + pmaxuw_2 = "rmo:660F383ErM", + pminsb_2 = "rmo:660F3838rM", + pminsd_2 = "rmo:660F3839rM", + pminud_2 = "rmo:660F383BrM", + pminuw_2 = "rmo:660F383ArM", + pmovsxbd_2 = "rro:660F3821rM|rx/od:", + pmovsxbq_2 = "rro:660F3822rM|rx/ow:", + pmovsxbw_2 = "rro:660F3820rM|rx/oq:", + pmovsxdq_2 = "rro:660F3825rM|rx/oq:", + pmovsxwd_2 = "rro:660F3823rM|rx/oq:", + pmovsxwq_2 = "rro:660F3824rM|rx/od:", + pmovzxbd_2 = "rro:660F3831rM|rx/od:", + pmovzxbq_2 = "rro:660F3832rM|rx/ow:", + pmovzxbw_2 = "rro:660F3830rM|rx/oq:", + pmovzxdq_2 = "rro:660F3835rM|rx/oq:", + pmovzxwd_2 = "rro:660F3833rM|rx/oq:", + pmovzxwq_2 = "rro:660F3834rM|rx/od:", + pmuldq_2 = "rmo:660F3828rM", + pmulld_2 = "rmo:660F3840rM", + ptest_2 = "rmo:660F3817rM", + roundpd_3 = "rmio:660F3A09rMU", + roundps_3 = "rmio:660F3A08rMU", + roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:", + roundss_3 = "rrio:660F3A0ArMU|rxi/od:", + + -- SSE4.2 ops + crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:", + pcmpestri_3 = "rmio:660F3A61rMU", + pcmpestrm_3 = "rmio:660F3A60rMU", + pcmpgtq_2 = "rmo:660F3837rM", + pcmpistri_3 = "rmio:660F3A63rMU", + pcmpistrm_3 = "rmio:660F3A62rMU", + popcnt_2 = "rmqdw:F30FB8rM", + + -- SSE4a + extrq_2 = "rro:660F79rM", + extrq_3 = "riio:660F780mUU", + insertq_2 = "rro:F20F79rM", + insertq_4 = "rriio:F20F78rMUU", + lzcnt_2 = "rmqdw:F30FBDrM", + movntsd_2 = "xr/qo:nF20F2BRm", + movntss_2 = "xr/do:F30F2BRm", + -- popcnt is also in SSE4.2 +} + +------------------------------------------------------------------------------ + +-- Arithmetic ops. +for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3, + ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do + local n8 = shl(n, 3) + map_op[name.."_2"] = format( + "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi", + 1+n8, 3+n8, n, n, 5+n8, n) +end + +-- Shift ops. +for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3, + shl = 4, shr = 5, sar = 7, sal = 4 } do + map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n) +end + +-- Conditional ops. +for cc,n in pairs(map_cc) do + map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X + map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n) + map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+ +end + +-- FP arithmetic ops. +for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3, + sub = 4, subr = 5, div = 6, divr = 7 } do + local nc = 0xc0 + shl(n, 3) + local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8)) + local fn = "f"..name + map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n) + if n == 2 or n == 3 then + map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n) + else + map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n) + map_op[fn.."p_1"] = format("ff:DE%02Xr", nr) + map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr) + end + map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n) +end + +-- FP conditional moves. +for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do + local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6) + map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+ + map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+ +end + +-- SSE FP arithmetic ops. +for name,n in pairs{ sqrt = 1, add = 8, mul = 9, + sub = 12, min = 13, div = 14, max = 15 } do + map_op[name.."ps_2"] = format("rmo:0F5%XrM", n) + map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n) + map_op[name.."pd_2"] = format("rmo:660F5%XrM", n) + map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n) +end + +------------------------------------------------------------------------------ + +-- Process pattern string. +local function dopattern(pat, args, sz, op, needrex) + local digit, addin + local opcode = 0 + local szov = sz + local narg = 1 + local rex = 0 + + -- Limit number of section buffer positions used by a single dasm_put(). + -- A single opcode needs a maximum of 5 positions. + if secpos+5 > maxsecpos then wflush() end + + -- Process each character. + for c in gmatch(pat.."|", ".") do + if match(c, "%x") then -- Hex digit. + digit = byte(c) - 48 + if digit > 48 then digit = digit - 39 + elseif digit > 16 then digit = digit - 7 end + opcode = opcode*16 + digit + addin = nil + elseif c == "n" then -- Disable operand size mods for opcode. + szov = nil + elseif c == "X" then -- Force REX.W. + rex = 8 + elseif c == "r" then -- Merge 1st operand regno. into opcode. + addin = args[1]; opcode = opcode + (addin.reg % 8) + if narg < 2 then narg = 2 end + elseif c == "R" then -- Merge 2nd operand regno. into opcode. + addin = args[2]; opcode = opcode + (addin.reg % 8) + narg = 3 + elseif c == "m" or c == "M" then -- Encode ModRM/SIB. + local s + if addin then + s = addin.reg + opcode = opcode - band(s, 7) -- Undo regno opcode merge. + else + s = band(opcode, 15) -- Undo last digit. + opcode = shr(opcode, 4) + end + local nn = c == "m" and 1 or 2 + local t = args[nn] + if narg <= nn then narg = nn + 1 end + if szov == "q" and rex == 0 then rex = rex + 8 end + if t.reg and t.reg > 7 then rex = rex + 1 end + if t.xreg and t.xreg > 7 then rex = rex + 2 end + if s > 7 then rex = rex + 4 end + if needrex then rex = rex + 16 end + wputop(szov, opcode, rex); opcode = nil + local imark = sub(pat, -1) -- Force a mark (ugly). + -- Put ModRM/SIB with regno/last digit as spare. + wputmrmsib(t, imark, s, addin and addin.vreg) + addin = nil + else + if opcode then -- Flush opcode. + if szov == "q" and rex == 0 then rex = rex + 8 end + if needrex then rex = rex + 16 end + if addin and addin.reg == -1 then + wputop(szov, opcode - 7, rex) + waction("VREG", addin.vreg); wputxb(0) + else + if addin and addin.reg > 7 then rex = rex + 1 end + wputop(szov, opcode, rex) + end + opcode = nil + end + if c == "|" then break end + if c == "o" then -- Offset (pure 32 bit displacement). + wputdarg(args[1].disp); if narg < 2 then narg = 2 end + elseif c == "O" then + wputdarg(args[2].disp); narg = 3 + else + -- Anything else is an immediate operand. + local a = args[narg] + narg = narg + 1 + local mode, imm = a.mode, a.imm + if mode == "iJ" and not match("iIJ", c) then + werror("bad operand size for label") + end + if c == "S" then + wputsbarg(imm) + elseif c == "U" then + wputbarg(imm) + elseif c == "W" then + wputwarg(imm) + elseif c == "i" or c == "I" then + if mode == "iJ" then + wputlabel("IMM_", imm, 1) + elseif mode == "iI" and c == "I" then + waction(sz == "w" and "IMM_WB" or "IMM_DB", imm) + else + wputszarg(sz, imm) + end + elseif c == "J" then + if mode == "iPJ" then + waction("REL_A", imm) -- !x64 (secpos) + else + wputlabel("REL_", imm, 2) + end + else + werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'") + end + end + end + end +end + +------------------------------------------------------------------------------ + +-- Mapping of operand modes to short names. Suppress output with '#'. +local map_modename = { + r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm", + f = "stx", F = "st0", J = "lbl", ["1"] = "1", + I = "#", S = "#", O = "#", +} + +-- Return a table/string showing all possible operand modes. +local function templatehelp(template, nparams) + if nparams == 0 then return "" end + local t = {} + for tm in gmatch(template, "[^%|]+") do + local s = map_modename[sub(tm, 1, 1)] + s = s..gsub(sub(tm, 2, nparams), ".", function(c) + return ", "..map_modename[c] + end) + if not match(s, "#") then t[#t+1] = s end + end + return t +end + +-- Match operand modes against mode match part of template. +local function matchtm(tm, args) + for i=1,#args do + if not match(args[i].mode, sub(tm, i, i)) then return end + end + return true +end + +-- Handle opcodes defined with template strings. +map_op[".template__"] = function(params, template, nparams) + if not params then return templatehelp(template, nparams) end + local args = {} + + -- Zero-operand opcodes have no match part. + if #params == 0 then + dopattern(template, args, "d", params.op, nil) + return + end + + -- Determine common operand size (coerce undefined size) or flag as mixed. + local sz, szmix, needrex + for i,p in ipairs(params) do + args[i] = parseoperand(p) + local nsz = args[i].opsize + if nsz then + if sz and sz ~= nsz then szmix = true else sz = nsz end + end + local nrex = args[i].needrex + if nrex ~= nil then + if needrex == nil then + needrex = nrex + elseif needrex ~= nrex then + werror("bad mix of byte-addressable registers") + end + end + end + + -- Try all match:pattern pairs (separated by '|'). + local gotmatch, lastpat + for tm in gmatch(template, "[^%|]+") do + -- Split off size match (starts after mode match) and pattern string. + local szm, pat = match(tm, "^(.-):(.*)$", #args+1) + if pat == "" then pat = lastpat else lastpat = pat end + if matchtm(tm, args) then + local prefix = sub(szm, 1, 1) + if prefix == "/" then -- Match both operand sizes. + if args[1].opsize == sub(szm, 2, 2) and + args[2].opsize == sub(szm, 3, 3) then + dopattern(pat, args, sz, params.op, needrex) -- Process pattern. + return + end + else -- Match common operand size. + local szp = sz + if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes. + if prefix == "1" then szp = args[1].opsize; szmix = nil + elseif prefix == "2" then szp = args[2].opsize; szmix = nil end + if not szmix and (prefix == "." or match(szm, szp or "#")) then + dopattern(pat, args, szp, params.op, needrex) -- Process pattern. + return + end + end + gotmatch = true + end + end + + local msg = "bad operand mode" + if gotmatch then + if szmix then + msg = "mixed operand size" + else + msg = sz and "bad operand size" or "missing operand size" + end + end + + werror(msg.." in `"..opmodestr(params.op, args).."'") +end + +------------------------------------------------------------------------------ + +-- x64-specific opcode for 64 bit immediates and displacements. +if x64 then + function map_op.mov64_2(params) + if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end + if secpos+2 > maxsecpos then wflush() end + local opcode, op64, sz, rex + local op64 = match(params[1], "^%[%s*(.-)%s*%]$") + if op64 then + local a = parseoperand(params[2]) + if a.mode ~= "rmR" then werror("bad operand mode") end + sz = a.opsize + rex = sz == "q" and 8 or 0 + opcode = 0xa3 + else + op64 = match(params[2], "^%[%s*(.-)%s*%]$") + local a = parseoperand(params[1]) + if op64 then + if a.mode ~= "rmR" then werror("bad operand mode") end + sz = a.opsize + rex = sz == "q" and 8 or 0 + opcode = 0xa1 + else + if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then + werror("bad operand mode") + end + op64 = params[2] + opcode = 0xb8 + band(a.reg, 7) -- !x64: no VREG support. + rex = a.reg > 7 and 9 or 8 + end + end + wputop(sz, opcode, rex) + waction("IMM_D", format("(unsigned int)(%s)", op64)) + waction("IMM_D", format("(unsigned int)((%s)>>32)", op64)) + end +end + +------------------------------------------------------------------------------ + +-- Pseudo-opcodes for data storage. +local function op_data(params) + if not params then return "imm..." end + local sz = sub(params.op, 2, 2) + if sz == "a" then sz = addrsize end + for _,p in ipairs(params) do + local a = parseoperand(p) + if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then + werror("bad mode or size in `"..p.."'") + end + if a.mode == "iJ" then + wputlabel("IMM_", a.imm, 1) + else + wputszarg(sz, a.imm) + end + if secpos+2 > maxsecpos then wflush() end + end +end + +map_op[".byte_*"] = op_data +map_op[".sbyte_*"] = op_data +map_op[".word_*"] = op_data +map_op[".dword_*"] = op_data +map_op[".aword_*"] = op_data + +------------------------------------------------------------------------------ + +-- Pseudo-opcode to mark the position where the action list is to be emitted. +map_op[".actionlist_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeactions(out, name) end) +end + +-- Pseudo-opcode to mark the position where the global enum is to be emitted. +map_op[".globals_1"] = function(params) + if not params then return "prefix" end + local prefix = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobals(out, prefix) end) +end + +-- Pseudo-opcode to mark the position where the global names are to be emitted. +map_op[".globalnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeglobalnames(out, name) end) +end + +-- Pseudo-opcode to mark the position where the extern names are to be emitted. +map_op[".externnames_1"] = function(params) + if not params then return "cvar" end + local name = params[1] -- No syntax check. You get to keep the pieces. + wline(function(out) writeexternnames(out, name) end) +end + +------------------------------------------------------------------------------ + +-- Label pseudo-opcode (converted from trailing colon form). +map_op[".label_2"] = function(params) + if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end + if secpos+2 > maxsecpos then wflush() end + local a = parseoperand(params[1]) + local mode, imm = a.mode, a.imm + if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then + -- Local label (1: ... 9:) or global label (->global:). + waction("LABEL_LG", nil, 1) + wputxb(imm) + elseif mode == "iJ" then + -- PC label (=>pcexpr:). + waction("LABEL_PC", imm) + else + werror("bad label definition") + end + -- SETLABEL must immediately follow LABEL_LG/LABEL_PC. + local addr = params[2] + if addr then + local a = parseoperand(addr) + if a.mode == "iPJ" then + waction("SETLABEL", a.imm) + else + werror("bad label assignment") + end + end +end +map_op[".label_1"] = map_op[".label_2"] + +------------------------------------------------------------------------------ + +-- Alignment pseudo-opcode. +map_op[".align_1"] = function(params) + if not params then return "numpow2" end + if secpos+1 > maxsecpos then wflush() end + local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]] + if align then + local x = align + -- Must be a power of 2 in the range (2 ... 256). + for i=1,8 do + x = x / 2 + if x == 1 then + waction("ALIGN", nil, 1) + wputxb(align-1) -- Action byte is 2**n-1. + return + end + end + end + werror("bad alignment") +end + +-- Spacing pseudo-opcode. +map_op[".space_2"] = function(params) + if not params then return "num [, filler]" end + if secpos+1 > maxsecpos then wflush() end + waction("SPACE", params[1]) + local fill = params[2] + if fill then + fill = tonumber(fill) + if not fill or fill < 0 or fill > 255 then werror("bad filler") end + end + wputxb(fill or 0) +end +map_op[".space_1"] = map_op[".space_2"] + +------------------------------------------------------------------------------ + +-- Pseudo-opcode for (primitive) type definitions (map to C types). +map_op[".type_3"] = function(params, nparams) + if not params then + return nparams == 2 and "name, ctype" or "name, ctype, reg" + end + local name, ctype, reg = params[1], params[2], params[3] + if not match(name, "^[%a_][%w_]*$") then + werror("bad type name `"..name.."'") + end + local tp = map_type[name] + if tp then + werror("duplicate type `"..name.."'") + end + if reg and not map_reg_valid_base[reg] then + werror("bad base register `"..(map_reg_rev[reg] or reg).."'") + end + -- Add #type to defines. A bit unclean to put it in map_archdef. + map_archdef["#"..name] = "sizeof("..ctype..")" + -- Add new type and emit shortcut define. + local num = ctypenum + 1 + map_type[name] = { + ctype = ctype, + ctypefmt = format("Dt%X(%%s)", num), + reg = reg, + } + wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) + ctypenum = num +end +map_op[".type_2"] = map_op[".type_3"] + +-- Dump type definitions. +local function dumptypes(out, lvl) + local t = {} + for name in pairs(map_type) do t[#t+1] = name end + sort(t) + out:write("Type definitions:\n") + for _,name in ipairs(t) do + local tp = map_type[name] + local reg = tp.reg and map_reg_rev[tp.reg] or "" + out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Set the current section. +function _M.section(num) + waction("SECTION") + wputxb(num) + wflush(true) -- SECTION is a terminal action. +end + +------------------------------------------------------------------------------ + +-- Dump architecture description. +function _M.dumparch(out) + out:write(format("DynASM %s version %s, released %s\n\n", + _info.arch, _info.version, _info.release)) + dumpregs(out) + dumpactions(out) +end + +-- Dump all user defined elements. +function _M.dumpdef(out, lvl) + dumptypes(out, lvl) + dumpglobals(out, lvl) + dumpexterns(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Pass callbacks from/to the DynASM core. +function _M.passcb(wl, we, wf, ww) + wline, werror, wfatal, wwarn = wl, we, wf, ww + return wflush +end + +-- Setup the arch-specific module. +function _M.setup(arch, opt) + g_arch, g_opt = arch, opt +end + +-- Merge the core maps and the arch-specific maps. +function _M.mergemaps(map_coreop, map_def) + setmetatable(map_op, { __index = map_coreop }) + setmetatable(map_def, { __index = map_archdef }) + return map_op, map_def +end + +return _M + +------------------------------------------------------------------------------ + diff --git a/lib/sregex/dynasm/dynasm.lua b/lib/sregex/dynasm/dynasm.lua new file mode 100644 index 0000000..aa6e339 --- /dev/null +++ b/lib/sregex/dynasm/dynasm.lua @@ -0,0 +1,1095 @@ +------------------------------------------------------------------------------ +-- DynASM. A dynamic assembler for code generation engines. +-- Originally designed and implemented for LuaJIT. +-- +-- Copyright (C) 2005-2012 Mike Pall. All rights reserved. +-- See below for full copyright notice. +------------------------------------------------------------------------------ + +-- Application information. +local _info = { + name = "DynASM", + description = "A dynamic assembler for code generation engines", + version = "1.3.0", + vernum = 10300, + release = "2011-05-05", + author = "Mike Pall", + url = "http://luajit.org/dynasm.html", + license = "MIT", + copyright = [[ +Copyright (C) 2005-2012 Mike Pall. All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +[ MIT license: http://www.opensource.org/licenses/mit-license.php ] +]], +} + +-- Cache library functions. +local type, pairs, ipairs = type, pairs, ipairs +local pcall, error, assert = pcall, error, assert +local _s = string +local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub +local format, rep, upper = _s.format, _s.rep, _s.upper +local _t = table +local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort +local exit = os.exit +local io = io +local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr + +------------------------------------------------------------------------------ + +-- Program options. +local g_opt = {} + +-- Global state for current file. +local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch +local g_errcount = 0 + +-- Write buffer for output file. +local g_wbuffer, g_capbuffer + +------------------------------------------------------------------------------ + +-- Write an output line (or callback function) to the buffer. +local function wline(line, needindent) + local buf = g_capbuffer or g_wbuffer + buf[#buf+1] = needindent and g_indent..line or line + g_synclineno = g_synclineno + 1 +end + +-- Write assembler line as a comment, if requestd. +local function wcomment(aline) + if g_opt.comment then + wline(g_opt.comment..aline..g_opt.endcomment, true) + end +end + +-- Resync CPP line numbers. +local function wsync() + if g_synclineno ~= g_lineno and g_opt.cpp then + wline("# "..g_lineno..' "'..g_fname..'"') + g_synclineno = g_lineno + end +end + +-- Dummy action flush function. Replaced with arch-specific function later. +local function wflush(term) +end + +-- Dump all buffered output lines. +local function wdumplines(out, buf) + for _,line in ipairs(buf) do + if type(line) == "string" then + assert(out:write(line, "\n")) + else + -- Special callback to dynamically insert lines after end of processing. + line(out) + end + end +end + +------------------------------------------------------------------------------ + +-- Emit an error. Processing continues with next statement. +local function werror(msg) + error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) +end + +-- Emit a fatal error. Processing stops. +local function wfatal(msg) + g_errcount = "fatal" + werror(msg) +end + +-- Print a warning. Processing continues. +local function wwarn(msg) + stderr:write(format("%s:%s: warning: %s:\n%s\n", + g_fname, g_lineno, msg, g_curline)) +end + +-- Print caught error message. But suppress excessive errors. +local function wprinterr(...) + if type(g_errcount) == "number" then + -- Regular error. + g_errcount = g_errcount + 1 + if g_errcount < 21 then -- Seems to be a reasonable limit. + stderr:write(...) + elseif g_errcount == 21 then + stderr:write(g_fname, + ":*: warning: too many errors (suppressed further messages).\n") + end + else + -- Fatal error. + stderr:write(...) + return true -- Stop processing. + end +end + +------------------------------------------------------------------------------ + +-- Map holding all option handlers. +local opt_map = {} +local opt_current + +-- Print error and exit with error status. +local function opterror(...) + stderr:write("dynasm.lua: ERROR: ", ...) + stderr:write("\n") + exit(1) +end + +-- Get option parameter. +local function optparam(args) + local argn = args.argn + local p = args[argn] + if not p then + opterror("missing parameter for option `", opt_current, "'.") + end + args.argn = argn + 1 + return p +end + +------------------------------------------------------------------------------ + +-- Core pseudo-opcodes. +local map_coreop = {} +-- Dummy opcode map. Replaced by arch-specific map. +local map_op = {} + +-- Forward declarations. +local dostmt +local readfile + +------------------------------------------------------------------------------ + +-- Map for defines (initially empty, chains to arch-specific map). +local map_def = {} + +-- Pseudo-opcode to define a substitution. +map_coreop[".define_2"] = function(params, nparams) + if not params then return nparams == 1 and "name" or "name, subst" end + local name, def = params[1], params[2] or "1" + if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end + map_def[name] = def +end +map_coreop[".define_1"] = map_coreop[".define_2"] + +-- Define a substitution on the command line. +function opt_map.D(args) + local namesubst = optparam(args) + local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") + if name then + map_def[name] = subst + elseif match(namesubst, "^[%a_][%w_]*$") then + map_def[namesubst] = "1" + else + opterror("bad define") + end +end + +-- Undefine a substitution on the command line. +function opt_map.U(args) + local name = optparam(args) + if match(name, "^[%a_][%w_]*$") then + map_def[name] = nil + else + opterror("bad define") + end +end + +-- Helper for definesubst. +local gotsubst + +local function definesubst_one(word) + local subst = map_def[word] + if subst then gotsubst = word; return subst else return word end +end + +-- Iteratively substitute defines. +local function definesubst(stmt) + -- Limit number of iterations. + for i=1,100 do + gotsubst = false + stmt = gsub(stmt, "#?[%w_]+", definesubst_one) + if not gotsubst then break end + end + if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end + return stmt +end + +-- Dump all defines. +local function dumpdefines(out, lvl) + local t = {} + for name in pairs(map_def) do + t[#t+1] = name + end + sort(t) + out:write("Defines:\n") + for _,name in ipairs(t) do + local subst = map_def[name] + if g_arch then subst = g_arch.revdef(subst) end + out:write(format(" %-20s %s\n", name, subst)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Support variables for conditional assembly. +local condlevel = 0 +local condstack = {} + +-- Evaluate condition with a Lua expression. Substitutions already performed. +local function cond_eval(cond) + local func, err + if setfenv then + func, err = loadstring("return "..cond, "=expr") + else + -- No globals. All unknown identifiers evaluate to nil. + func, err = load("return "..cond, "=expr", "t", {}) + end + if func then + if setfenv then + setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. + end + local ok, res = pcall(func) + if ok then + if res == 0 then return false end -- Oh well. + return not not res + end + err = res + end + wfatal("bad condition: "..err) +end + +-- Skip statements until next conditional pseudo-opcode at the same level. +local function stmtskip() + local dostmt_save = dostmt + local lvl = 0 + dostmt = function(stmt) + local op = match(stmt, "^%s*(%S+)") + if op == ".if" then + lvl = lvl + 1 + elseif lvl ~= 0 then + if op == ".endif" then lvl = lvl - 1 end + elseif op == ".elif" or op == ".else" or op == ".endif" then + dostmt = dostmt_save + dostmt(stmt) + end + end +end + +-- Pseudo-opcodes for conditional assembly. +map_coreop[".if_1"] = function(params) + if not params then return "condition" end + local lvl = condlevel + 1 + local res = cond_eval(params[1]) + condlevel = lvl + condstack[lvl] = res + if not res then stmtskip() end +end + +map_coreop[".elif_1"] = function(params) + if not params then return "condition" end + if condlevel == 0 then wfatal(".elif without .if") end + local lvl = condlevel + local res = condstack[lvl] + if res then + if res == "else" then wfatal(".elif after .else") end + else + res = cond_eval(params[1]) + if res then + condstack[lvl] = res + return + end + end + stmtskip() +end + +map_coreop[".else_0"] = function(params) + if condlevel == 0 then wfatal(".else without .if") end + local lvl = condlevel + local res = condstack[lvl] + condstack[lvl] = "else" + if res then + if res == "else" then wfatal(".else after .else") end + stmtskip() + end +end + +map_coreop[".endif_0"] = function(params) + local lvl = condlevel + if lvl == 0 then wfatal(".endif without .if") end + condlevel = lvl - 1 +end + +-- Check for unfinished conditionals. +local function checkconds() + if g_errcount ~= "fatal" and condlevel ~= 0 then + wprinterr(g_fname, ":*: error: unbalanced conditional\n") + end +end + +------------------------------------------------------------------------------ + +-- Search for a file in the given path and open it for reading. +local function pathopen(path, name) + local dirsep = package and match(package.path, "\\") and "\\" or "/" + for _,p in ipairs(path) do + local fullname = p == "" and name or p..dirsep..name + local fin = io.open(fullname, "r") + if fin then + g_fname = fullname + return fin + end + end +end + +-- Include a file. +map_coreop[".include_1"] = function(params) + if not params then return "filename" end + local name = params[1] + -- Save state. Ugly, I know. but upvalues are fast. + local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent + -- Read the included file. + local fatal = readfile(pathopen(g_opt.include, name) or + wfatal("include file `"..name.."' not found")) + -- Restore state. + g_synclineno = -1 + g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi + if fatal then wfatal("in include file") end +end + +-- Make .include and conditionals initially available, too. +map_op[".include_1"] = map_coreop[".include_1"] +map_op[".if_1"] = map_coreop[".if_1"] +map_op[".elif_1"] = map_coreop[".elif_1"] +map_op[".else_0"] = map_coreop[".else_0"] +map_op[".endif_0"] = map_coreop[".endif_0"] + +------------------------------------------------------------------------------ + +-- Support variables for macros. +local mac_capture, mac_lineno, mac_name +local mac_active = {} +local mac_list = {} + +-- Pseudo-opcode to define a macro. +map_coreop[".macro_*"] = function(mparams) + if not mparams then return "name [, params...]" end + -- Split off and validate macro name. + local name = remove(mparams, 1) + if not name then werror("missing macro name") end + if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then + wfatal("bad macro name `"..name.."'") + end + -- Validate macro parameter names. + local mdup = {} + for _,mp in ipairs(mparams) do + if not match(mp, "^[%a_][%w_]*$") then + wfatal("bad macro parameter name `"..mp.."'") + end + if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end + mdup[mp] = true + end + -- Check for duplicate or recursive macro definitions. + local opname = name.."_"..#mparams + if map_op[opname] or map_op[name.."_*"] then + wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") + end + if mac_capture then wfatal("recursive macro definition") end + + -- Enable statement capture. + local lines = {} + mac_lineno = g_lineno + mac_name = name + mac_capture = function(stmt) -- Statement capture function. + -- Stop macro definition with .endmacro pseudo-opcode. + if not match(stmt, "^%s*.endmacro%s*$") then + lines[#lines+1] = stmt + return + end + mac_capture = nil + mac_lineno = nil + mac_name = nil + mac_list[#mac_list+1] = opname + -- Add macro-op definition. + map_op[opname] = function(params) + if not params then return mparams, lines end + -- Protect against recursive macro invocation. + if mac_active[opname] then wfatal("recursive macro invocation") end + mac_active[opname] = true + -- Setup substitution map. + local subst = {} + for i,mp in ipairs(mparams) do subst[mp] = params[i] end + local mcom + if g_opt.maccomment and g_opt.comment then + mcom = " MACRO "..name.." ("..#mparams..")" + wcomment("{"..mcom) + end + -- Loop through all captured statements + for _,stmt in ipairs(lines) do + -- Substitute macro parameters. + local st = gsub(stmt, "[%w_]+", subst) + st = definesubst(st) + st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. + if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end + -- Emit statement. Use a protected call for better diagnostics. + local ok, err = pcall(dostmt, st) + if not ok then + -- Add the captured statement to the error. + wprinterr(err, "\n", g_indent, "| ", stmt, + "\t[MACRO ", name, " (", #mparams, ")]\n") + end + end + if mcom then wcomment("}"..mcom) end + mac_active[opname] = nil + end + end +end + +-- An .endmacro pseudo-opcode outside of a macro definition is an error. +map_coreop[".endmacro_0"] = function(params) + wfatal(".endmacro without .macro") +end + +-- Dump all macros and their contents (with -PP only). +local function dumpmacros(out, lvl) + sort(mac_list) + out:write("Macros:\n") + for _,opname in ipairs(mac_list) do + local name = sub(opname, 1, -3) + local params, lines = map_op[opname]() + out:write(format(" %-20s %s\n", name, concat(params, ", "))) + if lvl > 1 then + for _,line in ipairs(lines) do + out:write(" |", line, "\n") + end + out:write("\n") + end + end + out:write("\n") +end + +-- Check for unfinished macro definitions. +local function checkmacros() + if mac_capture then + wprinterr(g_fname, ":", mac_lineno, + ": error: unfinished .macro `", mac_name ,"'\n") + end +end + +------------------------------------------------------------------------------ + +-- Support variables for captures. +local cap_lineno, cap_name +local cap_buffers = {} +local cap_used = {} + +-- Start a capture. +map_coreop[".capture_1"] = function(params) + if not params then return "name" end + wflush() + local name = params[1] + if not match(name, "^[%a_][%w_]*$") then + wfatal("bad capture name `"..name.."'") + end + if cap_name then + wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) + end + cap_name = name + cap_lineno = g_lineno + -- Create or continue a capture buffer and start the output line capture. + local buf = cap_buffers[name] + if not buf then buf = {}; cap_buffers[name] = buf end + g_capbuffer = buf + g_synclineno = 0 +end + +-- Stop a capture. +map_coreop[".endcapture_0"] = function(params) + wflush() + if not cap_name then wfatal(".endcapture without a valid .capture") end + cap_name = nil + cap_lineno = nil + g_capbuffer = nil + g_synclineno = 0 +end + +-- Dump a capture buffer. +map_coreop[".dumpcapture_1"] = function(params) + if not params then return "name" end + wflush() + local name = params[1] + if not match(name, "^[%a_][%w_]*$") then + wfatal("bad capture name `"..name.."'") + end + cap_used[name] = true + wline(function(out) + local buf = cap_buffers[name] + if buf then wdumplines(out, buf) end + end) + g_synclineno = 0 +end + +-- Dump all captures and their buffers (with -PP only). +local function dumpcaptures(out, lvl) + out:write("Captures:\n") + for name,buf in pairs(cap_buffers) do + out:write(format(" %-20s %4s)\n", name, "("..#buf)) + if lvl > 1 then + local bar = rep("=", 76) + out:write(" ", bar, "\n") + for _,line in ipairs(buf) do + out:write(" ", line, "\n") + end + out:write(" ", bar, "\n\n") + end + end + out:write("\n") +end + +-- Check for unfinished or unused captures. +local function checkcaptures() + if cap_name then + wprinterr(g_fname, ":", cap_lineno, + ": error: unfinished .capture `", cap_name,"'\n") + return + end + for name in pairs(cap_buffers) do + if not cap_used[name] then + wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") + end + end +end + +------------------------------------------------------------------------------ + +-- Sections names. +local map_sections = {} + +-- Pseudo-opcode to define code sections. +-- TODO: Data sections, BSS sections. Needs extra C code and API. +map_coreop[".section_*"] = function(params) + if not params then return "name..." end + if #map_sections > 0 then werror("duplicate section definition") end + wflush() + for sn,name in ipairs(params) do + local opname = "."..name.."_0" + if not match(name, "^[%a][%w_]*$") or + map_op[opname] or map_op["."..name.."_*"] then + werror("bad section name `"..name.."'") + end + map_sections[#map_sections+1] = name + wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) + map_op[opname] = function(params) g_arch.section(sn-1) end + end + wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) +end + +-- Dump all sections. +local function dumpsections(out, lvl) + out:write("Sections:\n") + for _,name in ipairs(map_sections) do + out:write(format(" %s\n", name)) + end + out:write("\n") +end + +------------------------------------------------------------------------------ + +-- Replacement for customized Lua, which lacks the package library. +local prefix = "" +if not require then + function require(name) + local fp = assert(io.open(prefix..name..".lua")) + local s = fp:read("*a") + assert(fp:close()) + return assert(loadstring(s, "@"..name..".lua"))() + end +end + +-- Load architecture-specific module. +local function loadarch(arch) + if not match(arch, "^[%w_]+$") then return "bad arch name" end + local ok, m_arch = pcall(require, "dasm_"..arch) + if not ok then return "cannot load module: "..m_arch end + g_arch = m_arch + wflush = m_arch.passcb(wline, werror, wfatal, wwarn) + m_arch.setup(arch, g_opt) + map_op, map_def = m_arch.mergemaps(map_coreop, map_def) +end + +-- Dump architecture description. +function opt_map.dumparch(args) + local name = optparam(args) + if not g_arch then + local err = loadarch(name) + if err then opterror(err) end + end + + local t = {} + for name in pairs(map_coreop) do t[#t+1] = name end + for name in pairs(map_op) do t[#t+1] = name end + sort(t) + + local out = stdout + local _arch = g_arch._info + out:write(format("%s version %s, released %s, %s\n", + _info.name, _info.version, _info.release, _info.url)) + g_arch.dumparch(out) + + local pseudo = true + out:write("Pseudo-Opcodes:\n") + for _,sname in ipairs(t) do + local name, nparam = match(sname, "^(.+)_([0-9%*])$") + if name then + if pseudo and sub(name, 1, 1) ~= "." then + out:write("\nOpcodes:\n") + pseudo = false + end + local f = map_op[sname] + local s + if nparam ~= "*" then nparam = nparam + 0 end + if nparam == 0 then + s = "" + elseif type(f) == "string" then + s = map_op[".template__"](nil, f, nparam) + else + s = f(nil, nparam) + end + if type(s) == "table" then + for _,s2 in ipairs(s) do + out:write(format(" %-12s %s\n", name, s2)) + end + else + out:write(format(" %-12s %s\n", name, s)) + end + end + end + out:write("\n") + exit(0) +end + +-- Pseudo-opcode to set the architecture. +-- Only initially available (map_op is replaced when called). +map_op[".arch_1"] = function(params) + if not params then return "name" end + local err = loadarch(params[1]) + if err then wfatal(err) end +end + +-- Dummy .arch pseudo-opcode to improve the error report. +map_coreop[".arch_1"] = function(params) + if not params then return "name" end + wfatal("duplicate .arch statement") +end + +------------------------------------------------------------------------------ + +-- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. +map_coreop[".nop_*"] = function(params) + if not params then return "[ignored...]" end +end + +-- Pseudo-opcodes to raise errors. +map_coreop[".error_1"] = function(params) + if not params then return "message" end + werror(params[1]) +end + +map_coreop[".fatal_1"] = function(params) + if not params then return "message" end + wfatal(params[1]) +end + +-- Dump all user defined elements. +local function dumpdef(out) + local lvl = g_opt.dumpdef + if lvl == 0 then return end + dumpsections(out, lvl) + dumpdefines(out, lvl) + if g_arch then g_arch.dumpdef(out, lvl) end + dumpmacros(out, lvl) + dumpcaptures(out, lvl) +end + +------------------------------------------------------------------------------ + +-- Helper for splitstmt. +local splitlvl + +local function splitstmt_one(c) + if c == "(" then + splitlvl = ")"..splitlvl + elseif c == "[" then + splitlvl = "]"..splitlvl + elseif c == "{" then + splitlvl = "}"..splitlvl + elseif c == ")" or c == "]" or c == "}" then + if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end + splitlvl = sub(splitlvl, 2) + elseif splitlvl == "" then + return " \0 " + end + return c +end + +-- Split statement into (pseudo-)opcode and params. +local function splitstmt(stmt) + -- Convert label with trailing-colon into .label statement. + local label = match(stmt, "^%s*(.+):%s*$") + if label then return ".label", {label} end + + -- Split at commas and equal signs, but obey parentheses and brackets. + splitlvl = "" + stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) + if splitlvl ~= "" then werror("unbalanced () or []") end + + -- Split off opcode. + local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") + if not op then werror("bad statement syntax") end + + -- Split parameters. + local params = {} + for p in gmatch(other, "%s*(%Z+)%z?") do + params[#params+1] = gsub(p, "%s+$", "") + end + if #params > 16 then werror("too many parameters") end + + params.op = op + return op, params +end + +-- Process a single statement. +dostmt = function(stmt) + -- Ignore empty statements. + if match(stmt, "^%s*$") then return end + + -- Capture macro defs before substitution. + if mac_capture then return mac_capture(stmt) end + stmt = definesubst(stmt) + + -- Emit C code without parsing the line. + if sub(stmt, 1, 1) == "|" then + local tail = sub(stmt, 2) + wflush() + if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end + return + end + + -- Split into (pseudo-)opcode and params. + local op, params = splitstmt(stmt) + + -- Get opcode handler (matching # of parameters or generic handler). + local f = map_op[op.."_"..#params] or map_op[op.."_*"] + if not f then + if not g_arch then wfatal("first statement must be .arch") end + -- Improve error report. + for i=0,9 do + if map_op[op.."_"..i] then + werror("wrong number of parameters for `"..op.."'") + end + end + werror("unknown statement `"..op.."'") + end + + -- Call opcode handler or special handler for template strings. + if type(f) == "string" then + map_op[".template__"](params, f) + else + f(params) + end +end + +-- Process a single line. +local function doline(line) + if g_opt.flushline then wflush() end + + -- Assembler line? + local indent, aline = match(line, "^(%s*)%|(.*)$") + if not aline then + -- No, plain C code line, need to flush first. + wflush() + wsync() + wline(line, false) + return + end + + g_indent = indent -- Remember current line indentation. + + -- Emit C code (even from macros). Avoids echo and line parsing. + if sub(aline, 1, 1) == "|" then + if not mac_capture then + wsync() + elseif g_opt.comment then + wsync() + wcomment(aline) + end + dostmt(aline) + return + end + + -- Echo assembler line as a comment. + if g_opt.comment then + wsync() + wcomment(aline) + end + + -- Strip assembler comments. + aline = gsub(aline, "//.*$", "") + + -- Split line into statements at semicolons. + if match(aline, ";") then + for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end + else + dostmt(aline) + end +end + +------------------------------------------------------------------------------ + +-- Write DynASM header. +local function dasmhead(out) + out:write(format([[ +/* +** This file has been pre-processed with DynASM. +** %s +** DynASM version %s, DynASM %s version %s +** DO NOT EDIT! The original file is in "%s". +*/ + +#if DASM_VERSION != %d +#error "Version mismatch between DynASM and included encoding engine" +#endif + +]], _info.url, + _info.version, g_arch._info.arch, g_arch._info.version, + g_fname, _info.vernum)) +end + +-- Read input file. +readfile = function(fin) + g_indent = "" + g_lineno = 0 + g_synclineno = -1 + + -- Process all lines. + for line in fin:lines() do + g_lineno = g_lineno + 1 + g_curline = line + local ok, err = pcall(doline, line) + if not ok and wprinterr(err, "\n") then return true end + end + wflush() + + -- Close input file. + assert(fin == stdin or fin:close()) +end + +-- Write output file. +local function writefile(outfile) + local fout + + -- Open output file. + if outfile == nil or outfile == "-" then + fout = stdout + else + fout = assert(io.open(outfile, "w")) + end + + -- Write all buffered lines + wdumplines(fout, g_wbuffer) + + -- Close output file. + assert(fout == stdout or fout:close()) + + -- Optionally dump definitions. + dumpdef(fout == stdout and stderr or stdout) +end + +-- Translate an input file to an output file. +local function translate(infile, outfile) + g_wbuffer = {} + g_indent = "" + g_lineno = 0 + g_synclineno = -1 + + -- Put header. + wline(dasmhead) + + -- Read input file. + local fin + if infile == "-" then + g_fname = "(stdin)" + fin = stdin + else + g_fname = infile + fin = assert(io.open(infile, "r")) + end + readfile(fin) + + -- Check for errors. + if not g_arch then + wprinterr(g_fname, ":*: error: missing .arch directive\n") + end + checkconds() + checkmacros() + checkcaptures() + + if g_errcount ~= 0 then + stderr:write(g_fname, ":*: info: ", g_errcount, " error", + (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", + " in input file -- no output file generated.\n") + dumpdef(stderr) + exit(1) + end + + -- Write output file. + writefile(outfile) +end + +------------------------------------------------------------------------------ + +-- Print help text. +function opt_map.help() + stdout:write("DynASM -- ", _info.description, ".\n") + stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") + stdout:write[[ + +Usage: dynasm [OPTION]... INFILE.dasc|- + + -h, --help Display this help text. + -V, --version Display version and copyright information. + + -o, --outfile FILE Output file name (default is stdout). + -I, --include DIR Add directory to the include search path. + + -c, --ccomment Use /* */ comments for assembler lines. + -C, --cppcomment Use // comments for assembler lines (default). + -N, --nocomment Suppress assembler lines in output. + -M, --maccomment Show macro expansions as comments (default off). + + -L, --nolineno Suppress CPP line number information in output. + -F, --flushline Flush action list for every line. + + -D NAME[=SUBST] Define a substitution. + -U NAME Undefine a substitution. + + -P, --dumpdef Dump defines, macros, etc. Repeat for more output. + -A, --dumparch ARCH Load architecture ARCH and dump description. +]] + exit(0) +end + +-- Print version information. +function opt_map.version() + stdout:write(format("%s version %s, released %s\n%s\n\n%s", + _info.name, _info.version, _info.release, _info.url, _info.copyright)) + exit(0) +end + +-- Misc. options. +function opt_map.outfile(args) g_opt.outfile = optparam(args) end +function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end +function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end +function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end +function opt_map.nocomment() g_opt.comment = false end +function opt_map.maccomment() g_opt.maccomment = true end +function opt_map.nolineno() g_opt.cpp = false end +function opt_map.flushline() g_opt.flushline = true end +function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end + +------------------------------------------------------------------------------ + +-- Short aliases for long options. +local opt_alias = { + h = "help", ["?"] = "help", V = "version", + o = "outfile", I = "include", + c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", + L = "nolineno", F = "flushline", + P = "dumpdef", A = "dumparch", +} + +-- Parse single option. +local function parseopt(opt, args) + opt_current = #opt == 1 and "-"..opt or "--"..opt + local f = opt_map[opt] or opt_map[opt_alias[opt]] + if not f then + opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") + end + f(args) +end + +-- Parse arguments. +local function parseargs(args) + -- Default options. + g_opt.comment = "//|" + g_opt.endcomment = "" + g_opt.cpp = true + g_opt.dumpdef = 0 + g_opt.include = { "" } + + -- Process all option arguments. + args.argn = 1 + repeat + local a = args[args.argn] + if not a then break end + local lopt, opt = match(a, "^%-(%-?)(.+)") + if not opt then break end + args.argn = args.argn + 1 + if lopt == "" then + -- Loop through short options. + for o in gmatch(opt, ".") do parseopt(o, args) end + else + -- Long option. + parseopt(opt, args) + end + until false + + -- Check for proper number of arguments. + local nargs = #args - args.argn + 1 + if nargs ~= 1 then + if nargs == 0 then + if g_opt.dumpdef > 0 then return dumpdef(stdout) end + end + opt_map.help() + end + + -- Translate a single input file to a single output file + -- TODO: Handle multiple files? + translate(args[args.argn], g_opt.outfile) +end + +------------------------------------------------------------------------------ + +-- Add the directory dynasm.lua resides in to the Lua module search path. +local arg = arg +if arg and arg[0] then + prefix = match(arg[0], "^(.*[/\\])") + if package and prefix then package.path = prefix.."?.lua;"..package.path end +end + +-- Start DynASM. +parseargs{...} + +------------------------------------------------------------------------------ + diff --git a/lib/sregex/libsregex.a b/lib/sregex/libsregex.a new file mode 100644 index 0000000..c1d8cab Binary files /dev/null and b/lib/sregex/libsregex.a differ diff --git a/lib/sregex/libsregex.so b/lib/sregex/libsregex.so new file mode 100755 index 0000000..6702294 Binary files /dev/null and b/lib/sregex/libsregex.so differ diff --git a/lib/sregex/libsregex.so.0 b/lib/sregex/libsregex.so.0 new file mode 120000 index 0000000..1eb3c5a --- /dev/null +++ b/lib/sregex/libsregex.so.0 @@ -0,0 +1 @@ +libsregex.so \ No newline at end of file diff --git a/lib/sregex/misc/bts-to-test-or.patch b/lib/sregex/misc/bts-to-test-or.patch new file mode 100644 index 0000000..5c6d8a3 --- /dev/null +++ b/lib/sregex/misc/bts-to-test-or.patch @@ -0,0 +1,29 @@ +diff --git a/src/sregex/sre_vm_thompson_x64.dasc b/src/sregex/sre_vm_thompson_x64.dasc +index c7f59e4..0d3b8bd 100644 +--- a/src/sregex/sre_vm_thompson_x64.dasc ++++ b/src/sregex/sre_vm_thompson_x64.dasc +@@ -39,6 +39,7 @@ + + /* recording threads added */ + |.define ADDED, rcx ++|.define ADDEDd, ecx + + |.type CTX, sre_vm_thompson_ctx_t, rdi // 1st arg + |.type TL, sre_vm_thompson_thread_list_t, r15 // callee-save +@@ -92,8 +93,16 @@ + || bofs = tid; + ||} + | ++||if (bofs < 32) { ++| test ADDEDd, (1 << bofs) ++| jnz >2 ++| or ADDEDd, (1 << bofs) ++| ++||} else { ++| + | bts ADDED, (bofs) // load CF with the bit and set the bit + | jb >2 // jump if CF = 1 ++||} + | + ||if (jit->threads_added_in_memory) { + | mov CTX->threads_added[(tid / 64)], ADDED diff --git a/lib/sregex/misc/eof-lb-as-flags.patch b/lib/sregex/misc/eof-lb-as-flags.patch new file mode 100644 index 0000000..51aa8aa --- /dev/null +++ b/lib/sregex/misc/eof-lb-as-flags.patch @@ -0,0 +1,141 @@ +diff --git a/src/sregex/sre_vm_thompson_x64.dasc b/src/sregex/sre_vm_thompson_x64.dasc +index c27441c..ab342e0 100644 +--- a/src/sregex/sre_vm_thompson_x64.dasc ++++ b/src/sregex/sre_vm_thompson_x64.dasc +@@ -26,13 +26,10 @@ + + |.define LAST, rdx // overriding 3rd arg + |.define INPUT, rsi // 2nd arg +-|.define EOF, bl // 4th arg +- +-/* seen last byte */ +-|.define LB, bh ++|.define FLAGS, bh // 4th arg + + /* current input string byte */ +-|.define C, r11b ++|.define C, bl + + /* the position after the last thread */ + |.define LT, r9 +@@ -130,7 +127,7 @@ + + |.macro testWordChar + ||if (!char_always_valid) { +-| test LB, LB ++| test FLAGS, (FLAG_LB) + | jnz >2 + ||} + | cmp C, byte '0' +@@ -162,6 +159,10 @@ + #define Dst dasm + + ++#define FLAG_EOF 0x01 ++#define FLAG_LB 0x02 ++ ++ + #include + #include + #include +@@ -424,7 +425,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + + switch (pc->opcode) { + case SRE_OPCODE_ANY: +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jnz >1 + + break; +@@ -432,7 +433,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + case SRE_OPCODE_CHAR: + c = pc->v.ch; + +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jnz >1 + | + | cmp C, byte (c) +@@ -441,7 +442,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + break; + + case SRE_OPCODE_IN: +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jnz >1 + + for (i = 0; i < pc->v.ranges->count; i++) { +@@ -478,7 +479,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + break; + + case SRE_OPCODE_NOTIN: +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jnz >1 + + for (i = 0; i < pc->v.ranges->count; i++) { +@@ -746,19 +747,16 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + | push TC; push TL; push T; push SW; push LAST; push SP; + | push CTL; push CT; push LT; push rbx; push r11; push ADDED + | ++ | xor FLAGS, FLAGS ++ | + | // check the 4th arg, "eof" + | test ecx, ecx + | jz >1 +- | mov EOF, 1 +- | jmp >2 ++ | or FLAGS, (FLAG_EOF) + | + |1: +- | xor EOF, EOF +- | +- |2: + | mov CTL, CTX->current_threads + | mov TC, CTL->count +- | xor LB, LB + | + | mov al, CTX->first_buf + | test al, al +@@ -794,9 +792,9 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + | jmp ->run_cur_threads + | + |->buf_consumed: +- | test EOF, EOF ++ | test FLAGS, (FLAG_EOF) + | jz ->again +- | mov LB, 1 ++ | or FLAGS, (FLAG_LB) + | + |->run_cur_threads: + | test TC, TC +@@ -861,11 +859,11 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + | mov CTL, TL + | mov TL, rax + | +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jz ->sp_loop_next + | + |->done: +- | test EOF, EOF ++ | test FLAGS, (FLAG_EOF) + | jz ->again + | mov rax, (SRE_DECLINED) + | jmp ->return +@@ -914,13 +912,13 @@ sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) + |=>(len + flags - 1): + + if (flags & SRE_REGEX_ASSERT_SMALL_Z) { +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jz >1 + } + + if (flags & SRE_REGEX_ASSERT_DOLLAR) { + if (!(flags & SRE_REGEX_ASSERT_SMALL_Z)) { +- | test LB, LB ++ | test FLAGS, (FLAG_LB) + | jnz >2 + } + diff --git a/lib/sregex/misc/r13-fast-ret.patch b/lib/sregex/misc/r13-fast-ret.patch new file mode 100644 index 0000000..9e7898f --- /dev/null +++ b/lib/sregex/misc/r13-fast-ret.patch @@ -0,0 +1,122 @@ +diff --git a/src/sregex/sre_vm_thompson_x64.dasc b/src/sregex/sre_vm_thompson_x64.dasc +index c27441c..ead5f11 100644 +--- a/src/sregex/sre_vm_thompson_x64.dasc ++++ b/src/sregex/sre_vm_thompson_x64.dasc +@@ -19,7 +19,7 @@ + |.define TC, r14 // callee-save + + /* seen word */ +-|.define SW, r13 // callee-save ++|.define RETADDR, r13 // callee-save + + /* string pointer */ + |.define SP, r12 // callee-save +@@ -158,6 +158,11 @@ + |.endmacro + + ++|.macro fastRet ++| jmp RETADDR ++|.endmacro ++ ++ + /* This affects the "|" DynASM lines. */ + #define Dst dasm + +@@ -588,7 +593,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + + } else { + | mov eax, 1 +- | ret ++ | fastRet + } + + } else { +@@ -614,7 +619,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + + |1: + | xor eax, eax +- | ret ++ | fastRet + + return SRE_OK; + } +@@ -743,7 +748,7 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + + dasm = jit->dasm; + +- | push TC; push TL; push T; push SW; push LAST; push SP; ++ | push TC; push TL; push T; push RETADDR; push LAST; push SP; + | push CTL; push CT; push LT; push rbx; push r11; push ADDED + | + | // check the 4th arg, "eof" +@@ -768,8 +773,10 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + | mov byte CTX->first_buf, 0 + | + | mov TL, CTL +- | xor SW, SW +- | call =>0 ++ | lea RETADDR, [->init_pc_called] ++ | jmp =>0 ++ | ++ |->init_pc_called: + | test eax, eax + | jz ->not_first_buf + | xor rax, rax // (SRE_OK) +@@ -839,16 +846,21 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + if (jit->program->lookahead_asserts) { + | mov rax, CT->asserts_handler + | test rax, rax +- | jz >1 +- | call rax ++ | jz >2 ++ | ++ | lea RETADDR, qword [>1] ++ | jmp rax ++ |1: + | test eax, eax + | jz ->run_next_thread + | +- |1: ++ |2: + } + +- | call aword CT->pc ++ | lea RETADDR, qword [->pc_called] ++ | jmp aword CT->pc + | ++ |->pc_called: + | test eax, eax + | jz ->run_next_thread + | +@@ -882,7 +894,7 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + | mov TL->count, TC + | + | pop ADDED; pop r11; pop rbx; pop LT; pop CT; pop CTL; +- | pop SP; pop LAST; pop SW; pop T; pop TL; pop TC ++ | pop SP; pop LAST; pop RETADDR; pop T; pop TL; pop TC + | ret + + return SRE_OK; +@@ -903,7 +915,7 @@ sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) + + |->match: + | mov eax, 1 +- | ret ++ | fastRet + + for (flags = 1; flags <= SRE_REGEX_ASSERT_LOOKAHEAD; flags++) { + +@@ -944,10 +956,10 @@ sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) + } + + | mov eax, 1 +- | ret ++ | fastRet + |1: + | xor eax, eax +- | ret ++ | fastRet + } + } + diff --git a/lib/sregex/misc/sse-fast-ret.patch b/lib/sregex/misc/sse-fast-ret.patch new file mode 100644 index 0000000..96ff31f --- /dev/null +++ b/lib/sregex/misc/sse-fast-ret.patch @@ -0,0 +1,99 @@ +diff --git a/src/sregex/sre_vm_thompson_x64.dasc b/src/sregex/sre_vm_thompson_x64.dasc +index c27441c..3a754bb 100644 +--- a/src/sregex/sre_vm_thompson_x64.dasc ++++ b/src/sregex/sre_vm_thompson_x64.dasc +@@ -158,6 +158,13 @@ + |.endmacro + + ++|.macro fastRet ++| // r8 is T, which is no longer used ++| movd r8, xmm0 ++| jmp r8 ++|.endmacro ++ ++ + /* This affects the "|" DynASM lines. */ + #define Dst dasm + +@@ -588,7 +595,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + + } else { + | mov eax, 1 +- | ret ++ | fastRet + } + + } else { +@@ -614,7 +621,7 @@ sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + + |1: + | xor eax, eax +- | ret ++ | fastRet + + return SRE_OK; + } +@@ -769,7 +776,11 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + | + | mov TL, CTL + | xor SW, SW +- | call =>0 ++ | lea rax, [->init_pc_called] ++ | movd xmm0, rax ++ | jmp =>0 ++ | ++ |->init_pc_called: + | test eax, eax + | jz ->not_first_buf + | xor rax, rax // (SRE_OK) +@@ -839,16 +850,23 @@ sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) + if (jit->program->lookahead_asserts) { + | mov rax, CT->asserts_handler + | test rax, rax +- | jz >1 +- | call rax ++ | jz >2 ++ | ++ | lea r8, qword [>1] ++ | movd xmm0, r8 ++ | jmp rax ++ |1: + | test eax, eax + | jz ->run_next_thread + | +- |1: ++ |2: + } + +- | call aword CT->pc ++ | lea r8, qword [->pc_called] ++ | movd xmm0, r8 ++ | jmp aword CT->pc + | ++ |->pc_called: + | test eax, eax + | jz ->run_next_thread + | +@@ -903,7 +921,7 @@ sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) + + |->match: + | mov eax, 1 +- | ret ++ | fastRet + + for (flags = 1; flags <= SRE_REGEX_ASSERT_LOOKAHEAD; flags++) { + +@@ -944,10 +962,10 @@ sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) + } + + | mov eax, 1 +- | ret ++ | fastRet + |1: + | xor eax, eax +- | ret ++ | fastRet + } + } + diff --git a/lib/sregex/src/sre_cli.c b/lib/sregex/src/sre_cli.c new file mode 100644 index 0000000..e238b81 --- /dev/null +++ b/lib/sregex/src/sre_cli.c @@ -0,0 +1,711 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include +#include +#include +#include +#include + + +static void usage(void); +static void process_string(sre_char *s, size_t len, sre_program_t *prog, + sre_int_t *ovector, size_t ovecsize, sre_uint_t ncaps); +sre_int_t run_jitted_thompson(sre_vm_thompson_exec_pt handler, + sre_vm_thompson_ctx_t *ctx, sre_char *input, size_t size, unsigned eof); +static sre_int_t parse_regex_flags(const char *flags_str, int nregexes, + int *multi_flags); + + +int +main(int argc, char **argv) +{ + sre_uint_t i, n; + const char *flags_str = NULL; + int *multi_flags = NULL; + sre_int_t err_offset = -1, err_regex_id; + sre_pool_t *ppool; /* parser pool */ + sre_pool_t *cpool; /* compiler pool */ + sre_regex_t *re; + sre_program_t *prog; + sre_uint_t ncaps; + sre_int_t *ovector; + size_t ovecsize; + sre_char *s, *p; + size_t len; + unsigned from_stdin = 0; + sre_int_t nregexes = 1; + + if (argc < 2) { + usage(); + } + + for (i = 1; i < argc; i++) { + if (argv[i][0] != '-') { + break; + } + + if (strncmp(argv[i], "--stdin", sizeof("--stdin") - 1) == 0) { + from_stdin = 1; + + } else if (strncmp(argv[i], "--flags", sizeof("--flags") - 1) == 0) { + if (i == argc - 1) { + fprintf(stderr, "--flags should take a value.\n"); + return 1; + } + + i++; + + flags_str = argv[i]; + + } else if (strncmp(argv[i], "-n", 2) == 0) { + if (i == argc - 1) { + fprintf(stderr, "-n should take a value.\n"); + return 1; + } + + i++; + + nregexes = atoi(argv[i]); + if (nregexes <= 0) { + fprintf(stderr, "invalid -n value: %s.\n", argv[i]); + return 1; + } + + } else { + fprintf(stderr, "unknown option: %s\n", argv[i]); + return 1; + } + } + + ppool = sre_create_pool(1024); + if (ppool == NULL) { + return 2; + } + + dd("nregexes: %d", (int) nregexes); + + if (flags_str) { + multi_flags = malloc(nregexes * sizeof(int)); + if (multi_flags == NULL) { + return 2; + } + + memset(multi_flags, 0, nregexes * sizeof(int)); + + if (parse_regex_flags(flags_str, nregexes, multi_flags) != SRE_OK) { + fprintf(stderr, "Bad --flags option value: %s", flags_str); + free(multi_flags); + return 1; + } + } + + if (nregexes == 1) { + re = sre_regex_parse(ppool, (sre_char *) argv[i], &ncaps, + multi_flags ? multi_flags[0] : 0, &err_offset); + if (re == NULL) { + if (err_offset >= 0) { + fprintf(stderr, "[error] syntax error at pos %lld\n", + (long long) err_offset); + + } else { + fprintf(stderr, "unknown error\n"); + } + + if (multi_flags) { + free(multi_flags); + } + + sre_destroy_pool(ppool); + return 1; + } + + i++; + + } else { + + if (argc - i < nregexes) { + fprintf(stderr, "at least %ld regexes should be specified\n", + (long) nregexes); + + if (multi_flags) { + free(multi_flags); + } + + sre_destroy_pool(ppool); + return 1; + } + + re = sre_regex_parse_multi(ppool, (sre_char **) &argv[i], nregexes, + &ncaps, multi_flags, &err_offset, &err_regex_id); + if (re == NULL) { + if (err_offset >= 0) { + fprintf(stderr, "[error] regex %lu: syntax error at pos %ld\n", + (unsigned long) err_regex_id, (long) err_offset); + + } else { + fprintf(stderr, "unknown error\n"); + } + + if (multi_flags) { + free(multi_flags); + } + + sre_destroy_pool(ppool); + return 1; + } + + i += nregexes; + } + + sre_regex_dump(re); + printf("\n"); + + printf("captures: %ld\n", (long) ncaps); + + cpool = sre_create_pool(1024); + if (cpool == NULL) { + if (multi_flags) { + free(multi_flags); + } + return 2; + } + + prog = sre_regex_compile(cpool, re); + if (prog == NULL) { + fprintf(stderr, "failed to compile the regex.\n"); + sre_destroy_pool(ppool); + sre_destroy_pool(cpool); + if (multi_flags) { + free(multi_flags); + } + return 2; + } + + sre_destroy_pool(ppool); + ppool = NULL; + re = NULL; + + sre_program_dump(prog); + + ovecsize = 2 * (ncaps + 1) * sizeof(sre_int_t); + ovector = malloc(ovecsize); + if (ovector == NULL) { + if (multi_flags) { + free(multi_flags); + } + return 2; + } + + if (from_stdin) { + + for (;;) { + { + int i, n; + + n = scanf("%d", &i); + if (n != 1) { + if (errno != 0) { + perror("scanf"); + exit(1); + } + + break; + } + + len = (size_t) i; + + n = getchar(); + if (n != '\n') { + fprintf(stderr, "the next character after the chunk size " + "must be a newline"); + exit(1); + } + } + + s = malloc(len); + if (s == NULL) { + free(ovector); + return 2; + } + + n = fread(s, 1, len, stdin); + if (n < len) { + fprintf(stderr, "failed to read %ld bytes of string from " + "stdin (only read %ld bytes).", (long) len, (long) n); + + free(s); + free(ovector); + return 2; + } + + process_string(s, len, prog, ovector, ovecsize, ncaps); + + free(s); + } + + } else { + + if (i >= argc) { + fprintf(stderr, "no subject string specified.\n"); + return 1; + } + + for (; i < argc; i++) { + len = strlen(argv[i]); + p = (sre_char *) argv[i]; + + s = malloc(len); + if (s == NULL) { + free(ovector); + return 2; + } + + memcpy(s, p, len); + + process_string(s, len, prog, ovector, ovecsize, ncaps); + + free(s); + } + } + + sre_destroy_pool(cpool); + prog = NULL; + cpool = NULL; + free(ovector); + + if (multi_flags) { + free(multi_flags); + } + + return 0; +} + + +static void +process_string(sre_char *s, size_t len, sre_program_t *prog, sre_int_t *ovector, + size_t ovecsize, sre_uint_t ncaps) +{ + sre_uint_t i, j; + sre_int_t rc; + sre_char *p; + unsigned gen_empty_buf; + sre_int_t *pending_matched; + sre_pool_t *pool; + sre_vm_pike_ctx_t *pctx; + sre_vm_thompson_ctx_t *tctx; + sre_vm_thompson_code_t *tcode; + sre_vm_thompson_exec_pt texec; + + printf("## %.*s (len %d)\n", (int) len, s, (int) len); + + p = malloc(1); + if (p == NULL) { + exit(2); + } + + pool = sre_create_pool(1024); + if (pool == NULL) { + free(p); + exit(2); + } + + /* + * Thompson + */ + + printf("thompson "); + + tctx = sre_vm_thompson_create_ctx(pool, prog); + assert(tctx); + + rc = sre_vm_thompson_exec(tctx, s, len, 1); + + switch (rc) { + case SRE_OK: + printf("match\n"); + break; + + case SRE_DECLINED: + printf("no match\n"); + break; + + case SRE_AGAIN: + printf("again\n"); + break; + + case SRE_ERROR: + printf("error\n"); + break; + + default: + assert(rc); + } + + sre_reset_pool(pool); + + /* + * Splitted Thompson + */ + + printf("splitted thompson "); + + tctx = sre_vm_thompson_create_ctx(pool, prog); + assert(tctx); + + gen_empty_buf = 1; + + for (i = 0; i <= len; i++) { + if (i == len) { + rc = sre_vm_thompson_exec(tctx, NULL, 0 /* len */, 1 /* eof */); + + } else if (gen_empty_buf) { + rc = sre_vm_thompson_exec(tctx, NULL, 0 /* len */, 0 /* eof */); + gen_empty_buf = 0; + i--; + + } else { + p[0] = s[i]; + + rc = sre_vm_thompson_exec(tctx, p, 1 /* len */, 0 /* eof */); + gen_empty_buf = 1; + } + + switch (rc) { + case SRE_AGAIN: +#if 0 + printf("again"); +#endif + continue; + + case SRE_OK: + printf("match\n"); + break; + + case SRE_DECLINED: + printf("no match\n"); + break; + + case SRE_ERROR: + printf("error\n"); + break; + + default: + assert(rc); + } + + break; + } + + sre_reset_pool(pool); + + /* + * run Thompson VM's JIT compiler + */ + + rc = sre_vm_thompson_jit_compile(pool, prog, &tcode); + if (rc == SRE_DECLINED) { + printf("jitted thompson disabled\n"); + printf("splitted jitted thompson disabled\n"); + goto pike; + } + + if (rc != SRE_OK) { + fprintf(stderr, "failed to run thompson jit compile: %ld\n", (long) rc); + exit(2); + } + + texec = sre_vm_thompson_jit_get_handler(tcode); + if (texec == NULL) { + fprintf(stderr, "failed to get thompson jit handler.\n"); + exit(2); + } + + /* + * JITted Thompson + */ + + printf("jitted thompson "); + + tctx = sre_vm_thompson_jit_create_ctx(pool, prog); + assert(tctx); + + rc = run_jitted_thompson(texec, tctx, s, len, 1); +#if 0 + rc = (sre_int_t) run_jitted_thompson; +#endif + + switch (rc) { + case SRE_OK: + printf("match\n"); + break; + + case SRE_DECLINED: + printf("no match\n"); + break; + + case SRE_AGAIN: + printf("again\n"); + break; + + case SRE_ERROR: + printf("error\n"); + break; + + default: + printf("bad retval: %lx\n", (unsigned long) rc); + break; + } + + sre_reset_pool(pool); + + /* + * Splitted JITted Thompson + */ + + printf("splitted jitted thompson "); + + tctx = sre_vm_thompson_jit_create_ctx(pool, prog); + assert(tctx); + + gen_empty_buf = 1; + + for (i = 0; i <= len; i++) { + if (i == len) { + rc = run_jitted_thompson(texec, tctx, NULL, 0 /* len */, + 1 /* eof */); + + } else if (gen_empty_buf) { + rc = run_jitted_thompson(texec, tctx, NULL, 0 /* len */, + 0 /* eof */); + gen_empty_buf = 0; + i--; + + } else { + p[0] = s[i]; + + rc = run_jitted_thompson(texec, tctx, p, 1 /* len */, 0 /* eof */); + gen_empty_buf = 1; + } + + switch (rc) { + case SRE_AGAIN: +#if 0 + printf("again"); +#endif + continue; + + case SRE_OK: + printf("match\n"); + break; + + case SRE_DECLINED: + printf("no match\n"); + break; + + case SRE_ERROR: + printf("error\n"); + break; + + default: + assert(rc); + } + + break; + } + + if (sre_vm_thompson_jit_free(tcode) != SRE_OK) { + fprintf(stderr, "failed to free thompson jit.\n"); + exit(2); + } + + sre_reset_pool(pool); + +pike: + printf("pike "); + + pctx = sre_vm_pike_create_ctx(pool, prog, ovector, ovecsize); + assert(pctx); + + rc = sre_vm_pike_exec(pctx, s, len, 1 /* eof */, NULL); + + if (rc >= 0) { + printf("match %ld", (long) rc); + + for (i = 0; i < 2 * (ncaps + 1); i += 2) { + printf(" (%ld, %ld)", (long) ovector[i], (long) ovector[i + 1]); + } + + printf("\n"); + + } else { + switch (rc) { + case SRE_AGAIN: + printf("again\n"); + break; + + case SRE_DECLINED: + printf("no match\n"); + break; + + case SRE_ERROR: + printf("error\n"); + break; + + default: + printf("unknown (%d)\n", (int) rc); + break; + } + } + + sre_reset_pool(pool); + + printf("splitted pike "); + + dd("===== splitted pike ====="); + + pctx = sre_vm_pike_create_ctx(pool, prog, ovector, ovecsize); + assert(pctx); + + gen_empty_buf = 1; + + for (i = 0; i <= len; i++) { + if (i == len) { + rc = sre_vm_pike_exec(pctx, NULL, 0 /* len */, 1 /* eof */, + &pending_matched); + + } else if (gen_empty_buf) { + rc = sre_vm_pike_exec(pctx, NULL, 0 /* len */, 0 /* eof */, NULL); + gen_empty_buf = 0; + i--; + + } else { + p[0] = s[i]; + rc = sre_vm_pike_exec(pctx, p, 1 /* len */, 0 /* eof */, + &pending_matched); + +#if 1 + if (rc == SRE_AGAIN) { + printf("["); + for (j = 0; j < 2; j += 2) { + printf("(%ld, %ld)", (long) ovector[j], + (long) ovector[j + 1]); + } + printf("]"); + + if (pending_matched) { + printf("(%ld, %ld) ", (long) pending_matched[0], + (long) pending_matched[1]); + + } else { + printf(" "); + } + } +#endif + + gen_empty_buf = 1; + } + + dd("i = %d, rc = %d", (int) i, (int) rc); + + if (rc >= 0) { + printf("match %ld", (long) rc); + + for (j = 0; j < 2 * (ncaps + 1); j += 2) { + printf(" (%ld, %ld)", (long) ovector[j], (long) ovector[j + 1]); + } + + printf("\n"); + + } else { + switch (rc) { + case SRE_AGAIN: +#if 0 + printf("again\n"); +#endif + continue; + + case SRE_DECLINED: + printf("no match\n"); + break; + + case SRE_ERROR: + printf("error\n"); + break; + + default: + printf("unknown (%d)\n", (int) rc); + break; + } + } + + break; + } + + sre_destroy_pool(pool); + free(p); +} + + +static void +usage(void) +{ + fprintf(stderr, "usage: sregex-cli regexp string...\n"); + fprintf(stderr, " sregex-cli --stdin regexp\n"); + exit(2); +} + + +sre_int_t +run_jitted_thompson(sre_vm_thompson_exec_pt handler, sre_vm_thompson_ctx_t *ctx, + sre_char *input, size_t size, unsigned eof) +{ + return handler(ctx, input, size, eof); +} + + +static sre_int_t +parse_regex_flags(const char *flags_str, int nregexes, + int *multi_flags) +{ + int i = 0; + const char *p; + + for (p = flags_str; *p != '\0'; p++) { + if (i >= nregexes) { + fprintf(stderr, "Too many flags given but only %d regexes " + "specified.\n", nregexes); + + return SRE_ERROR; + } + + switch (*p) { + case ' ': + i++; + break; + + case 'i': + multi_flags[i] |= SRE_REGEX_CASELESS; + break; + + default: + fprintf(stderr, "Bad regex flag '%c' for regex %d\n", *p, i); + return SRE_ERROR; + } + } + + return SRE_OK; +} diff --git a/lib/sregex/src/sregex/ddebug.h b/lib/sregex/src/sregex/ddebug.h new file mode 100644 index 0000000..101e7bd --- /dev/null +++ b/lib/sregex/src/sregex/ddebug.h @@ -0,0 +1,29 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef _SREGEX_DDEBUG_H_INCLUDED_ +#define _SREGEX_DDEBUG_H_INCLUDED_ + + +#if defined(DDEBUG) && (DDEBUG) + +# include + +# define dd(...) \ + fprintf(stderr, "sregex ** "); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s:%d\n", __FILE__, __LINE__) + +#else + +# define dd(fmt, ...) + +#endif + + +#endif /* _SREGEX_DDEBUG_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_capture.c b/lib/sregex/src/sregex/sre_capture.c new file mode 100644 index 0000000..d1c1854 --- /dev/null +++ b/lib/sregex/src/sregex/sre_capture.c @@ -0,0 +1,99 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include + + +SRE_NOAPI sre_capture_t * +sre_capture_create(sre_pool_t *pool, size_t ovecsize, unsigned clear, + sre_capture_t **freecap) +{ + sre_char *p; + sre_capture_t *cap; + + if (*freecap) { + dd("reusing cap %p", *freecap); + cap = *freecap; + *freecap = cap->next; + cap->next = NULL; + cap->ref = 1; + + } else { + p = sre_pnalloc(pool, sizeof(sre_capture_t) + ovecsize); + if (p == NULL) { + return NULL; + } + + cap = (sre_capture_t *) p; + + cap->ovecsize = ovecsize; + cap->ref = 1; + cap->next = NULL; + cap->regex_id = 0; + + p += sizeof(sre_capture_t); + cap->vector = (sre_int_t *) p; + } + + if (clear) { + (void) memset(cap->vector, -1, ovecsize); + } + + return cap; +} + + +SRE_NOAPI sre_capture_t * +sre_capture_update(sre_pool_t *pool, sre_capture_t *cap, sre_uint_t group, + sre_int_t pos, sre_capture_t **freecap) +{ + sre_capture_t *newcap; + + dd("update cap %u to %d", group, pos); + + if (cap->ref > 1) { + newcap = sre_capture_create(pool, cap->ovecsize, 0, freecap); + if (newcap == NULL) { + return NULL; + } + + memcpy(newcap->vector, cap->vector, cap->ovecsize); + + cap->ref--; + + dd("!! cap %p: set group %u to %d", newcap, group, pos); + newcap->vector[group] = pos; + return newcap; + } + + dd("!! cap %p: set group %u to %d", cap, group, pos); + cap->vector[group] = pos; + return cap; +} + + +SRE_NOAPI void +sre_capture_dump(sre_capture_t *cap) +{ + sre_uint_t i, n; + + n = cap->ovecsize / sizeof(sre_int_t); + + for (i = 0; i < n; i += 2) { + fprintf(stderr, " (%lld, %lld)", (long long) cap->vector[i], + (long long) cap->vector[i + 1]); + } +} diff --git a/lib/sregex/src/sregex/sre_capture.h b/lib/sregex/src/sregex/sre_capture.h new file mode 100644 index 0000000..a0bd8df --- /dev/null +++ b/lib/sregex/src/sregex/sre_capture.h @@ -0,0 +1,46 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef _SRE_CAPTURE_H_INCLUDED_ +#define _SRE_CAPTURE_H_INCLUDED_ + + +#include +#include + + +#define sre_capture_decr_ref(ctx, cap) \ + if (--(cap)->ref == 0) { \ + (cap)->next = (ctx)->free_capture; \ + (ctx)->free_capture = (cap); \ + } + + +typedef struct sre_capture_s sre_capture_t; + +struct sre_capture_s { + unsigned ref; /* reference count */ + size_t ovecsize; + sre_int_t regex_id; + sre_int_t *vector; + sre_capture_t *next; +}; + + +SRE_NOAPI sre_capture_t *sre_capture_create(sre_pool_t *pool, size_t ovecsize, + unsigned clear, sre_capture_t **freecap); + +SRE_NOAPI sre_capture_t *sre_capture_update(sre_pool_t *pool, + sre_capture_t *cap, sre_uint_t group, sre_int_t pos, + sre_capture_t **freecap); + +SRE_NOAPI void sre_capture_dump(sre_capture_t *cap); + + +#endif /* _SRE_CAPTURE_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_core.h b/lib/sregex/src/sregex/sre_core.h new file mode 100644 index 0000000..110c616 --- /dev/null +++ b/lib/sregex/src/sregex/sre_core.h @@ -0,0 +1,68 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _SRE_CORE_H_INCLUDED_ +#define _SRE_CORE_H_INCLUDED_ + + +#include +#include +#include + + +#ifndef SRE_USE_VALGRIND +#define SRE_USE_VALGRIND 0 +#endif + + +#define SRE_UNSET_PTR (void *) -1 + + +#define sre_memzero(buf, n) (void) memset(buf, 0, n) +#define sre_nelems(a) (sizeof(a)/sizeof((a)[0])) + +#define sre_min(a, b) ((a) <= (b) ? (a) : (b)) +#define sre_max(a, b) ((a) >= (b) ? (a) : (b)) + +#define sre_isword(c) \ + (((c) >= '0' && (c) <= '9') \ + || ((c) >= 'A' && (c) <= 'Z') \ + || ((c) >= 'a' && (c) <= 'z') \ + || (c) == '_') + + +#define SRE_ARCH_UNKNOWN 0 +#define SRE_ARCH_X86 1 +#define SRE_ARCH_X64 2 + + +#ifndef SRE_TARGET + +#if defined(__i386) || defined(__i386__) || defined(_M_IX86) +# define SRE_TARGET SRE_ARCH_X86 +#elif defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) \ + || defined(_M_AMD64) +# define SRE_TARGET SRE_ARCH_X64 +#else +# define SRE_TARGET SRE_ARCH_UNKNOWN +#endif + +#endif /* SRE_TARGET */ + + +#if 0 +# undef SRE_TARGET +# define SRE_TARGET 0 +#endif + + +#ifndef sre_assert +#define sre_assert assert +#endif + + +#endif /* _SRE_CORE_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_palloc.c b/lib/sregex/src/sregex/sre_palloc.c new file mode 100644 index 0000000..dde25db --- /dev/null +++ b/lib/sregex/src/sregex/sre_palloc.c @@ -0,0 +1,389 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include + + +#if !(SRE_USE_VALGRIND) +static void *sre_palloc_block(sre_pool_t *pool, size_t size); +#endif +static void *sre_palloc_large(sre_pool_t *pool, size_t size); +#if !(SRE_USE_VALGRIND) +static void * sre_memalign(size_t alignment, size_t size); +#endif + + +SRE_API sre_pool_t * +sre_create_pool(size_t size) +{ + sre_pool_t *p; + +#if (SRE_USE_VALGRIND) + size = sizeof(sre_pool_t); + p = malloc(size); +#else + p = sre_memalign(SRE_POOL_ALIGNMENT, size); +#endif + if (p == NULL) { + return NULL; + } + +#if !(SRE_USE_VALGRIND) + p->d.last = (uint8_t *) p + sizeof(sre_pool_t); + p->d.end = (uint8_t *) p + size; + p->d.next = NULL; + p->d.failed = 0; + + size = size - sizeof(sre_pool_t); + p->max = (size < SRE_MAX_ALLOC_FROM_POOL) ? size : SRE_MAX_ALLOC_FROM_POOL; + + p->current = p; +#endif + + p->large = NULL; + p->cleanup = NULL; + + return p; +} + + +SRE_API void +sre_destroy_pool(sre_pool_t *pool) +{ +#if !(SRE_USE_VALGRIND) + sre_pool_t *p, *n; +#else + sre_pool_large_t *n; +#endif + sre_pool_large_t *l; + sre_pool_cleanup_t *c; + + for (c = pool->cleanup; c; c = c->next) { + if (c->handler) { + c->handler(c->data); + } + } + +#if (SRE_USE_VALGRIND) + if (pool->large == NULL) { + free(pool); + return; + } +#endif + +#if (SRE_USE_VALGRIND) + for (l = pool->large; l; l = n) { + if (l->alloc) { + free(l->alloc); + n = l->next; + free(l); + + } else { + n = l->next; + } + } +#else + for (l = pool->large; l; l = l->next) { + if (l->alloc) { + free(l->alloc); + } + } +#endif + +#if !(SRE_USE_VALGRIND) + for (p = pool, n = pool->d.next; /* void */; p = n, n = n->d.next) { + free(p); + + if (n == NULL) { + break; + } + } +#else + pool->large = NULL; + free(pool); +#endif +} + + +SRE_API void +sre_reset_pool(sre_pool_t *pool) +{ +#if !(SRE_USE_VALGRIND) + sre_pool_t *p; +#else + sre_pool_large_t *next = NULL; +#endif + sre_pool_large_t *l; + + for (l = pool->large; l; l = l->next) { + if (l->alloc) { + free(l->alloc); + } + } + +#if (SRE_USE_VALGRIND) + for (l = pool->large; l; l = next) { + next = l->next; + free(l); + } +#endif + + pool->large = NULL; + +#if !(SRE_USE_VALGRIND) + for (p = pool; p; p = p->d.next) { + p->d.last = (uint8_t *) p + sizeof(sre_pool_t); + } +#endif +} + + +void * +sre_palloc(sre_pool_t *pool, size_t size) +{ +#if !(SRE_USE_VALGRIND) + uint8_t *m; + sre_pool_t *p; + + if (size <= pool->max) { + + p = pool->current; + + do { + m = sre_align_ptr(p->d.last, SRE_ALIGNMENT); + + if ((size_t) (p->d.end - m) >= size) { + p->d.last = m + size; + + return m; + } + + p = p->d.next; + + } while (p); + + return sre_palloc_block(pool, size); + } +#endif + + return sre_palloc_large(pool, size); +} + + +void * +sre_pnalloc(sre_pool_t *pool, size_t size) +{ +#if !(SRE_USE_VALGRIND) + uint8_t *m; + sre_pool_t *p; + + if (size <= pool->max) { + + p = pool->current; + + do { + m = p->d.last; + + if ((size_t) (p->d.end - m) >= size) { + p->d.last = m + size; + + return m; + } + + p = p->d.next; + + } while (p); + + return sre_palloc_block(pool, size); + } +#endif + + return sre_palloc_large(pool, size); +} + + +#if !(SRE_USE_VALGRIND) +static void * +sre_palloc_block(sre_pool_t *pool, size_t size) +{ + uint8_t *m; + size_t psize; + sre_pool_t *p, *new, *current; + + psize = (size_t) (pool->d.end - (uint8_t *) pool); + + m = sre_memalign(SRE_POOL_ALIGNMENT, psize); + if (m == NULL) { + return NULL; + } + + new = (sre_pool_t *) m; + + new->d.end = m + psize; + new->d.next = NULL; + new->d.failed = 0; + + m += sizeof(sre_pool_data_t); + m = sre_align_ptr(m, SRE_ALIGNMENT); + new->d.last = m + size; + + current = pool->current; + + for (p = current; p->d.next; p = p->d.next) { + if (p->d.failed++ > 4) { + current = p->d.next; + } + } + + p->d.next = new; + + pool->current = current ? current : new; + + return m; +} +#endif + + +static void * +sre_palloc_large(sre_pool_t *pool, size_t size) +{ + void *p; + sre_uint_t n; + sre_pool_large_t *large; + + p = malloc(size); + if (p == NULL) { + return NULL; + } + + n = 0; + + for (large = pool->large; large; large = large->next) { + if (large->alloc == NULL) { + large->alloc = p; + return p; + } + + if (n++ > 3) { + break; + } + } + +#if (SRE_USE_VALGRIND) + large = malloc(sizeof(sre_pool_large_t)); +#else + large = sre_palloc(pool, sizeof(sre_pool_large_t)); +#endif + if (large == NULL) { + free(p); + return NULL; + } + + large->alloc = p; + large->next = pool->large; + pool->large = large; + + return p; +} + + +int +sre_pfree(sre_pool_t *pool, void *p) +{ + sre_pool_large_t *l; +#if (SRE_USE_VALGRIND) + sre_pool_large_t **next; + + next = &pool->large; +#endif + + for (l = pool->large; l; l = l->next) { + if (p == l->alloc) { + free(l->alloc); + l->alloc = NULL; + +#if (SRE_USE_VALGRIND) + *next = l->next; + free(l); +#endif + return SRE_OK; + } + +#if (SRE_USE_VALGRIND) + next = &l->next; +#endif + } + + return SRE_DECLINED; +} + + +void * +sre_pcalloc(sre_pool_t *pool, size_t size) +{ + void *p; + + p = sre_palloc(pool, size); + if (p != NULL) { + sre_memzero(p, size); + } + + return p; +} + + +sre_pool_cleanup_t * +sre_pool_cleanup_add(sre_pool_t *p, size_t size) +{ + sre_pool_cleanup_t *c; + + c = sre_palloc(p, sizeof(sre_pool_cleanup_t)); + if (c == NULL) { + return NULL; + } + + if (size) { + c->data = sre_palloc(p, size); + if (c->data == NULL) { + return NULL; + } + + } else { + c->data = NULL; + } + + c->handler = NULL; + c->next = p->cleanup; + + p->cleanup = c; + + return c; +} + + +#if !(SRE_USE_VALGRIND) +static void * +sre_memalign(size_t alignment, size_t size) +{ + void *p; + int err; + + err = posix_memalign(&p, alignment, size); + + if (err) { + p = NULL; + } + + return p; +} +#endif diff --git a/lib/sregex/src/sregex/sre_palloc.h b/lib/sregex/src/sregex/sre_palloc.h new file mode 100644 index 0000000..4b935c4 --- /dev/null +++ b/lib/sregex/src/sregex/sre_palloc.h @@ -0,0 +1,88 @@ + +/* + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef _SRE_PALLOC_H_INCLUDED_ +#define _SRE_PALLOC_H_INCLUDED_ + + +#include +#include + + +#define sre_pagesize 4096 + +#define sre_align(d, a) (((d) + (a - 1)) & ~(a - 1)) + + +#define SRE_MAX_ALLOC_FROM_POOL (sre_pagesize - 1) + +#define SRE_DEFAULT_POOL_SIZE (16 * 1024) + +#define SRE_POOL_ALIGNMENT 16 +#define SRE_MIN_POOL_SIZE \ + sre_align((sizeof(sre_pool_t) + 2 * sizeof(sre_pool_large_t)), \ + SRE_POOL_ALIGNMENT) + + +#ifndef SRE_ALIGNMENT +#define SRE_ALIGNMENT sizeof(unsigned long) /* platform word */ +#endif + +#define ngx_align(d, a) (((d) + (a - 1)) & ~(a - 1)) +#define sre_align_ptr(p, a) \ + (uint8_t *) (((uintptr_t) (p) + ((uintptr_t) a - 1)) & ~((uintptr_t) a - 1)) + + +typedef void (*sre_pool_cleanup_pt)(void *data); + +typedef struct sre_pool_cleanup_s sre_pool_cleanup_t; + +struct sre_pool_cleanup_s { + sre_pool_cleanup_pt handler; + void *data; + sre_pool_cleanup_t *next; +}; + + +typedef struct sre_pool_large_s sre_pool_large_t; + +struct sre_pool_large_s { + sre_pool_large_t *next; + void *alloc; +}; + + +#if !(SRE_USE_VALGRIND) +typedef struct { + sre_char *last; + sre_char *end; + sre_pool_t *next; + unsigned failed; +} sre_pool_data_t; +#endif + + +struct sre_pool_s { +#if !(SRE_USE_VALGRIND) + sre_pool_data_t d; + size_t max; + sre_pool_t *current; +#endif + sre_pool_large_t *large; + sre_pool_cleanup_t *cleanup; +}; + + +SRE_NOAPI void *sre_palloc(sre_pool_t *pool, size_t size); +SRE_NOAPI void *sre_pnalloc(sre_pool_t *pool, size_t size); +SRE_NOAPI void *sre_pcalloc(sre_pool_t *pool, size_t size); +SRE_NOAPI int sre_pfree(sre_pool_t *pool, void *p); + +SRE_NOAPI sre_pool_cleanup_t *sre_pool_cleanup_add(sre_pool_t *p, size_t size); + + +#endif /* _SRE_PALLOC_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_regex.c b/lib/sregex/src/sregex/sre_regex.c new file mode 100644 index 0000000..7a1eda9 --- /dev/null +++ b/lib/sregex/src/sregex/sre_regex.c @@ -0,0 +1,214 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#include +#include + + +SRE_NOAPI sre_regex_t * +sre_regex_create(sre_pool_t *pool, sre_regex_type_t type, sre_regex_t *left, + sre_regex_t *right) +{ + sre_regex_t *r; + + r = sre_pcalloc(pool, sizeof(sre_regex_t)); + if (r == NULL) { + return NULL; + } + + r->type = type; + r->left = left; + r->right = right; + + return r; +} + + +SRE_API void +sre_regex_dump(sre_regex_t *r) +{ + sre_regex_range_t *range; + + switch (r->type) { + case SRE_REGEX_TYPE_ALT: + printf("Alt("); + sre_regex_dump(r->left); + printf(", "); + sre_regex_dump(r->right); + printf(")"); + break; + + case SRE_REGEX_TYPE_CAT: + printf("Cat("); + sre_regex_dump(r->left); + printf(", "); + sre_regex_dump(r->right); + printf(")"); + break; + + case SRE_REGEX_TYPE_LIT: + printf("Lit(%d)", (int) r->data.ch); + break; + + case SRE_REGEX_TYPE_DOT: + printf("Dot"); + break; + + case SRE_REGEX_TYPE_PAREN: + printf("Paren(%lu, ", (unsigned long) r->data.group); + sre_regex_dump(r->left); + printf(")"); + break; + + case SRE_REGEX_TYPE_STAR: + if (!r->data.greedy) { + printf("Ng"); + } + + printf("Star("); + sre_regex_dump(r->left); + printf(")"); + break; + + case SRE_REGEX_TYPE_PLUS: + if (!r->data.greedy) { + printf("Ng"); + } + + printf("Plus("); + sre_regex_dump(r->left); + printf(")"); + break; + + case SRE_REGEX_TYPE_QUEST: + if (!r->data.greedy) { + printf("Ng"); + } + + printf("Quest("); + sre_regex_dump(r->left); + printf(")"); + break; + + case SRE_REGEX_TYPE_NIL: + printf("Nil"); + break; + + case SRE_REGEX_TYPE_CLASS: + printf("CLASS("); + + for (range = r->data.range; range; range = range->next) { + printf("[%d, %d]", range->from, range->to); + } + + printf(")"); + break; + + case SRE_REGEX_TYPE_NCLASS: + printf("NCLASS("); + + for (range = r->data.range; range; range = range->next) { + printf("[%d, %d]", range->from, range->to); + } + + printf(")"); + break; + + case SRE_REGEX_TYPE_ASSERT: + printf("ASSERT("); + switch (r->data.assertion) { + case SRE_REGEX_ASSERT_BIG_A: + printf("\\A"); + break; + + case SRE_REGEX_ASSERT_CARET: + printf("^"); + break; + + case SRE_REGEX_ASSERT_DOLLAR: + printf("$"); + break; + + case SRE_REGEX_ASSERT_SMALL_Z: + printf("\\z"); + break; + + case SRE_REGEX_ASSERT_BIG_B: + printf("\\B"); + break; + + case SRE_REGEX_ASSERT_SMALL_B: + printf("\\b"); + break; + + default: + printf("???"); + break; + } + printf(")"); + break; + + case SRE_REGEX_TYPE_TOPLEVEL: + printf("TOPLEVEL(%lu, ", (unsigned long) r->data.regex_id); + sre_regex_dump(r->left); + printf(")"); + break; + + default: + printf("???"); + break; + } +} + + +SRE_NOAPI sre_regex_range_t * +sre_regex_turn_char_class_caseless(sre_pool_t *pool, sre_regex_range_t *range) +{ + sre_char from, to; + sre_regex_range_t *r, *nr; + + for (r = range; r; r = r->next) { + from = r->from; + to = r->to; + + if (to >= 'A' && from <= 'Z') { + /* overlap with A-Z */ + + nr = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (nr == NULL) { + return NULL; + } + + nr->from = sre_max(from, 'A') + 32; + nr->to = sre_min(to, 'Z') + 32; + nr->next = r->next; + + r->next = nr; + r = nr; + } + + if (to >= 'a' && from <= 'z') { + /* overlap with a-z */ + + nr = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (nr == NULL) { + return NULL; + } + + nr->from = sre_max(from, 'a') - 32; + nr->to = sre_min(to, 'z') - 32; + nr->next = r->next; + + r->next = nr; + r = nr; + } + } + + return range; +} diff --git a/lib/sregex/src/sregex/sre_regex.h b/lib/sregex/src/sregex/sre_regex.h new file mode 100644 index 0000000..44393cc --- /dev/null +++ b/lib/sregex/src/sregex/sre_regex.h @@ -0,0 +1,101 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef _SRE_REGEX_H_INCLUDED_ +#define _SRE_REGEX_H_INCLUDED_ + + +#include +#include + + +typedef enum { + SRE_REGEX_TYPE_NIL = 0, + SRE_REGEX_TYPE_ALT = 1, + SRE_REGEX_TYPE_CAT = 2, + SRE_REGEX_TYPE_LIT = 3, + SRE_REGEX_TYPE_DOT = 4, + SRE_REGEX_TYPE_PAREN = 5, + SRE_REGEX_TYPE_QUEST = 6, + SRE_REGEX_TYPE_STAR = 7, + SRE_REGEX_TYPE_PLUS = 8, + SRE_REGEX_TYPE_CLASS = 9, + SRE_REGEX_TYPE_NCLASS = 10, + SRE_REGEX_TYPE_ASSERT = 11, + SRE_REGEX_TYPE_TOPLEVEL = 12 +} sre_regex_type_t; + + +typedef enum { + SRE_REGEX_ASSERT_SMALL_Z = 0x01, + SRE_REGEX_ASSERT_DOLLAR = 0x02, + SRE_REGEX_ASSERT_BIG_B = 0x04, + SRE_REGEX_ASSERT_SMALL_B = 0x08, + SRE_REGEX_ASSERT_BIG_A = 0x10, + SRE_REGEX_ASSERT_CARET = 0x20 +} sre_regex_assertion_type_t; + + +enum { + SRE_REGEX_ASSERT_LOOKAHEAD = SRE_REGEX_ASSERT_SMALL_Z + | SRE_REGEX_ASSERT_DOLLAR + | SRE_REGEX_ASSERT_BIG_B + | SRE_REGEX_ASSERT_SMALL_B, + + SRE_REGEX_ASSERT_WORD_BOUNDARY = SRE_REGEX_ASSERT_SMALL_B + | SRE_REGEX_ASSERT_BIG_B +}; + + +typedef struct sre_regex_range_s sre_regex_range_t; + +struct sre_regex_range_s { + sre_char from; + sre_char to; + sre_regex_range_t *next; +}; + + +/* counted quantifier */ + +typedef struct { + int from; + int to; +} sre_regex_cquant_t; + + +struct sre_regex_s { + sre_regex_type_t type; + + sre_regex_t *left; + sre_regex_t *right; + + sre_uint_t nregexes; + + union { + sre_char ch; + sre_regex_range_t *range; + sre_uint_t *multi_ncaps; + sre_uint_t group; + sre_uint_t assertion; + sre_uint_t greedy; + sre_int_t regex_id; + } data; +}; + + +SRE_NOAPI sre_regex_t *sre_regex_create(sre_pool_t *pool, sre_regex_type_t type, + sre_regex_t *left, sre_regex_t *right); + +SRE_NOAPI sre_regex_range_t * + sre_regex_turn_char_class_caseless(sre_pool_t *pool, + sre_regex_range_t *range); + + +#endif /* _SRE_REGEX_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_regex_compiler.c b/lib/sregex/src/sregex/sre_regex_compiler.c new file mode 100644 index 0000000..111aafc --- /dev/null +++ b/lib/sregex/src/sregex/sre_regex_compiler.c @@ -0,0 +1,517 @@ + +/* + * Copyright 2012-2013 Yichun Zhang (agentzh) + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include + + +static sre_int_t sre_program_get_leading_bytes(sre_pool_t *pool, + sre_program_t *prog, sre_chain_t **res); +static sre_int_t sre_program_get_leading_bytes_helper(sre_pool_t *pool, + sre_instruction_t *pc, sre_program_t *prog, sre_chain_t **res, + unsigned tag); +static sre_uint_t sre_program_len(sre_regex_t *r); +static sre_instruction_t *sre_regex_emit_bytecode(sre_pool_t *pool, + sre_instruction_t *pc, sre_regex_t *re); +static sre_int_t sre_regex_compiler_add_char_class(sre_pool_t *pool, + sre_instruction_t *pc, sre_regex_range_t *range); + + +sre_program_t * +sre_regex_compile(sre_pool_t *pool, sre_regex_t *re) +{ + sre_uint_t i, n, multi_ncaps_size; + sre_char *p; + sre_program_t *prog; + sre_instruction_t *pc; + + n = sre_program_len(re); + + multi_ncaps_size = (re->nregexes - 1) * sizeof(sre_uint_t); + + p = sre_pnalloc(pool, + sizeof(sre_program_t) + multi_ncaps_size + + n * sizeof(sre_instruction_t)); + + if (p == NULL) { + return NULL; + } + + prog = (sre_program_t *) p; + + prog->nregexes = re->nregexes; + + memcpy(prog->multi_ncaps, re->data.multi_ncaps, + re->nregexes * sizeof(sre_uint_t)); + + prog->start = (sre_instruction_t *) (p + sizeof(sre_program_t) + + multi_ncaps_size); + + sre_memzero(prog->start, n * sizeof(sre_instruction_t)); + + pc = sre_regex_emit_bytecode(pool, prog->start, re); + if (pc == NULL) { + return NULL; + } + + if (pc - prog->start != n) { + dd("buffer error: %d != %d", (int) (pc - prog->start), (int) n); + return NULL; + } + + prog->len = pc - prog->start; + prog->tag = 0; + prog->lookahead_asserts = 0; + prog->dup_threads = 0; + prog->uniq_threads = 0; + prog->nullable = 0; + prog->leading_bytes = NULL; + prog->leading_byte = -1; + + prog->ovecsize = 0; + for (i = 0; i < prog->nregexes; i++) { + prog->ovecsize += prog->multi_ncaps[i] + 1; + } + prog->ovecsize *= 2 * sizeof(sre_uint_t); + + if (sre_program_get_leading_bytes(pool, prog, &prog->leading_bytes) + == SRE_ERROR) + { + return NULL; + } + + if (prog->leading_bytes && prog->leading_bytes->next == NULL) { + pc = prog->leading_bytes->data; + if (pc->opcode == SRE_OPCODE_CHAR) { + prog->leading_byte = pc->v.ch; + } + } + + dd("nullable: %u", prog->nullable); + +#if (DDEBUG) + { + sre_chain_t *cl; + + for (cl = prog->leading_bytes; cl; cl = cl->next) { + pc = cl->data; + fprintf(stderr, "["); + sre_dump_instruction(stderr, pc, prog->start); + fprintf(stderr, "]"); + } + if (prog->leading_bytes) { + fprintf(stderr, "\n"); + } + } +#endif + + return prog; +} + + +static sre_int_t +sre_program_get_leading_bytes(sre_pool_t *pool, sre_program_t *prog, + sre_chain_t **res) +{ + unsigned tag; + sre_int_t rc; + + tag = prog->tag + 1; + + rc = sre_program_get_leading_bytes_helper(pool, prog->start, prog, res, + tag); + prog->tag = tag; + + if (rc == SRE_ERROR) { + return SRE_ERROR; + } + + if (rc == SRE_DECLINED || prog->nullable) { + *res = NULL; + return SRE_DECLINED; + } + + return rc; +} + + +static sre_int_t +sre_program_get_leading_bytes_helper(sre_pool_t *pool, sre_instruction_t *pc, + sre_program_t *prog, sre_chain_t **res, unsigned tag) +{ + sre_int_t rc; + sre_chain_t *cl, *ncl; + sre_instruction_t *bc; + + if (pc->tag == tag) { + return SRE_OK; + } + + if (pc == prog->start + 1) { + /* skip the dot (.) in the initial boilerplate ".*?" */ + return SRE_OK; + } + + pc->tag = tag; + + switch (pc->opcode) { + case SRE_OPCODE_SPLIT: + rc = sre_program_get_leading_bytes_helper(pool, pc->x, prog, res, + tag); + if (rc != SRE_OK) { + return rc; + } + + return sre_program_get_leading_bytes_helper(pool, pc->y, prog, res, + tag); + + case SRE_OPCODE_JMP: + return sre_program_get_leading_bytes_helper(pool, pc->x, prog, res, + tag); + + case SRE_OPCODE_SAVE: + if (++pc == prog->start + prog->len) { + return SRE_OK; + } + + return sre_program_get_leading_bytes_helper(pool, pc, prog, res, + tag); + + case SRE_OPCODE_MATCH: + prog->nullable = 1; + return SRE_DONE; + + case SRE_OPCODE_ASSERT: + if (++pc == prog->start + prog->len) { + return SRE_OK; + } + + return sre_program_get_leading_bytes_helper(pool, pc, prog, res, tag); + + case SRE_OPCODE_ANY: + return SRE_DECLINED; + + default: + /* CHAR, ANY, IN, NOTIN */ + + ncl = sre_palloc(pool, sizeof(sre_chain_t)); + if (ncl == NULL) { + return SRE_ERROR; + } + + ncl->data = pc; + ncl->next = NULL; + + if (*res) { + for (cl = *res; /* void */; cl = cl->next) { + bc = cl->data; + if (bc->opcode == pc->opcode) { + if (bc->opcode == SRE_OPCODE_CHAR) { + if (bc->v.ch == pc->v.ch) { + return SRE_OK; + } + } + } + + if (cl->next == NULL) { + cl->next = ncl; + return SRE_OK; + } + } + + } else { + *res = ncl; + } + + return SRE_OK; + } + + /* impossible to reach here */ +} + + +static sre_uint_t +sre_program_len(sre_regex_t *r) +{ + dd("program len on node: %d", (int) r->type); + + switch(r->type) { + case SRE_REGEX_TYPE_ALT: + return 2 + sre_program_len(r->left) + sre_program_len(r->right); + + case SRE_REGEX_TYPE_CAT: + return sre_program_len(r->left) + sre_program_len(r->right); + + case SRE_REGEX_TYPE_LIT: + case SRE_REGEX_TYPE_DOT: + case SRE_REGEX_TYPE_CLASS: + case SRE_REGEX_TYPE_NCLASS: + return 1; + + case SRE_REGEX_TYPE_PAREN: + return 2 + sre_program_len(r->left); + + case SRE_REGEX_TYPE_QUEST: + return 1 + sre_program_len(r->left); + + case SRE_REGEX_TYPE_STAR: + return 2 + sre_program_len(r->left); + + case SRE_REGEX_TYPE_PLUS: + return 1 + sre_program_len(r->left); + + case SRE_REGEX_TYPE_ASSERT: + return 1; + + case SRE_REGEX_TYPE_TOPLEVEL: + return 1 + sre_program_len(r->left); + + case SRE_REGEX_TYPE_NIL: + default: + /* impossible to reach here */ + return 0; + } +} + + +static sre_instruction_t * +sre_regex_emit_bytecode(sre_pool_t *pool, sre_instruction_t *pc, sre_regex_t *r) +{ + sre_instruction_t *p1, *p2, *t; + + dd("program emit bytecode on node: %d", (int) r->type); + + switch(r->type) { + case SRE_REGEX_TYPE_ALT: + pc->opcode = SRE_OPCODE_SPLIT; + p1 = pc++; + p1->x = pc; + + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + pc->opcode = SRE_OPCODE_JMP; + p2 = pc++; + p1->y = pc; + + pc = sre_regex_emit_bytecode(pool, pc, r->right); + if (pc == NULL) { + return NULL; + } + + p2->x = pc; + + break; + + case SRE_REGEX_TYPE_CAT: + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + pc = sre_regex_emit_bytecode(pool, pc, r->right); + if (pc == NULL) { + return NULL; + } + + break; + + case SRE_REGEX_TYPE_LIT: + pc->opcode = SRE_OPCODE_CHAR; + pc->v.ch = r->data.ch; + pc++; + break; + + case SRE_REGEX_TYPE_CLASS: + pc->opcode = SRE_OPCODE_IN; + + if (sre_regex_compiler_add_char_class(pool, pc, r->data.range) + != SRE_OK) + { + return NULL; + } + + pc++; + break; + + case SRE_REGEX_TYPE_NCLASS: + pc->opcode = SRE_OPCODE_NOTIN; + + if (sre_regex_compiler_add_char_class(pool, pc, r->data.range) + != SRE_OK) + { + return NULL; + } + + pc++; + break; + + case SRE_REGEX_TYPE_DOT: + pc->opcode = SRE_OPCODE_ANY; + pc++; + break; + + case SRE_REGEX_TYPE_PAREN: + pc->opcode = SRE_OPCODE_SAVE; + pc->v.group = 2 * r->data.group; + pc++; + + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + pc->opcode = SRE_OPCODE_SAVE; + + pc->v.group = 2 * r->data.group + 1; + pc++; + + break; + + case SRE_REGEX_TYPE_QUEST: + pc->opcode = SRE_OPCODE_SPLIT; + p1 = pc++; + p1->x = pc; + + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + p1->y = pc; + + if (!r->data.greedy) { /* non-greedy */ + t = p1->x; + p1->x = p1->y; + p1->y = t; + } + + break; + + case SRE_REGEX_TYPE_STAR: + pc->opcode = SRE_OPCODE_SPLIT; + p1 = pc++; + p1->x = pc; + + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + pc->opcode = SRE_OPCODE_JMP; + pc->x = p1; + pc++; + + p1->y = pc; + + if (!r->data.greedy) { /* non-greedy */ + t = p1->x; + p1->x = p1->y; + p1->y = t; + } + + break; + + case SRE_REGEX_TYPE_PLUS: + p1 = pc; + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + pc->opcode = SRE_OPCODE_SPLIT; + pc->x = p1; + p2 = pc; + + pc++; + p2->y = pc; + + if (!r->data.greedy) { /* non-greedy */ + t = p2->x; + p2->x = p2->y; + p2->y = t; + } + + break; + + case SRE_REGEX_TYPE_ASSERT: + pc->opcode = SRE_OPCODE_ASSERT; + pc->v.assertion = r->data.assertion; + pc++; + + break; + + case SRE_REGEX_TYPE_TOPLEVEL: + pc = sre_regex_emit_bytecode(pool, pc, r->left); + if (pc == NULL) { + return NULL; + } + + pc->opcode = SRE_OPCODE_MATCH; + + dd("setting regex id %ld", (long) r->data.regex_id); + + pc->v.regex_id = r->data.regex_id; + pc++; + + break; + + case SRE_REGEX_TYPE_NIL: + /* do nothing */ + break; + + default: + /* impossible to reach here */ + break; + } + + return pc; +} + + +static sre_int_t +sre_regex_compiler_add_char_class(sre_pool_t *pool, sre_instruction_t *pc, + sre_regex_range_t *range) +{ + sre_char *p; + sre_uint_t i, n; + sre_regex_range_t *r; + + n = 0; + for (r = range; r; r = r->next) { + n++; + } + + p = sre_pnalloc(pool, + sizeof(sre_vm_ranges_t) + n * sizeof(sre_vm_range_t)); + if (p == NULL) { + return SRE_ERROR; + } + + pc->v.ranges = (sre_vm_ranges_t *) p; + + p += sizeof(sre_vm_ranges_t); + pc->v.ranges->head = (sre_vm_range_t *) p; + + pc->v.ranges->count = n; + + for (i = 0, r = range; r; i++, r = r->next) { + pc->v.ranges->head[i].from = r->from; + pc->v.ranges->head[i].to = r->to; + } + + return SRE_OK; +} diff --git a/lib/sregex/src/sregex/sre_vm_bytecode.c b/lib/sregex/src/sregex/sre_vm_bytecode.c new file mode 100644 index 0000000..452e87e --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_bytecode.c @@ -0,0 +1,128 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#include +#include + + +SRE_API void +sre_program_dump(sre_program_t *prog) +{ + sre_instruction_t *pc, *start, *end; + + start = prog->start; + end = prog->start + prog->len; + + for (pc = start; pc < end; pc++) { + sre_dump_instruction(stdout, pc, start); + printf("\n"); + } +} + + +void +sre_dump_instruction(FILE *f, sre_instruction_t *pc, + sre_instruction_t *start) +{ + sre_uint_t i; + sre_vm_range_t *range; + + switch (pc->opcode) { + case SRE_OPCODE_SPLIT: + fprintf(f, "%2d. split %d, %d", (int) (pc - start), + (int) (pc->x - start), (int) (pc->y - start)); + break; + + case SRE_OPCODE_JMP: + fprintf(f, "%2d. jmp %d", (int) (pc - start), (int) (pc->x - start)); + break; + + case SRE_OPCODE_CHAR: + fprintf(f, "%2d. char %d", (int) (pc - start), (int) pc->v.ch); + break; + + case SRE_OPCODE_IN: + fprintf(f, "%2d. in", (int) (pc - start)); + + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + if (i > 0) { + fputc(',', f); + } + fprintf(f, " %d-%d", range->from, range->to); + } + + break; + + case SRE_OPCODE_NOTIN: + fprintf(f, "%2d. notin", (int) (pc - start)); + + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + if (i > 0) { + fputc(',', f); + } + fprintf(f, " %d-%d", range->from, range->to); + } + + break; + + case SRE_OPCODE_ANY: + fprintf(f, "%2d. any", (int) (pc - start)); + break; + + case SRE_OPCODE_MATCH: + fprintf(f, "%2d. match %d", (int) (pc - start), (int) pc->v.regex_id); + break; + + case SRE_OPCODE_SAVE: + fprintf(f, "%2d. save %d", (int) (pc - start), + (int) pc->v.group); + break; + + case SRE_OPCODE_ASSERT: + fprintf(f, "%2d. assert ", (int) (pc - start)); + + switch (pc->v.assertion) { + case SRE_REGEX_ASSERT_BIG_A: + fprintf(f, "\\A"); + break; + + case SRE_REGEX_ASSERT_CARET: + fprintf(f, "^"); + break; + + case SRE_REGEX_ASSERT_SMALL_Z: + fprintf(f, "\\z"); + break; + + case SRE_REGEX_ASSERT_BIG_B: + fprintf(f, "\\B"); + break; + + case SRE_REGEX_ASSERT_SMALL_B: + fprintf(f, "\\b"); + break; + + case SRE_REGEX_ASSERT_DOLLAR: + fprintf(f, "$"); + break; + + default: + fprintf(f, "?"); + break; + } + + break; + + default: + fprintf(f, "%2d. unknown", (int) (pc - start)); + break; + } +} diff --git a/lib/sregex/src/sregex/sre_vm_bytecode.h b/lib/sregex/src/sregex/sre_vm_bytecode.h new file mode 100644 index 0000000..544f274 --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_bytecode.h @@ -0,0 +1,94 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef _SRE_BYTECODE_H_INCLUDED_ +#define _SRE_BYTECODE_H_INCLUDED_ + + +#include +#include + + +typedef enum { + SRE_OPCODE_CHAR = 1, + SRE_OPCODE_MATCH = 2, + SRE_OPCODE_JMP = 3, + SRE_OPCODE_SPLIT = 4, + SRE_OPCODE_ANY = 5, + SRE_OPCODE_SAVE = 6, + SRE_OPCODE_IN = 7, + SRE_OPCODE_NOTIN = 8, + SRE_OPCODE_ASSERT = 9 +} sre_opcode_t; + + +typedef struct { + sre_char from; + sre_char to; +} sre_vm_range_t; + + +typedef struct { + sre_uint_t count; + sre_vm_range_t *head; +} sre_vm_ranges_t; + + +typedef struct sre_instruction_s sre_instruction_t; + +struct sre_instruction_s { + sre_opcode_t opcode; + + sre_instruction_t *x; + sre_instruction_t *y; + + unsigned tag; + + union { + sre_char ch; + sre_vm_ranges_t *ranges; + sre_uint_t group; /* capture group */ + sre_uint_t greedy; + sre_uint_t assertion; + sre_int_t regex_id; + } v; +}; + + +typedef struct sre_chain_s sre_chain_t; + +struct sre_chain_s { + void *data; + sre_chain_t *next; +}; + + +struct sre_program_s { + sre_instruction_t *start; + sre_uint_t len; + + unsigned tag; + unsigned uniq_threads; /* unique thread count */ + unsigned dup_threads; /* duplicatable thread count */ + unsigned lookahead_asserts; + unsigned nullable; + sre_chain_t *leading_bytes; + int leading_byte; + + sre_uint_t ovecsize; + sre_uint_t nregexes; + sre_uint_t multi_ncaps[1]; +}; + + +void sre_dump_instruction(FILE *f, sre_instruction_t *pc, + sre_instruction_t *start); + + +#endif /* _SRE_BYTECODE_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_vm_pike.c b/lib/sregex/src/sregex/sre_vm_pike.c new file mode 100644 index 0000000..bdb4274 --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_pike.c @@ -0,0 +1,1080 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include + + +#define sre_vm_pike_free_thread(ctx, t) \ + (t)->next = (ctx)->free_threads; \ + (ctx)->free_threads = t; + + +enum { + SRE_VM_PIKE_SEEN_WORD = 1 +}; + + +typedef struct sre_vm_pike_thread_s sre_vm_pike_thread_t; + +struct sre_vm_pike_thread_s { + sre_instruction_t *pc; + sre_capture_t *capture; + sre_vm_pike_thread_t *next; + unsigned seen_word; /* :1 */ +}; + + +typedef struct { + sre_uint_t count; + sre_vm_pike_thread_t *head; + sre_vm_pike_thread_t **next; +} sre_vm_pike_thread_list_t; + + +struct sre_vm_pike_ctx_s { + unsigned tag; + sre_int_t processed_bytes; + sre_char *buffer; + sre_pool_t *pool; + sre_program_t *program; + sre_capture_t *matched; + sre_capture_t *free_capture; + sre_vm_pike_thread_t *free_threads; + + sre_int_t *pending_ovector; + sre_int_t *ovector; + size_t ovecsize; + + sre_vm_pike_thread_list_t *current_threads; + sre_vm_pike_thread_list_t *next_threads; + + sre_int_t last_matched_pos; /* the pos for the last + (partial) match */ + + sre_instruction_t **initial_states; + sre_uint_t initial_states_count; + + unsigned first_buf:1; + unsigned seen_start_state:1; + unsigned eof:1; + unsigned empty_capture:1; + unsigned seen_newline:1; + unsigned seen_word:1; +} ; + + +static sre_vm_pike_thread_list_t * + sre_vm_pike_thread_list_create(sre_pool_t *pool); +static sre_int_t sre_vm_pike_add_thread(sre_vm_pike_ctx_t *ctx, + sre_vm_pike_thread_list_t *l, sre_instruction_t *pc, sre_capture_t *capture, + sre_int_t pos, sre_capture_t **pcap); +static void sre_vm_pike_prepare_temp_captures(sre_program_t *prog, + sre_vm_pike_ctx_t *ctx); +static sre_int_t sre_vm_pike_prepare_matched_captures(sre_vm_pike_ctx_t *ctx, + sre_capture_t *matched, sre_int_t *ovector, sre_int_t complete); +static sre_char *sre_vm_pike_find_first_byte(sre_char *pos, sre_char *last, + int leading_byte, sre_chain_t *leading_bytes); +static void sre_vm_pike_clear_thread_list(sre_vm_pike_ctx_t *ctx, + sre_vm_pike_thread_list_t *list); + + +SRE_API sre_vm_pike_ctx_t * +sre_vm_pike_create_ctx(sre_pool_t *pool, sre_program_t *prog, + sre_int_t *ovector, size_t ovecsize) +{ + sre_vm_pike_ctx_t *ctx; + sre_vm_pike_thread_list_t *clist, *nlist; + + ctx = sre_palloc(pool, sizeof(sre_vm_pike_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ctx->pool = pool; + ctx->program = prog; + ctx->processed_bytes = 0; + ctx->pending_ovector = NULL; + + clist = sre_vm_pike_thread_list_create(pool); + if (clist == NULL) { + return NULL; + } + + ctx->current_threads = clist; + + nlist = sre_vm_pike_thread_list_create(pool); + if (nlist == NULL) { + return NULL; + } + + ctx->next_threads = nlist; + + ctx->program = prog; + ctx->pool = pool; + ctx->free_capture = NULL; + ctx->free_threads = NULL; + ctx->matched = NULL; + + ctx->ovecsize = ovecsize; + ctx->ovector = ovector; + + dd("resetting seen start state"); + ctx->seen_start_state = 0; + ctx->initial_states_count = 0; + ctx->initial_states = NULL; + ctx->first_buf = 1; + ctx->eof = 0; + ctx->empty_capture = 0; + ctx->seen_newline = 0; + ctx->seen_word = 0; + + return ctx; +} + + +SRE_API sre_int_t +sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, size_t size, + unsigned eof, sre_int_t **pending_matched) +{ + sre_char *sp, *last, *p; + sre_int_t rc; + sre_uint_t i; + unsigned seen_word, in; + sre_pool_t *pool; + sre_program_t *prog; + sre_capture_t *cap, *matched; + sre_vm_range_t *range; + sre_instruction_t *pc; + sre_vm_pike_thread_t *t; + sre_vm_pike_thread_list_t *clist, *nlist, *tmp; + sre_vm_pike_thread_list_t list; + + if (ctx->eof) { + dd("eof found"); + return SRE_ERROR; + } + + pool = ctx->pool; + prog = ctx->program; + clist = ctx->current_threads; + nlist = ctx->next_threads; + matched = ctx->matched; + + ctx->buffer = input; + ctx->last_matched_pos = -1; + + if (ctx->empty_capture) { + dd("found empty capture"); + ctx->empty_capture = 0; + + if (size == 0) { + if (eof) { + ctx->eof = 1; + return SRE_DECLINED; + } + + return SRE_AGAIN; + } + + sp = input + 1; + + } else { + sp = input; + } + + last = input + size; + + dd("processing buffer size %d", (int) size); + + if (ctx->first_buf) { + ctx->first_buf = 0; + + cap = sre_capture_create(pool, prog->ovecsize, 1, &ctx->free_capture); + if (cap == NULL) { + return SRE_ERROR; + } + + ctx->tag = prog->tag + 1; + rc = sre_vm_pike_add_thread(ctx, clist, prog->start, cap, + (sre_int_t) (sp - input), NULL); + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + ctx->initial_states_count = clist->count; + ctx->initial_states = sre_palloc(pool, + sizeof(sre_instruction_t *) + * clist->count); + if (ctx->initial_states == NULL) { + return SRE_ERROR; + } + + /* we skip the last thread because it must always be .*? */ + for (i = 0, t = clist->head; t && t->next; i++, t = t->next) { + ctx->initial_states[i] = t->pc; + } + + } else { + ctx->tag = prog->tag; + } + + for (; sp < last || (eof && sp == last); sp++) { + dd("=== pos %d, offset %d (char '%c' (%d)).\n", + (int)(sp - input + ctx->processed_bytes), + (int)(sp - input), + sp < last ? *sp : '?', sp < last ? *sp : 0); + + if (clist->head == NULL) { + dd("clist empty. abort."); + break; + } + +#if (DDEBUG) + fprintf(stderr, "sregex: cur list:"); + for (t = clist->head; t; t = t->next) { + fprintf(stderr, " %d", (int) (t->pc - prog->start)); + } + fprintf(stderr, "\n"); +#endif + + dd("seen start state: %d", (int) ctx->seen_start_state); + + if (prog->leading_bytes && ctx->seen_start_state) { + dd("resetting seen start state"); + ctx->seen_start_state = 0; + + if (sp == last || clist->count != ctx->initial_states_count) { + dd("skip because sp == last or " + "clist->count != initial states count!"); + goto run_cur_threads; + } + + for (i = 0, t = clist->head; t && t->next; i++, t = t->next) { + if (t->pc != ctx->initial_states[i]) { + dd("skip because pc %d unmatched: %d != %d", (int) i, + (int) (t->pc - prog->start), + (int) (ctx->initial_states[i] - prog->start)); + goto run_cur_threads; + } + } + +#if 1 + dd("XXX found initial state to do first byte search!"); + p = sre_vm_pike_find_first_byte(sp, last, prog->leading_byte, + prog->leading_bytes); + + if (p > sp) { + dd("XXX moved sp by %d bytes", (int) (p - sp)); +#if 0 + fprintf(stderr, "XXX moved sp by %d bytes\n", (int) (p - sp)); +#endif + + sp = p; + + sre_vm_pike_clear_thread_list(ctx, clist); + + cap = sre_capture_create(pool, prog->ovecsize, 1, + &ctx->free_capture); + if (cap == NULL) { + return SRE_ERROR; + } + + ctx->tag++; + rc = sre_vm_pike_add_thread(ctx, clist, prog->start, cap, + (sre_int_t) (sp - input), NULL); + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + if (sp == last) { + break; + } + } +#endif + } + +run_cur_threads: + ctx->tag++; + + while (clist->head) { + t = clist->head; + clist->head = t->next; + clist->count--; + + pc = t->pc; + cap = t->capture; + +#if DDEBUG + fprintf(stderr, "--- #%u", ctx->tag); + sre_dump_instruction(stderr, pc, prog->start); + fprintf(stderr, "\n"); +#endif + + switch (pc->opcode) { + case SRE_OPCODE_IN: + if (sp == last) { + sre_capture_decr_ref(ctx, cap); + break; + } + + in = 0; + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + dd("testing %d for [%d, %d] (%u)", *sp, + (int) range->from, (int) range->to, (unsigned) i); + + if (*sp >= range->from && *sp <= range->to) { + in = 1; + break; + } + } + + if (!in) { + sre_capture_decr_ref(ctx, cap); + break; + } + + rc = sre_vm_pike_add_thread(ctx, nlist, pc + 1, cap, + (sre_int_t) (sp - input + 1), &cap); + + if (rc == SRE_DONE) { + goto matched; + } + + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + break; + + case SRE_OPCODE_NOTIN: + if (sp == last) { + sre_capture_decr_ref(ctx, cap); + break; + } + + in = 0; + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + dd("testing %d for [%d, %d] (%u)", *sp, (int) range->from, + (int) range->to, (unsigned) i); + + if (*sp >= range->from && *sp <= range->to) { + in = 1; + break; + } + } + + if (in) { + sre_capture_decr_ref(ctx, cap); + break; + } + + rc = sre_vm_pike_add_thread(ctx, nlist, pc + 1, cap, + (sre_int_t) (sp - input + 1), &cap); + + if (rc == SRE_DONE) { + goto matched; + } + + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + break; + + case SRE_OPCODE_CHAR: + + dd("matching char '%c' (%d) against %d", + sp != last ? *sp : '?', sp != last ? *sp : 0, pc->v.ch); + + if (sp == last || *sp != pc->v.ch) { + sre_capture_decr_ref(ctx, cap); + break; + } + + rc = sre_vm_pike_add_thread(ctx, nlist, pc + 1, cap, + (sre_int_t) (sp - input + 1), &cap); + + if (rc == SRE_DONE) { + goto matched; + } + + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + break; + + case SRE_OPCODE_ANY: + + if (sp == last) { + sre_capture_decr_ref(ctx, cap); + break; + } + + rc = sre_vm_pike_add_thread(ctx, nlist, pc + 1, cap, + (sre_int_t) (sp - input + 1), &cap); + + if (rc == SRE_DONE) { + goto matched; + } + + if (rc != SRE_OK) { + prog->tag = ctx->tag; + return SRE_ERROR; + } + + break; + + case SRE_OPCODE_ASSERT: + switch (pc->v.assertion) { + case SRE_REGEX_ASSERT_SMALL_Z: + if (sp != last) { + break; + } + + goto assertion_hold; + + case SRE_REGEX_ASSERT_DOLLAR: + + if (sp != last && *sp != '\n') { + break; + } + + dd("dollar $ assertion hold: pos=%d", + (int)(sp - input + ctx->processed_bytes)); + + goto assertion_hold; + + case SRE_REGEX_ASSERT_BIG_B: + + seen_word = (t->seen_word + || (sp == input && ctx->seen_word)); + if (seen_word ^ (sp != last && sre_isword(*sp))) { + break; + } + + dd("\\B assertion passed: %u %c", t->seen_word, *sp); + + goto assertion_hold; + + case SRE_REGEX_ASSERT_SMALL_B: + + seen_word = (t->seen_word + || (sp == input && ctx->seen_word)); + if ((seen_word ^ (sp != last && sre_isword(*sp))) == 0) { + break; + } + +#if (DDEBUG) + if (sp) { + dd("\\b assertion passed: t:%u, ctx:%u, %c", + t->seen_word, ctx->seen_word, *sp); + } +#endif + + goto assertion_hold; + + default: + /* impossible to reach here */ + break; + } + + break; + +assertion_hold: + ctx->tag--; + + list.head = NULL; + list.count = 0; + rc = sre_vm_pike_add_thread(ctx, &list, pc + 1, cap, + (sre_int_t) (sp - input), NULL); + + if (rc != SRE_OK) { + prog->tag = ctx->tag + 1; + return SRE_ERROR; + } + + if (list.head) { + *list.next = clist->head; + clist->head = list.head; + clist->count += list.count; + } + + ctx->tag++; + + dd("sp + 1 == last: %d, eof: %u", sp + 1 == last, eof); + break; + + case SRE_OPCODE_MATCH: + + ctx->last_matched_pos = cap->vector[1]; + cap->regex_id = pc->v.regex_id; + +matched: + if (matched) { + + dd("discarding match: "); +#if (DDEBUG) + sre_capture_dump(matched); +#endif + sre_capture_decr_ref(ctx, matched); + } + + dd("set matched, regex id: %d", (int) pc->v.regex_id); + + matched = cap; + + sre_vm_pike_free_thread(ctx, t); + + sre_vm_pike_clear_thread_list(ctx, clist); + + goto step_done; + + /* + * Jmp, Split, Save handled in addthread, so that + * machine execution matches what a backtracker would do. + * This is discussed (but not shown as code) in + * Regular Expression Matching: the Virtual Machine Approach. + */ + default: + /* impossible to reach here */ + break; + } + + sre_vm_pike_free_thread(ctx, t); + } /* while */ + +step_done: + tmp = clist; + clist = nlist; + nlist = tmp; + + if (nlist->head) { + sre_vm_pike_clear_thread_list(ctx, nlist); + } + + if (sp == last) { + break; + } + } /* for */ + + dd("matched: %p, clist: %p, pos: %d", matched, clist->head, + (int) (ctx->processed_bytes + (sp - input))); + + if (ctx->last_matched_pos >= 0) { + p = input + ctx->last_matched_pos - ctx->processed_bytes; + if (p > input) { + dd("diff: %d", + (int) (ctx->last_matched_pos - ctx->processed_bytes)); + dd("p=%p, input=%p", p, ctx->buffer); + + ctx->seen_newline = (p[-1] == '\n'); + ctx->seen_word = sre_isword(p[-1]); + + dd("set seen newline: %u", ctx->seen_newline); + dd("set seen word: %u", ctx->seen_word); + } + + ctx->last_matched_pos = -1; + } + + prog->tag = ctx->tag; + ctx->current_threads = clist; + ctx->next_threads = nlist; + + if (matched) { + if (eof || clist->head == NULL) { + if (sre_vm_pike_prepare_matched_captures(ctx, matched, + ctx->ovector, 1) + != SRE_OK) + { + return SRE_ERROR; + } + + if (clist->head) { + *clist->next = ctx->free_threads; + ctx->free_threads = clist->head; + clist->head = NULL; + clist->count = 0; + ctx->eof = 1; + } + + ctx->processed_bytes = ctx->ovector[1]; + ctx->empty_capture = (ctx->ovector[0] == ctx->ovector[1]); + + ctx->matched = NULL; + ctx->first_buf = 1; + + rc = matched->regex_id; + sre_capture_decr_ref(ctx, matched); + + dd("set empty capture: %u", ctx->empty_capture); + + return rc; + } + + dd("clist head cap == matched: %d", clist->head->capture == matched); + + if (pending_matched) { +#if 1 + if (ctx->pending_ovector == NULL) { + ctx->pending_ovector = sre_palloc(pool, 2 * sizeof(sre_int_t)); + if (ctx->pending_ovector == NULL) { + return SRE_ERROR; + } + } + + *pending_matched = ctx->pending_ovector; + + if (sre_vm_pike_prepare_matched_captures(ctx, matched, + *pending_matched, 0) + != SRE_OK) + { + return SRE_ERROR; + } +#endif + } + + } else { + if (eof) { + ctx->eof = 1; + ctx->matched = NULL; + + return SRE_DECLINED; + } + + if (pending_matched) { + *pending_matched = NULL; + } + } + + ctx->processed_bytes += (sre_int_t) (sp - input); + + dd("processed bytes: %u", (unsigned) ctx->processed_bytes); + + ctx->matched = matched; + + sre_vm_pike_prepare_temp_captures(prog, ctx); + +#if 0 + if (sp > input) { + ctx->seen_newline = (sp[-1] == '\n'); + ctx->seen_word = sre_isword(sp[-1]); + } +#endif + + return SRE_AGAIN; +} + + +static void +sre_vm_pike_prepare_temp_captures(sre_program_t *prog, sre_vm_pike_ctx_t *ctx) +{ + sre_int_t a, b; + sre_uint_t i, j, ofs; + sre_capture_t *cap; + sre_vm_pike_thread_t *t; + + ctx->ovector[0] = -1; + ctx->ovector[1] = -1; + + for (t = ctx->current_threads->head; t; t = t->next) { + cap = t->capture; + + ofs = 0; + for (i = 0; i < prog->nregexes; i++) { + + for (j = 0; j < 2; j += 2) { + a = ctx->ovector[j]; + b = cap->vector[ofs + j]; + + dd("%d: %d -> %d", (int) j, (int) b, (int) a); + + if (b != -1 && (a == -1 || b < a)) { + dd("setting group %d to %d", (int) j, (int) cap->vector[j]); + ctx->ovector[j] = b; + } + + a = ctx->ovector[j + 1]; + b = cap->vector[j + 1]; + + dd("%d: %d -> %d", (int) (j + 1), (int) b, (int) a); + + if (b != -1 && (a == -1 || b > a)) { + dd("setting group %d to %d", (int) (j + 1), + (int) cap->vector[j + 1]); + ctx->ovector[j + 1] = b; + } + } + + ofs += 2 * (prog->multi_ncaps[i] + 1); + } + } +} + + +static sre_vm_pike_thread_list_t * +sre_vm_pike_thread_list_create(sre_pool_t *pool) +{ + sre_vm_pike_thread_list_t *l; + + l = sre_palloc(pool, sizeof(sre_vm_pike_thread_list_t)); + if (l == NULL) { + return NULL; + } + + l->head = NULL; + l->next = &l->head; + l->count = 0; + + return l; +} + + +static sre_int_t +sre_vm_pike_add_thread(sre_vm_pike_ctx_t *ctx, sre_vm_pike_thread_list_t *l, + sre_instruction_t *pc, sre_capture_t *capture, sre_int_t pos, + sre_capture_t **pcap) +{ + sre_int_t rc; + sre_vm_pike_thread_t *t; + sre_capture_t *cap; + unsigned seen_word = 0; + +#if 0 + dd("pc tag: %u, ctx tag: %u", pc->tag, ctx->tag); +#endif + + if (pc->tag == ctx->tag) { + dd("pc %d: already on list: %d", (int) (pc - ctx->program->start), + pc->tag); + + if (pc->opcode == SRE_OPCODE_SPLIT) { + if (pc->y->tag != ctx->tag) { + if (pc == ctx->program->start) { + dd("setting seen start state"); + ctx->seen_start_state = 1; + } + + return sre_vm_pike_add_thread(ctx, l, pc->y, capture, pos, + pcap); + } + } + + return SRE_OK; + } + + dd("adding thread: pc %d, bytecode %d", (int) (pc - ctx->program->start), + pc->opcode); + + pc->tag = ctx->tag; + + switch (pc->opcode) { + case SRE_OPCODE_JMP: + return sre_vm_pike_add_thread(ctx, l, pc->x, capture, pos, pcap); + + case SRE_OPCODE_SPLIT: + if (pc == ctx->program->start) { + dd("setting seen start state"); + ctx->seen_start_state = 1; + } + + capture->ref++; + + rc = sre_vm_pike_add_thread(ctx, l, pc->x, capture, pos, pcap); + if (rc != SRE_OK) { + capture->ref--; + return rc; + } + + return sre_vm_pike_add_thread(ctx, l, pc->y, capture, pos, pcap); + + case SRE_OPCODE_SAVE: + +#if 0 + dd("pc %d: cap %p: save %d as group %d", + (int) (pc - ctx->program->start), capture, pos, + pc->v.group); +#endif + + dd("save %u: processed bytes: %u, pos: %u", + (unsigned) pc->v.group, + (unsigned) ctx->processed_bytes, (unsigned) pos); + + cap = sre_capture_update(ctx->pool, capture, pc->v.group, + ctx->processed_bytes + pos, + &ctx->free_capture); + if (cap == NULL) { + return SRE_ERROR; + } + +#if 0 + dd("new cap: %p", cap); +#endif + + return sre_vm_pike_add_thread(ctx, l, pc + 1, cap, pos, pcap); + + case SRE_OPCODE_ASSERT: + switch (pc->v.assertion) { + case SRE_REGEX_ASSERT_BIG_A: + if (pos || ctx->processed_bytes) { + break; + } + + return sre_vm_pike_add_thread(ctx, l, pc + 1, capture, pos, pcap); + + case SRE_REGEX_ASSERT_CARET: + dd("seen newline: %u", ctx->seen_newline); + + if (pos == 0) { + if (ctx->processed_bytes && !ctx->seen_newline) { + break; + } + + } else { + if (ctx->buffer[pos - 1] != '\n') { + break; + } + } + + dd("newline assertion hold"); + + return sre_vm_pike_add_thread(ctx, l, pc + 1, capture, pos, pcap); + + case SRE_REGEX_ASSERT_SMALL_B: + case SRE_REGEX_ASSERT_BIG_B: + { + sre_char c; + + if (pos == 0) { + seen_word = 0; + + } else { + c = ctx->buffer[pos - 1]; + seen_word = sre_isword(c); + } + + goto add; + } + + default: + /* postpone look-ahead assertions */ + goto add; + } + + break; + + case SRE_OPCODE_MATCH: + + ctx->last_matched_pos = capture->vector[1]; + capture->regex_id = pc->v.regex_id; + +#if 1 + if (pcap) { + *pcap = capture; + return SRE_DONE; + } +#endif + + default: + +add: + if (ctx->free_threads) { + /* fprintf(stderr, "reusing free thread\n"); */ + + t = ctx->free_threads; + ctx->free_threads = t->next; + t->next = NULL; + + } else { + /* fprintf(stderr, "creating new thread\n"); */ + + t = sre_palloc(ctx->pool, sizeof(sre_vm_pike_thread_t)); + if (t == NULL) { + return SRE_ERROR; + } + } + + t->pc = pc; + t->capture = capture; + t->next = NULL; + t->seen_word = seen_word; + + if (l->head == NULL) { + l->head = t; + + } else { + *l->next = t; + } + + l->count++; + l->next = &t->next; + + dd("added thread: pc %d, bytecode %d", (int) (pc - ctx->program->start), + pc->opcode); + + break; + } + + return SRE_OK; +} + + +static sre_int_t +sre_vm_pike_prepare_matched_captures(sre_vm_pike_ctx_t *ctx, + sre_capture_t *matched, sre_int_t *ovector, sre_int_t complete) +{ + sre_program_t *prog = ctx->program; + sre_uint_t i, ofs = 0; + size_t len; + + if (matched->regex_id >= prog->nregexes) { + dd("bad regex id: %ld >= %ld", (long) matched->regex_id, + (long) prog->nregexes); + + return SRE_ERROR; + } + + for (i = 0; i < matched->regex_id; i++) { + ofs += prog->multi_ncaps[i] + 1; + } + + ofs *= 2; + + if (complete) { + len = 2 * (prog->multi_ncaps[i] + 1) * sizeof(sre_int_t); + + } else { + len = 2 * sizeof(sre_int_t); + } + + dd("ncaps for regex %d: %d", (int) i, (int) prog->multi_ncaps[i]); + + dd("matched captures: ofs: %d, len: %d", (int) ofs, + (int) (len / sizeof(sre_int_t))); + + memcpy(ovector, &matched->vector[ofs], len); + + if (!complete) { + return SRE_OK; + } + + if (ctx->ovecsize > len) { + memset((char *) ovector + len, -1, ctx->ovecsize - len); + } + + return SRE_OK; +} + + +static sre_char * +sre_vm_pike_find_first_byte(sre_char *pos, sre_char *last, + int leading_byte, sre_chain_t *leading_bytes) +{ +#if 1 + int in; + sre_uint_t i; + sre_chain_t *cl; + sre_instruction_t *pc; + sre_vm_range_t *range; + + /* optimize for single CHAR bc */ + if (leading_byte != -1) { + pos = memchr(pos, leading_byte, last - pos); + if (pos == NULL) { + return last; + } + + return pos; + } + + for ( ; pos != last; pos++) { + for (cl = leading_bytes; cl; cl = cl->next) { + pc = cl->data; + switch (pc->opcode) { + case SRE_OPCODE_CHAR: + if (*pos == pc->v.ch) { + return pos; + } + + break; + + case SRE_OPCODE_IN: + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + if (*pos >= range->from && *pos <= range->to) { + return pos; + } + } + + break; + + case SRE_OPCODE_NOTIN: + in = 0; + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + if (*pos >= range->from && *pos <= range->to) { + in = 1; + break; + } + } + + if (in == 0) { + return pos; + } + + break; + + default: + sre_assert(pc->opcode); + break; + } + } + } +#endif + + return pos; +} + + +static void +sre_vm_pike_clear_thread_list(sre_vm_pike_ctx_t *ctx, + sre_vm_pike_thread_list_t *list) +{ + sre_vm_pike_thread_t *t; + + while (list->head) { + t = list->head; + list->head = t->next; + list->count--; + + sre_capture_decr_ref(ctx, t->capture); + sre_vm_pike_free_thread(ctx, t); + } + + sre_assert(list->count == 0); +} diff --git a/lib/sregex/src/sregex/sre_vm_thompson.c b/lib/sregex/src/sregex/sre_vm_thompson.c new file mode 100644 index 0000000..ecc796f --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_thompson.c @@ -0,0 +1,362 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include +#include + + +static void sre_vm_thompson_add_thread(sre_vm_thompson_ctx_t *ctx, + sre_vm_thompson_thread_list_t *l, sre_instruction_t *pc, sre_char *sp); + + +SRE_API sre_vm_thompson_ctx_t * +sre_vm_thompson_create_ctx(sre_pool_t *pool, sre_program_t *prog) +{ + sre_uint_t len; + sre_vm_thompson_ctx_t *ctx; + sre_vm_thompson_thread_list_t *clist, *nlist; + + ctx = sre_palloc(pool, sizeof(sre_vm_thompson_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + ctx->pool = pool; + ctx->program = prog; + + len = prog->len; + + clist = sre_vm_thompson_create_thread_list(pool, len); + if (clist == NULL) { + return NULL; + } + + ctx->current_threads = clist; + + nlist = sre_vm_thompson_create_thread_list(pool, len); + if (nlist == NULL) { + return NULL; + } + + ctx->next_threads = nlist; + + ctx->tag = prog->tag + 1; + ctx->first_buf = 1; + + return ctx; +} + + +SRE_API sre_int_t +sre_vm_thompson_exec(sre_vm_thompson_ctx_t *ctx, sre_char *input, size_t size, + unsigned eof) +{ + sre_char *sp, *last; + sre_uint_t i, j; + unsigned in; + sre_program_t *prog; + sre_vm_range_t *range; + sre_instruction_t *pc; + sre_vm_thompson_thread_t *t; + sre_vm_thompson_thread_list_t *clist, *nlist, *tmp; + + prog = ctx->program; + clist = ctx->current_threads; + nlist = ctx->next_threads; + ctx->buffer = input; + + if (ctx->first_buf) { + ctx->first_buf = 0; + sre_vm_thompson_add_thread(ctx, clist, prog->start, input); + } + + last = input + size; + + for (sp = input; sp < last || (eof && sp == last); sp++) { + dd("=== pos %d (char %d).\n", (int)(sp - input), + (sp < last) ? (*sp & 0xFF) : 0); + + if (clist->count == 0) { + break; + } + + /* printf("%d(%02x).", (int)(sp - input), *sp & 0xFF); */ + + ctx->tag++; + + for (i = 0; i < clist->count; i++) { + t = &clist->threads[i]; + pc = t->pc; + + dd("--- #%u: pc %d: opcode %d\n", ctx->tag, (int)(pc - prog->start), + pc->opcode); + + switch (pc->opcode) { + case SRE_OPCODE_IN: + if (sp == last) { + break; + } + + in = 0; + for (j = 0; j < pc->v.ranges->count; j++) { + range = &pc->v.ranges->head[j]; + + dd("testing %d for [%d, %d] (%u)", *sp, (int) range->from, + (int) range->to, (unsigned) j); + + if (*sp >= range->from && *sp <= range->to) { + in = 1; + break; + } + } + + if (!in) { + break; + } + + sre_vm_thompson_add_thread(ctx, nlist, pc + 1, sp + 1); + break; + + case SRE_OPCODE_NOTIN: + if (sp == last) { + break; + } + + in = 0; + for (j = 0; j < pc->v.ranges->count; j++) { + range = &pc->v.ranges->head[j]; + + dd("testing %d for [%d, %d] (%u)", *sp, (int) range->from, + (int) range->to, (unsigned) j); + + if (*sp >= range->from && *sp <= range->to) { + in = 1; + break; + } + } + + if (in) { + break; + } + + sre_vm_thompson_add_thread(ctx, nlist, pc + 1, sp + 1); + break; + + case SRE_OPCODE_CHAR: + if (sp == last || *sp != pc->v.ch) { + break; + } + + sre_vm_thompson_add_thread(ctx, nlist, pc + 1, sp + 1); + break; + + case SRE_OPCODE_ANY: + if (sp == last) { + break; + } + + sre_vm_thompson_add_thread(ctx, nlist, pc + 1, sp + 1); + break; + + case SRE_OPCODE_ASSERT: + switch (pc->v.assertion) { + case SRE_REGEX_ASSERT_SMALL_Z: + if (sp != last) { + break; + } + + goto assertion_hold; + + case SRE_REGEX_ASSERT_DOLLAR: + if (sp != last && *sp != '\n') { + break; + } + + goto assertion_hold; + + case SRE_REGEX_ASSERT_BIG_B: + if (t->seen_word ^ (sp != last && sre_isword(*sp))) { + dd("\\B assertion failed: %u %c", t->seen_word, *sp); + break; + } + + dd("\\B assertion passed: %u %c", t->seen_word, *sp); + + goto assertion_hold; + + + case SRE_REGEX_ASSERT_SMALL_B: + dd("seen word: %d, sp == last: %d, char=%d", + t->seen_word, sp == last, sp == last ? 0 : *sp); + if ((t->seen_word + ^ (sp != last && sre_isword(*sp))) == 0) + { + dd("\\b assertion failed: %u %c, cur is word: %d, " + "pc=%d", + (int) t->seen_word, sp == last ? 0 : *sp, + sp != last && sre_isword(*sp), + (int) (pc - ctx->program->start)); + break; + } + + dd("\\b assertion passed: %u %c", (int) t->seen_word, + sp != last ? *sp : 0); + + goto assertion_hold; + + default: + /* impossible to reach here */ + break; + } + + break; + +assertion_hold: + ctx->tag--; + sre_vm_thompson_add_thread(ctx, clist, pc + 1, sp); + ctx->tag++; + break; + + case SRE_OPCODE_MATCH: + prog->tag = ctx->tag; + return SRE_OK; + + default: + /* + * Jmp, Split, Save handled in addthread, so that + * machine execution matches what a backtracker would do. + * This is discussed (but not shown as code) in + * Regular Expression Matching: the Virtual Machine Approach. + */ + break; + } /* switch */ + } /* for */ + + /* printf("\n"); */ + + tmp = clist; + clist = nlist; + nlist = tmp; + + nlist->count = 0; + if (sp == last) { + break; + } + } /* for */ + + prog->tag = ctx->tag; + + ctx->current_threads = clist; + ctx->next_threads = nlist; + + if (eof) { + return SRE_DECLINED; + } + + return SRE_AGAIN; +} + + +static void +sre_vm_thompson_add_thread(sre_vm_thompson_ctx_t *ctx, + sre_vm_thompson_thread_list_t *l, sre_instruction_t *pc, sre_char *sp) +{ + uint8_t seen_word = 0; + sre_vm_thompson_thread_t *t; + + if (pc->tag == ctx->tag) { /* already on list */ + return; + } + + pc->tag = ctx->tag; + + switch (pc->opcode) { + case SRE_OPCODE_JMP: + sre_vm_thompson_add_thread(ctx, l, pc->x, sp); + return; + + case SRE_OPCODE_SPLIT: + sre_vm_thompson_add_thread(ctx, l, pc->x, sp); + sre_vm_thompson_add_thread(ctx, l, pc->y, sp); + return; + + case SRE_OPCODE_SAVE: + sre_vm_thompson_add_thread(ctx, l, pc + 1, sp); + return; + + case SRE_OPCODE_ASSERT: + switch (pc->v.assertion) { + case SRE_REGEX_ASSERT_BIG_A: + if (sp != ctx->buffer) { + dd("\\A assertion failed: %d", (int) (sp - ctx->buffer)); + return; + } + + sre_vm_thompson_add_thread(ctx, l, pc + 1, sp); + return; + + case SRE_REGEX_ASSERT_CARET: + if (sp != ctx->buffer && sp[-1] != '\n') { + return; + } + + sre_vm_thompson_add_thread(ctx, l, pc + 1, sp); + return; + + case SRE_REGEX_ASSERT_SMALL_B: + case SRE_REGEX_ASSERT_BIG_B: + seen_word = (sp != ctx->buffer && sre_isword(sp[-1])); + dd("pc=%d, setting seen word: %u %c", + (int) (pc - ctx->program->start), + (int) seen_word, + (sp != ctx->buffer) ? sp[-1] : 0); + break; + + default: + /* postpone look-ahead assertions */ + + break; + } + + break; + + default: + break; + } + + t = &l->threads[l->count]; + t->pc = pc; + t->seen_word = seen_word; + + l->count++; +} + + +sre_vm_thompson_thread_list_t * +sre_vm_thompson_create_thread_list(sre_pool_t *pool, sre_uint_t size) +{ + sre_vm_thompson_thread_list_t *l; + + l = sre_pnalloc(pool, sizeof(sre_vm_thompson_thread_list_t) + + (size - 1) * sizeof(sre_vm_thompson_thread_t)); + if (l == NULL) { + return NULL; + } + + l->count = 0; + + return l; +} diff --git a/lib/sregex/src/sregex/sre_vm_thompson.h b/lib/sregex/src/sregex/sre_vm_thompson.h new file mode 100644 index 0000000..887d6a5 --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_thompson.h @@ -0,0 +1,50 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef _SRE_VM_THOMPSON_H_INCLUDED_ +#define _SRE_VM_THOMPSON_H_INCLUDED_ + + +#include +#include + + +typedef struct { + sre_instruction_t *pc; + void *asserts_handler; + uint8_t seen_word; /* :1 */ +} sre_vm_thompson_thread_t; + + +typedef struct { + sre_uint_t count; + sre_vm_thompson_thread_t threads[1]; +} sre_vm_thompson_thread_list_t; + + +struct sre_vm_thompson_ctx_s { + sre_pool_t *pool; + sre_program_t *program; + sre_char *buffer; + + sre_vm_thompson_thread_list_t *current_threads; + sre_vm_thompson_thread_list_t *next_threads; + + unsigned tag; + uint8_t first_buf; /* :1 */ + uint8_t threads_added[1]; /* bit array */ +}; + + +sre_vm_thompson_thread_list_t * + sre_vm_thompson_create_thread_list(sre_pool_t *pool, sre_uint_t size); + +unsigned sre_vm_thompson_jit_get_threads_added_size(sre_program_t *prog); + + +#endif /* _SRE_VM_THOMPSON_H_INCLUDED_ */ diff --git a/lib/sregex/src/sregex/sre_vm_thompson_jit.c b/lib/sregex/src/sregex/sre_vm_thompson_jit.c new file mode 100644 index 0000000..3c4f0fc --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_thompson_jit.c @@ -0,0 +1,241 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include + +#include + +#if (SRE_TARGET == SRE_ARCH_X64) +#include +#endif + +#include +#include +#if (SRE_TARGET != SRE_ARCH_UNKNOWN) +#include +#include +#endif + + +struct sre_vm_thompson_code_s { + size_t size; + + sre_vm_thompson_exec_pt handler; +}; + + +SRE_API sre_int_t +sre_vm_thompson_jit_compile(sre_pool_t *pool, sre_program_t *prog, + sre_vm_thompson_code_t **pcode) +{ +#if (SRE_TARGET != SRE_ARCH_X64) + return SRE_DECLINED; +#else + int status; + size_t codesz; + size_t size; + unsigned char *mem; + dasm_State *dasm; + void **glob; + unsigned nglobs = SRE_VM_THOMPSON_GLOB__MAX; + + sre_vm_thompson_code_t *code; + + glob = sre_pcalloc(pool, nglobs * sizeof(void *)); + if (glob == NULL) { + return SRE_ERROR; + } + + dasm_init(&dasm, 1); + dasm_setupglobal(&dasm, glob, nglobs); + dasm_setup(&dasm, sre_vm_thompson_jit_actions); + + dd("thread size: %d", (int) sizeof(sre_vm_thompson_thread_t)); + + if (sre_vm_thompson_jit_do_compile(&dasm, pool, prog) != SRE_OK) { + dasm_free(&dasm); + return SRE_ERROR; + } + + status = dasm_link(&dasm, &codesz); + if (status != DASM_S_OK) { + dasm_free(&dasm); + return SRE_ERROR; + } + + size = codesz + sizeof(sre_vm_thompson_code_t); + + dd("size: %d, codesiz: %d", (int) size, (int) codesz); + + mem = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, 0); + if (mem == MAP_FAILED) { + perror("mmap"); + dasm_free(&dasm); + return SRE_ERROR; + } + + code = (sre_vm_thompson_code_t *) mem; + + code->size = size; + code->handler = (sre_vm_thompson_exec_pt) + (mem + sizeof(sre_vm_thompson_code_t)); + + *pcode = code; + + dasm_encode(&dasm, code->handler); + +#if (DDEBUG) + { + int i; + int len; + FILE *f; + const char *gl; + + /* + * write generated machine code to a temporary file. + * wiew with objdump or ndisasm + */ + f = fopen("/tmp/thompson-jit.bin", "wb"); + fwrite(code->handler, codesz, 1, f); + fclose(f); + + f = fopen("/tmp/thompson-jit.txt", "w"); + fprintf(f, "code section: start=%p len=%lu\n", code->handler, + (unsigned long) codesz); + + fprintf(f, "global names:\n"); + + for (i = 0; i < nglobs; i++) { + gl = sre_vm_thompson_jit_global_names[i]; + len = (int) strlen(gl); + if (!glob[i]) { + continue; + } + /* Skip the _Z symbols. */ + if (!(len >= 2 && gl[len-2] == '_' && gl[len-1] == 'Z')) { + fprintf(f, " %s => %p\n", gl, glob[i]); + } + } + + fprintf(f, "\npc labels:\n"); + for (i = 0; i < dasm->pcsize; i++) { + int32_t ofs = dasm_getpclabel(&dasm, i); + if (ofs >= 0) { + fprintf(f, " %d => %ld\n", i, (long) ofs); + } + } + + fclose(f); + } +#endif + + dasm_free(&dasm); + + if (mprotect(mem, size, PROT_EXEC | PROT_READ) != 0) { + (void) munmap(code, code->size); + return SRE_ERROR; + } + + dd("code start addr: %p", code->handler); + + return SRE_OK; +#endif /* SRE_TARGET == SRE_ARCH_X64 */ +} + + +SRE_API sre_int_t +sre_vm_thompson_jit_free(sre_vm_thompson_code_t *code) +{ +#if (SRE_TARGET != SRE_ARCH_UNKNOWN) + if (munmap(code, code->size) != 0) { + return SRE_ERROR; + } +#endif + return SRE_OK; +} + + +SRE_API sre_vm_thompson_exec_pt +sre_vm_thompson_jit_get_handler(sre_vm_thompson_code_t *code) +{ + if (code == NULL) { + return NULL; + } + + return code->handler; +} + + +SRE_API sre_vm_thompson_ctx_t * +sre_vm_thompson_jit_create_ctx(sre_pool_t *pool, sre_program_t *prog) +{ + sre_uint_t size, len; + sre_vm_thompson_ctx_t *ctx; + sre_vm_thompson_thread_list_t *clist, *nlist; + + size = sre_vm_thompson_jit_get_threads_added_size(prog); + + dd("threads_added size: %d", (int) size); + + ctx = sre_palloc(pool, sizeof(sre_vm_thompson_ctx_t) - 1 + size); + if (ctx == NULL) { + return NULL; + } + + dd("ctx->threads_added: %x", + (int) offsetof(sre_vm_thompson_ctx_t, threads_added)); + + ctx->pool = pool; + ctx->program = prog; + + len = prog->uniq_threads; + + clist = sre_vm_thompson_create_thread_list(pool, len); + if (clist == NULL) { + return NULL; + } + + ctx->current_threads = clist; + + nlist = sre_vm_thompson_create_thread_list(pool, len); + if (nlist == NULL) { + return NULL; + } + + ctx->next_threads = nlist; + + ctx->tag = prog->tag + 1; + ctx->first_buf = 1; + + return ctx; +} + + +unsigned +sre_vm_thompson_jit_get_threads_added_size(sre_program_t *prog) +{ +#if (SRE_TARGET == SRE_ARCH_X64) + +#if 1 + if (prog->dup_threads <= 64) { + return 0; + } +#endif + + return sre_align(prog->dup_threads, 64) / 8; +#else + return 0; +#endif +} diff --git a/lib/sregex/src/sregex/sre_vm_thompson_x64.dasc b/lib/sregex/src/sregex/sre_vm_thompson_x64.dasc new file mode 100644 index 0000000..36cc0e2 --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_thompson_x64.dasc @@ -0,0 +1,955 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +|.arch x64 +|.actionlist sre_vm_thompson_jit_actions + +|.globals SRE_VM_THOMPSON_GLOB_ + +#if (DDEBUG) +|.globalnames sre_vm_thompson_jit_global_names +#endif + +/* thread count */ +|.define TC, r14 // callee-save + +/* seen word */ +|.define SW, r13 // callee-save + +/* string pointer */ +|.define SP, r12 // callee-save + +|.define LAST, rdx // overriding 3rd arg +|.define INPUT, rsi // 2nd arg +|.define EOF, bl // 4th arg + +/* seen last byte */ +|.define LB, bh + +/* current input string byte */ +|.define C, r11b + +/* the position after the last thread */ +|.define LT, r9 + +/* recording threads added */ +|.define ADDED, rcx + +|.type CTX, sre_vm_thompson_ctx_t, rdi // 1st arg +|.type TL, sre_vm_thompson_thread_list_t, r15 // callee-save +|.type T, sre_vm_thompson_thread_t, r8 // callee-save +|.type CT, sre_vm_thompson_thread_t, rbp // callee-save + +/* current thread list */ +|.type CTL, sre_vm_thompson_thread_list_t, r10 // callee-save + +|.macro addThreadWithoutCheck, target +| +||if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { +| mov T->seen_word, al +||} +| +| lea rax, [target] +| mov T->pc, rax +| +||if (jit->program->lookahead_asserts) { +|| if (asserts) { +| +| lea rax, [=>(jit->program->len + asserts - 1)] +| mov T->asserts_handler, rax +| +|| } else { +| xor rax, rax +| mov T->asserts_handler, rax +|| } +||} +| +| add TC, 1 +| +||if (n != path->nthreads) { +| add T, #T +||} +| +|.endmacro + + +|.macro addThreadWithCheck, target +| +||if (jit->threads_added_in_memory) { +|| if (tid / 64 != prev_word) { +|| prev_word = tid / 64; +| mov ADDED, CTX->threads_added[(tid / 64)] +|| } +| +|| bofs = tid % 64; +| +||} else { +|| bofs = tid; +||} +| +| bts ADDED, (bofs) // load CF with the bit and set the bit +| jb >2 // jump if CF = 1 +| +||if (jit->threads_added_in_memory) { +| mov CTX->threads_added[(tid / 64)], ADDED +||} +| +||if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { +| mov T->seen_word, al +||} +| +| lea rax, [target] +| mov T->pc, rax +| +||if (jit->program->lookahead_asserts) { +|| if (asserts) { +| lea rax, [=>(jit->program->len + asserts - 1)] +| mov T->asserts_handler, rax +| +|| } else { +| xor rax, rax +| mov T->asserts_handler, rax +|| } +||} +| +| add TC, 1 +| +||if (n != path->nthreads) { +| add T, #T +||} +| +|2: +| +|.endmacro + + +|.macro testWordChar +||if (!char_always_valid) { +| test LB, LB +| jnz >2 +||} +| cmp C, byte '0' +| jb >2 +| cmp C, byte '9' +| jbe >3 +| cmp C, byte 'A' +| jb >2 +| cmp C, byte 'Z' +| jbe >3 +| cmp C, byte 'a' +| jb >2 +| cmp C, byte 'z' +| jbe >3 +| cmp C, byte '_' +| je >3 +|2: +| // not word +| xor al, al +| jmp >4 +|3: +| // word +| mov al, 1 +|4: +|.endmacro + + +/* This affects the "|" DynASM lines. */ +#define Dst dasm + + +#include +#include +#include +#include +#include + + +typedef struct sre_vm_thompson_path_s sre_vm_thompson_path_t; + +typedef struct { + sre_pool_t *pool; + sre_program_t *program; + dasm_State **dasm; + unsigned tag; + unsigned thread_index_factor; + + uint8_t *bc_accessed; /* TODO: use a sparse or bit array here */ + int *dup_thread_ids; /* TODO: use a sparse array here */ + unsigned threads_added_in_memory; /* 1: use ctx->threads_added; + 0: use the CPU register + ADDED only */ + + sre_vm_thompson_path_t *path; +} sre_vm_thompson_jit_t; + + +typedef struct sre_vm_thompson_state_s sre_vm_thompson_state_t; + +struct sre_vm_thompson_state_s { + unsigned asserts; + unsigned thread_index; + unsigned is_thread; + sre_instruction_t *bc; + sre_vm_thompson_state_t *next; +}; + + +struct sre_vm_thompson_path_s { + unsigned nthreads; + sre_instruction_t *from; + sre_vm_thompson_state_t *to; + sre_vm_thompson_path_t *next; +}; + + +static sre_int_t sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + sre_vm_thompson_path_t *path); +static sre_int_t sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit); +static sre_int_t sre_vm_thompson_jit_get_next_states(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, sre_vm_thompson_state_t ***plast_state, + unsigned *nthreads, unsigned asserts); +static sre_int_t sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit); +static sre_int_t sre_vm_thompson_jit_build_paths(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, sre_vm_thompson_path_t ***plast_path); +static unsigned sre_vm_thompson_jit_gen_thread_index(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, unsigned asserts); + + +SRE_NOAPI sre_int_t +sre_vm_thompson_jit_do_compile(dasm_State **dasm, sre_pool_t *pool, + sre_program_t *prog) +{ + unsigned i, n, count; + sre_vm_thompson_jit_t jit; + sre_vm_thompson_path_t *path, **last_path; + + jit.pool = pool; + jit.program = prog; + jit.dasm = dasm; + + jit.bc_accessed = sre_pcalloc(pool, prog->len); + if (jit.bc_accessed == NULL) { + return SRE_ERROR; + } + + jit.thread_index_factor = (SRE_REGEX_ASSERT_LOOKAHEAD + 1); + + dd("prog len: %d", (int) prog->len); + dd("thread index factor: %d", (int) jit.thread_index_factor); + + count = prog->len * jit.thread_index_factor; + dd("thread index count: %d", (int) count); + + jit.dup_thread_ids = sre_pcalloc(pool, count * sizeof(int)); + if (jit.dup_thread_ids == NULL) { + return SRE_ERROR; + } + + jit.path = NULL; + last_path = &jit.path; + + if (sre_vm_thompson_jit_build_paths(&jit, prog->start, &last_path) + != SRE_OK) + { + return SRE_ERROR; + } + + dd("first path: %p, pc: %d", jit.path, + (int) (jit.path->from - jit.program->start)); + + n = 0; + for (i = 0; i < count; i++) { + if (jit.dup_thread_ids[i] > 0) { + dd("found unique thread at pc %d, ref count: %d", + (int) (i / jit.thread_index_factor), (int) jit.dup_thread_ids[i]); + + prog->uniq_threads++; + + if (jit.dup_thread_ids[i] > 1) { + dd("found duplicatable thread at pc %d, ref count: %d", + (int) (i / jit.thread_index_factor), (int) jit.dup_thread_ids[i]); + + jit.dup_thread_ids[i] = n++; + continue; + } + } + + jit.dup_thread_ids[i] = -1; + } + + prog->dup_threads = n; + + dd("unique threads: %u, duplicatable threads: %u", + prog->uniq_threads, prog->dup_threads); + + jit.threads_added_in_memory = (prog->dup_threads > 64); + +#if 0 + jit.threads_added_in_memory = 1; +#endif + + n = prog->len + prog->lookahead_asserts; + + dd("growing pc label to %d, prog len: %d", n, (int) prog->len); + dasm_growpc(dasm, n); + + if (sre_vm_thompson_jit_prologue(&jit) != SRE_OK) { + return SRE_ERROR; + } + + for (path = jit.path; path; path = path->next) { + + dd("compiling path %p with pc %d", path, + (int) (path->from - jit.program->start)); + + if (sre_vm_thompson_jit_compile_path(&jit, path) != SRE_OK) { + return SRE_ERROR; + } + } + + if (sre_vm_thompson_jit_epilogue(&jit) != SRE_OK) { + return SRE_ERROR; + } + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_build_paths(sre_vm_thompson_jit_t *jit, sre_instruction_t *pc, + sre_vm_thompson_path_t ***plast_path) +{ + sre_vm_thompson_path_t *path; + sre_vm_thompson_state_t *state, **last_state; + + jit->bc_accessed[pc - jit->program->start] = 1; + + path = sre_pcalloc(jit->pool, sizeof(sre_vm_thompson_path_t)); + if (path == NULL) { + return SRE_ERROR; + } + + dd("build path from pc %d", (int) (pc - jit->program->start)); + + path->from = pc; + last_state = &path->to; + jit->tag = jit->program->tag + 1; + + if (pc == jit->program->start) { + if (sre_vm_thompson_jit_get_next_states(jit, pc, &last_state, + &path->nthreads, 0) + != SRE_OK) + { + jit->program->tag = jit->tag; + return SRE_ERROR; + } + + } else { + if (pc + 1 >= jit->program->start + jit->program->len) { + jit->program->tag = jit->tag; + return SRE_ERROR; + } + + if (sre_vm_thompson_jit_get_next_states(jit, pc + 1, &last_state, + &path->nthreads, 0) + != SRE_OK) + { + jit->program->tag = jit->tag; + return SRE_ERROR; + } + } + + jit->program->tag = jit->tag; + + if (path->to == NULL) { + return SRE_ERROR; + } + + **plast_path = path; + *plast_path = &path->next; + + for (state = path->to; state; state = state->next) { + if (state->bc->opcode == SRE_OPCODE_MATCH) { + continue; + } + + if (jit->bc_accessed[state->bc - jit->program->start]) { + continue; + } + + if (sre_vm_thompson_jit_build_paths(jit, state->bc, + plast_path) + != SRE_OK) + { + return SRE_ERROR; + } + } + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + sre_vm_thompson_path_t *path) +{ + sre_char c; + unsigned i, n, asserts, char_always_valid = 1; + int tid, prev_word; + unsigned bofs; + sre_int_t ofs; + dasm_State **dasm; + sre_vm_range_t *range; + sre_instruction_t *bc, *pc; + + sre_vm_thompson_state_t *state; + + dasm = jit->dasm; + pc = path->from; + ofs = pc - jit->program->start; + + if (dasm_getpclabel(dasm, ofs) >= 0) { + dd("bc %d already compiled", (int) ofs); + return SRE_ERROR; + } + + dd("compiling path at pc %d", (int) (pc - jit->program->start)); + + |=>(ofs): + + switch (pc->opcode) { + case SRE_OPCODE_ANY: + | test LB, LB + | jnz >1 + + break; + + case SRE_OPCODE_CHAR: + c = pc->v.ch; + + | test LB, LB + | jnz >1 + | + | cmp C, byte (c) + | jne >1 + + break; + + case SRE_OPCODE_IN: + | test LB, LB + | jnz >1 + + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + dd("compile opcode IN: [%d, %d] (%u)", (int) range->from, + (int) range->to, (unsigned) i); + + if (range->from == range->to) { + | cmp C, byte (range->from) + | je >2 + + } else { + if (range->from != 0x00) { + | cmp C, byte (range->from) + | jb >3 + } + + if (range->to == 0xff) { + | jmp >2 + + } else { + | cmp C, byte (range->to) + | jbe >2 + } + + |3: + } + } + + | jmp >1 + |2: + + break; + + case SRE_OPCODE_NOTIN: + | test LB, LB + | jnz >1 + + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + dd("compile opcode IN: [%d, %d] (%u)", (int) range->from, + (int) range->to, (unsigned) i); + + if (range->from == range->to) { + | cmp C, byte (range->from) + | je >1 + + } else { + if (range->from != 0x00) { + | cmp C, byte (range->from) + | jb >2 + } + + if (range->to == 0xff) { + | jmp >1 + + } else { + | cmp C, byte (range->to) + | jbe >1 + } + + if (range->from != 0x00) { + |2: + } + } + } + + break; + + default: + /* do nothing */ + break; + } + + prev_word = -1; + n = 0; + for (state = path->to; state; state = state->next) { + bc = state->bc; + asserts = state->asserts; + + if (state->is_thread) { + n++; + + if (n == 1) { + | imul rax, TC, #T // thread index offset + | lea T, [TL + rax + offsetof(sre_vm_thompson_thread_list_t, threads)] + } + } + + if (asserts) { + if (asserts & SRE_REGEX_ASSERT_BIG_A) { + asserts &= ~SRE_REGEX_ASSERT_BIG_A; + + if (pc != jit->program->start) { + /* assertion always does not hold */ + continue; + } + + /* assertion always holds when pc == jit->program->start */ + } + + if (asserts & SRE_REGEX_ASSERT_CARET) { + asserts &= ~SRE_REGEX_ASSERT_CARET; + + /* assertion always holds when pc == jit->program->start */ + + if (pc != jit->program->start) { + | cmp C, byte '\n' + | jne >9 + } + } + + if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + if (pc == jit->program->start) { + | xor al, al + + } else { + | testWordChar + } + } + } + + if (bc->opcode == SRE_OPCODE_MATCH) { + + dd("seen a match bc: %d, len: %d", + (int) (bc - jit->program->start), (int) jit->program->len); + + if (asserts) { + ofs = bc - jit->program->start; + tid = jit->dup_thread_ids[state->thread_index]; + + dd("compiling asserts for match: %d", asserts); + + if (tid >= 0 && pc != jit->program->start) { + | addThreadWithCheck ->match + + } else { + dd("seen a non thread entry match at bc %d", (int) ofs); + + | addThreadWithoutCheck ->match + } + + } else { + | mov eax, 1 + | ret + } + + } else { + /* being bytecode ANY, CHAR, IN, or NOTIN */ + + ofs = bc - jit->program->start; + tid = jit->dup_thread_ids[state->thread_index]; + + if (tid >= 0 && pc != jit->program->start) { + dd("seen a thread entry bc at bc %d, id=%d", (int) ofs, + (int) tid); + + | addThreadWithCheck =>(ofs) + + } else { + dd("seen a non thread entry bc at bc %d", (int) ofs); + | addThreadWithoutCheck =>(ofs) + } + } + + |9: + } /* for */ + + |1: + | xor eax, eax + | ret + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_get_next_states(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, sre_vm_thompson_state_t ***plast_state, + unsigned *nthreads, unsigned asserts) +{ + sre_vm_thompson_state_t *state; + + if (pc->tag == jit->tag) { + return SRE_OK; + } + + pc->tag = jit->tag; + + switch (pc->opcode) { + case SRE_OPCODE_SPLIT: + if (sre_vm_thompson_jit_get_next_states(jit, pc->x, plast_state, + nthreads, asserts) + != SRE_OK) + { + return SRE_ERROR; + } + + return sre_vm_thompson_jit_get_next_states(jit, pc->y, plast_state, + nthreads, asserts); + + case SRE_OPCODE_JMP: + return sre_vm_thompson_jit_get_next_states(jit, pc->x, plast_state, + nthreads, asserts); + + case SRE_OPCODE_SAVE: + if (++pc == jit->program->start + jit->program->len) { + return SRE_OK; + } + + return sre_vm_thompson_jit_get_next_states(jit, pc, plast_state, + nthreads, asserts); + + case SRE_OPCODE_MATCH: + dd("seen match bc %d, asserts %d", + (int) (pc - jit->program->start), (int) asserts); + + state = sre_pcalloc(jit->pool, sizeof(sre_vm_thompson_state_t)); + if (state == NULL) { + return SRE_ERROR; + } + + state->asserts = asserts; + state->bc = pc; + state->thread_index = sre_vm_thompson_jit_gen_thread_index(jit, pc, + asserts); + + if (asserts & SRE_REGEX_ASSERT_LOOKAHEAD) { + jit->dup_thread_ids[state->thread_index]++; + + state->is_thread = 1; + (*nthreads)++; + } + + **plast_state = state; + *plast_state = &state->next; + + return SRE_OK; + + case SRE_OPCODE_ASSERT: + dd("seen assert bc at %d", (int) (pc - jit->program->start)); + + asserts |= pc->v.assertion; + + jit->program->lookahead_asserts |= (asserts & SRE_REGEX_ASSERT_LOOKAHEAD); + + if (++pc == jit->program->start + jit->program->len) { + return SRE_OK; + } + + return sre_vm_thompson_jit_get_next_states(jit, pc, plast_state, + nthreads, asserts); + + default: + /* CHAR, ANY, IN, NOTIN */ + + state = sre_pcalloc(jit->pool, sizeof(sre_vm_thompson_state_t)); + if (state == NULL) { + return SRE_ERROR; + } + + state->asserts = asserts; + state->bc = pc; + state->thread_index = sre_vm_thompson_jit_gen_thread_index(jit, pc, + asserts); + + jit->dup_thread_ids[state->thread_index]++; + state->is_thread = 1; + + **plast_state = state; + *plast_state = &state->next; + + (*nthreads)++; + + dd("seen terminal bc: %d", (int) (pc - jit->program->start)); + return SRE_OK; + } + + /* impossible to reach here */ +} + + +static unsigned +sre_vm_thompson_jit_gen_thread_index(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, unsigned asserts) +{ + return (pc - jit->program->start) * jit->thread_index_factor + + (asserts & SRE_REGEX_ASSERT_LOOKAHEAD); +} + + +static sre_int_t +sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) +{ + size_t size; + dasm_State **dasm; + + dasm = jit->dasm; + + | push TC; push TL; push T; push SW; push LAST; push SP; + | push CTL; push CT; push LT; push rbx; push r11; push ADDED + | + | // check the 4th arg, "eof" + | test ecx, ecx + | jz >1 + | mov EOF, 1 + | jmp >2 + | + |1: + | xor EOF, EOF + | + |2: + | mov CTL, CTX->current_threads + | mov TC, CTL->count + | xor LB, LB + | + | mov al, CTX->first_buf + | test al, al + | jz ->not_first_buf + | + |->first_buf: + | mov byte CTX->first_buf, 0 + | + | mov TL, CTL + | xor SW, SW + | call =>0 + | test eax, eax + | jz ->not_first_buf + | xor rax, rax // (SRE_OK) + | jmp ->return + | + |->not_first_buf: + | add LAST, INPUT // last = input + size + | mov TL, CTX->next_threads + | mov SP, INPUT + | + | jmp ->sp_loop_start + | + |->sp_loop_next: + | add SP, 1 + | + |->sp_loop_start: + | cmp SP, LAST + | je ->buf_consumed + | + | // sp != last + | mov C, byte [SP] + | jmp ->run_cur_threads + | + |->buf_consumed: + | test EOF, EOF + | jz ->again + | mov LB, 1 + | + |->run_cur_threads: + | test TC, TC + | jz ->done + | + + if (jit->threads_added_in_memory) { + size = sre_vm_thompson_jit_get_threads_added_size(jit->program); + + /* clear the CTX->threads_added bit array */ + + | // rcx is for ADDED, and r8 is for T + | lea r8, CTX->threads_added + | xor rax, rax + | mov rcx, (size / 8) + |1: + | mov qword [r8], rax + | add r8, 8 + | dec rcx + | jnz <1 + + } else { + | xor ADDED, ADDED + } + + | imul rax, TC, #T // thread index offset + | lea LT, [CTL + rax + offsetof(sre_vm_thompson_thread_list_t, threads)] + | lea CT, [CTL + offsetof(sre_vm_thompson_thread_list_t, threads)] + | xor TC, TC + | jmp ->run_thread + | + |->run_next_thread: + | add CT, #T + | + |->run_thread: + | cmp CT, LT + | je ->run_threads_done + | + + if (jit->program->lookahead_asserts) { + | mov rax, CT->asserts_handler + | test rax, rax + | jz >1 + | call rax + | test eax, eax + | jz ->run_next_thread + | + |1: + } + + | call aword CT->pc + | + | test eax, eax + | jz ->run_next_thread + | + | // matched + | xor rax, rax // (SRE_OK) + | jmp ->return + | + |->run_threads_done: + | mov rax, CTL + | mov CTL, TL + | mov TL, rax + | + | test LB, LB + | jz ->sp_loop_next + | + |->done: + | test EOF, EOF + | jz ->again + | mov rax, (SRE_DECLINED) + | jmp ->return + | + |->again: + | mov rax, (SRE_AGAIN) + | + |->return: + | mov CTX->current_threads, CTL + | mov CTL->count, TC + | + | mov CTX->next_threads, TL + | xor TC, TC + | mov TL->count, TC + | + | pop ADDED; pop r11; pop rbx; pop LT; pop CT; pop CTL; + | pop SP; pop LAST; pop SW; pop T; pop TL; pop TC + | ret + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) +{ + unsigned flags, char_always_valid = 0; + sre_uint_t len; + dasm_State **dasm; + + if (jit->program->lookahead_asserts) { + + dasm = jit->dasm; + len = jit->program->len; + + |->match: + | mov eax, 1 + | ret + + for (flags = 1; flags <= SRE_REGEX_ASSERT_LOOKAHEAD; flags++) { + + if ((flags & jit->program->lookahead_asserts) != flags) { + continue; + } + + |=>(len + flags - 1): + + if (flags & SRE_REGEX_ASSERT_SMALL_Z) { + | test LB, LB + | jz >1 + } + + if (flags & SRE_REGEX_ASSERT_DOLLAR) { + if (!(flags & SRE_REGEX_ASSERT_SMALL_Z)) { + | test LB, LB + | jnz >2 + } + + | cmp C, '\n' + | jne >1 + |2: + } + + if (flags & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + | mov ah, byte CT->seen_word + | testWordChar + | xor al, ah + + if (flags & SRE_REGEX_ASSERT_SMALL_B) { + | jz >1 + + } else { + /* SRE_REGEX_ASSERT_BIG_B */ + | jnz >1 + } + } + + | mov eax, 1 + | ret + |1: + | xor eax, eax + | ret + } + } + + return SRE_OK; +} diff --git a/lib/sregex/src/sregex/sre_vm_thompson_x64.h b/lib/sregex/src/sregex/sre_vm_thompson_x64.h new file mode 100644 index 0000000..6280ae7 --- /dev/null +++ b/lib/sregex/src/sregex/sre_vm_thompson_x64.h @@ -0,0 +1,1232 @@ +/* +** This file has been pre-processed with DynASM. +** http://luajit.org/dynasm.html +** DynASM version 1.3.0, DynASM x64 version 1.3.0 +** DO NOT EDIT! The original file is in "src/sregex/sre_vm_thompson_x64.dasc". +*/ + +#if DASM_VERSION != 10300 +#error "Version mismatch between DynASM and included encoding engine" +#endif + +# 1 "src/sregex/sre_vm_thompson_x64.dasc" + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +//|.arch x64 +//|.actionlist sre_vm_thompson_jit_actions +static const unsigned char sre_vm_thompson_jit_actions[703] = { + 249,255,132,252,255,15,133,244,247,255,132,252,255,15,133,244,247,65,128, + 252,251,235,15,133,244,247,255,65,128,252,251,235,15,132,244,248,255,65,128, + 252,251,235,15,130,244,249,255,252,233,244,248,255,65,128,252,251,235,15, + 134,244,248,255,248,3,255,252,233,244,247,248,2,255,65,128,252,251,235,15, + 132,244,247,255,65,128,252,251,235,15,130,244,248,255,252,233,244,247,255, + 65,128,252,251,235,15,134,244,247,255,73,105,198,239,77,141,132,253,7,233, + 255,65,128,252,251,235,15,133,244,255,255,48,192,255,132,252,255,15,133,244, + 248,255,65,128,252,251,235,15,130,244,248,65,128,252,251,235,15,134,244,249, + 65,128,252,251,235,15,130,244,248,65,128,252,251,235,15,134,244,249,65,128, + 252,251,235,15,130,244,248,65,128,252,251,235,15,134,244,249,65,128,252,251, + 235,15,132,244,249,248,2,255,48,192,252,233,244,250,248,3,176,1,248,4,255, + 72,139,143,233,255,72,15,186,252,233,235,15,130,244,248,255,72,137,143,233, + 255,65,136,128,233,255,72,141,5,244,10,73,137,128,233,255,72,141,5,245,73, + 137,128,233,255,72,49,192,73,137,128,233,255,73,131,198,1,255,73,129,192, + 239,255,184,1,0,0,0,195,255,248,9,255,248,1,49,192,195,255,65,86,65,87,65, + 80,65,85,82,65,84,65,82,85,65,81,83,65,83,81,133,201,15,132,244,247,179,1, + 252,233,244,248,248,1,48,219,248,2,76,139,151,233,77,139,178,233,48,252,255, + 138,135,233,132,192,15,132,244,11,248,12,198,135,233,0,77,137,215,77,49,252, + 237,232,245,133,192,15,132,244,11,72,49,192,252,233,244,13,248,11,255,72, + 1,252,242,76,139,191,233,73,137,252,244,252,233,244,14,248,15,73,131,196, + 1,248,14,73,57,212,15,132,244,16,69,138,28,36,252,233,244,17,248,16,132,219, + 15,132,244,18,183,1,248,17,77,133,252,246,15,132,244,19,255,76,141,135,233, + 72,49,192,72,199,193,237,248,1,73,137,0,73,131,192,8,72,252,255,201,15,133, + 244,1,255,72,49,201,255,73,105,198,239,77,141,140,253,2,233,73,141,170,233, + 77,49,252,246,252,233,244,20,248,21,72,129,197,239,248,20,76,57,205,15,132, + 244,22,255,72,139,133,233,72,133,192,15,132,244,247,252,255,208,133,192,15, + 132,244,21,248,1,255,252,255,149,233,133,192,15,132,244,21,72,49,192,252, + 233,244,13,248,22,76,137,208,77,137,252,250,73,137,199,132,252,255,15,132, + 244,15,248,19,132,219,15,132,244,18,72,199,192,237,252,233,244,13,248,18, + 72,199,192,237,248,13,76,137,151,233,77,137,178,233,76,137,191,233,255,77, + 49,252,246,77,137,183,233,89,65,91,91,65,89,93,65,90,65,92,90,65,93,65,88, + 65,95,65,94,195,255,248,10,184,1,0,0,0,195,255,132,252,255,15,132,244,247, + 255,65,128,252,251,235,15,133,244,247,248,2,255,138,165,233,255,48,192,252, + 233,244,250,248,3,176,1,248,4,48,224,255,184,1,0,0,0,195,248,1,49,192,195, + 255 +}; + +# 11 "src/sregex/sre_vm_thompson_x64.dasc" + +//|.globals SRE_VM_THOMPSON_GLOB_ +enum { + SRE_VM_THOMPSON_GLOB_match, + SRE_VM_THOMPSON_GLOB_not_first_buf, + SRE_VM_THOMPSON_GLOB_first_buf, + SRE_VM_THOMPSON_GLOB_return, + SRE_VM_THOMPSON_GLOB_sp_loop_start, + SRE_VM_THOMPSON_GLOB_sp_loop_next, + SRE_VM_THOMPSON_GLOB_buf_consumed, + SRE_VM_THOMPSON_GLOB_run_cur_threads, + SRE_VM_THOMPSON_GLOB_again, + SRE_VM_THOMPSON_GLOB_done, + SRE_VM_THOMPSON_GLOB_run_thread, + SRE_VM_THOMPSON_GLOB_run_next_thread, + SRE_VM_THOMPSON_GLOB_run_threads_done, + SRE_VM_THOMPSON_GLOB__MAX +}; +# 13 "src/sregex/sre_vm_thompson_x64.dasc" + +#if (DDEBUG) +//|.globalnames sre_vm_thompson_jit_global_names +static const char *const sre_vm_thompson_jit_global_names[] = { + "match", + "not_first_buf", + "first_buf", + "return", + "sp_loop_start", + "sp_loop_next", + "buf_consumed", + "run_cur_threads", + "again", + "done", + "run_thread", + "run_next_thread", + "run_threads_done", + (const char *)0 +}; +# 16 "src/sregex/sre_vm_thompson_x64.dasc" +#endif + +/* thread count */ +//|.define TC, r14 // callee-save + +/* seen word */ +//|.define SW, r13 // callee-save + +/* string pointer */ +//|.define SP, r12 // callee-save + +//|.define LAST, rdx // overriding 3rd arg +//|.define INPUT, rsi // 2nd arg +//|.define EOF, bl // 4th arg + +/* seen last byte */ +//|.define LB, bh + +/* current input string byte */ +//|.define C, r11b + +/* the position after the last thread */ +//|.define LT, r9 + +/* recording threads added */ +//|.define ADDED, rcx + +//|.type CTX, sre_vm_thompson_ctx_t, rdi // 1st arg +#define Dt1(_V) (int)(ptrdiff_t)&(((sre_vm_thompson_ctx_t *)0)_V) +# 44 "src/sregex/sre_vm_thompson_x64.dasc" +//|.type TL, sre_vm_thompson_thread_list_t, r15 // callee-save +#define Dt2(_V) (int)(ptrdiff_t)&(((sre_vm_thompson_thread_list_t *)0)_V) +# 45 "src/sregex/sre_vm_thompson_x64.dasc" +//|.type T, sre_vm_thompson_thread_t, r8 // callee-save +#define Dt3(_V) (int)(ptrdiff_t)&(((sre_vm_thompson_thread_t *)0)_V) +# 46 "src/sregex/sre_vm_thompson_x64.dasc" +//|.type CT, sre_vm_thompson_thread_t, rbp // callee-save +#define Dt4(_V) (int)(ptrdiff_t)&(((sre_vm_thompson_thread_t *)0)_V) +# 47 "src/sregex/sre_vm_thompson_x64.dasc" + +/* current thread list */ +//|.type CTL, sre_vm_thompson_thread_list_t, r10 // callee-save +#define Dt5(_V) (int)(ptrdiff_t)&(((sre_vm_thompson_thread_list_t *)0)_V) +# 50 "src/sregex/sre_vm_thompson_x64.dasc" + +//|.macro addThreadWithoutCheck, target +//| +//||if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { +//| mov T->seen_word, al +//||} +//| +//| lea rax, [target] +//| mov T->pc, rax +//| +//||if (jit->program->lookahead_asserts) { +//|| if (asserts) { +//| +//| lea rax, [=>(jit->program->len + asserts - 1)] +//| mov T->asserts_handler, rax +//| +//|| } else { +//| xor rax, rax +//| mov T->asserts_handler, rax +//|| } +//||} +//| +//| add TC, 1 +//| +//||if (n != path->nthreads) { +//| add T, #T +//||} +//| +//|.endmacro + + +//|.macro addThreadWithCheck, target +//| +//||if (jit->threads_added_in_memory) { +//|| if (tid / 64 != prev_word) { +//|| prev_word = tid / 64; +//| mov ADDED, CTX->threads_added[(tid / 64)] +//|| } +//| +//|| bofs = tid % 64; +//| +//||} else { +//|| bofs = tid; +//||} +//| +//| bts ADDED, (bofs) // load CF with the bit and set the bit +//| jb >2 // jump if CF = 1 +//| +//||if (jit->threads_added_in_memory) { +//| mov CTX->threads_added[(tid / 64)], ADDED +//||} +//| +//||if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { +//| mov T->seen_word, al +//||} +//| +//| lea rax, [target] +//| mov T->pc, rax +//| +//||if (jit->program->lookahead_asserts) { +//|| if (asserts) { +//| lea rax, [=>(jit->program->len + asserts - 1)] +//| mov T->asserts_handler, rax +//| +//|| } else { +//| xor rax, rax +//| mov T->asserts_handler, rax +//|| } +//||} +//| +//| add TC, 1 +//| +//||if (n != path->nthreads) { +//| add T, #T +//||} +//| +//|2: +//| +//|.endmacro + + +//|.macro testWordChar +//||if (!char_always_valid) { +//| test LB, LB +//| jnz >2 +//||} +//| cmp C, byte '0' +//| jb >2 +//| cmp C, byte '9' +//| jbe >3 +//| cmp C, byte 'A' +//| jb >2 +//| cmp C, byte 'Z' +//| jbe >3 +//| cmp C, byte 'a' +//| jb >2 +//| cmp C, byte 'z' +//| jbe >3 +//| cmp C, byte '_' +//| je >3 +//|2: +//| // not word +//| xor al, al +//| jmp >4 +//|3: +//| // word +//| mov al, 1 +//|4: +//|.endmacro + + +/* This affects the "|" DynASM lines. */ +#define Dst dasm + + +#include +#include +#include +#include +#include + + +typedef struct sre_vm_thompson_path_s sre_vm_thompson_path_t; + +typedef struct { + sre_pool_t *pool; + sre_program_t *program; + dasm_State **dasm; + unsigned tag; + unsigned thread_index_factor; + + uint8_t *bc_accessed; /* TODO: use a sparse or bit array here */ + int *dup_thread_ids; /* TODO: use a sparse array here */ + unsigned threads_added_in_memory; /* 1: use ctx->threads_added; + 0: use the CPU register + ADDED only */ + + sre_vm_thompson_path_t *path; +} sre_vm_thompson_jit_t; + + +typedef struct sre_vm_thompson_state_s sre_vm_thompson_state_t; + +struct sre_vm_thompson_state_s { + unsigned asserts; + unsigned thread_index; + unsigned is_thread; + sre_instruction_t *bc; + sre_vm_thompson_state_t *next; +}; + + +struct sre_vm_thompson_path_s { + unsigned nthreads; + sre_instruction_t *from; + sre_vm_thompson_state_t *to; + sre_vm_thompson_path_t *next; +}; + + +static sre_int_t sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + sre_vm_thompson_path_t *path); +static sre_int_t sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit); +static sre_int_t sre_vm_thompson_jit_get_next_states(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, sre_vm_thompson_state_t ***plast_state, + unsigned *nthreads, unsigned asserts); +static sre_int_t sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit); +static sre_int_t sre_vm_thompson_jit_build_paths(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, sre_vm_thompson_path_t ***plast_path); +static unsigned sre_vm_thompson_jit_gen_thread_index(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, unsigned asserts); + + +SRE_NOAPI sre_int_t +sre_vm_thompson_jit_do_compile(dasm_State **dasm, sre_pool_t *pool, + sre_program_t *prog) +{ + unsigned i, n, count; + sre_vm_thompson_jit_t jit; + sre_vm_thompson_path_t *path, **last_path; + + jit.pool = pool; + jit.program = prog; + jit.dasm = dasm; + + jit.bc_accessed = sre_pcalloc(pool, prog->len); + if (jit.bc_accessed == NULL) { + return SRE_ERROR; + } + + jit.thread_index_factor = (SRE_REGEX_ASSERT_LOOKAHEAD + 1); + + dd("prog len: %d", (int) prog->len); + dd("thread index factor: %d", (int) jit.thread_index_factor); + + count = prog->len * jit.thread_index_factor; + dd("thread index count: %d", (int) count); + + jit.dup_thread_ids = sre_pcalloc(pool, count * sizeof(int)); + if (jit.dup_thread_ids == NULL) { + return SRE_ERROR; + } + + jit.path = NULL; + last_path = &jit.path; + + if (sre_vm_thompson_jit_build_paths(&jit, prog->start, &last_path) + != SRE_OK) + { + return SRE_ERROR; + } + + dd("first path: %p, pc: %d", jit.path, + (int) (jit.path->from - jit.program->start)); + + n = 0; + for (i = 0; i < count; i++) { + if (jit.dup_thread_ids[i] > 0) { + dd("found unique thread at pc %d, ref count: %d", + (int) (i / jit.thread_index_factor), (int) jit.dup_thread_ids[i]); + + prog->uniq_threads++; + + if (jit.dup_thread_ids[i] > 1) { + dd("found duplicatable thread at pc %d, ref count: %d", + (int) (i / jit.thread_index_factor), (int) jit.dup_thread_ids[i]); + + jit.dup_thread_ids[i] = n++; + continue; + } + } + + jit.dup_thread_ids[i] = -1; + } + + prog->dup_threads = n; + + dd("unique threads: %u, duplicatable threads: %u", + prog->uniq_threads, prog->dup_threads); + + jit.threads_added_in_memory = (prog->dup_threads > 64); + +#if 0 + jit.threads_added_in_memory = 1; +#endif + + n = prog->len + prog->lookahead_asserts; + + dd("growing pc label to %d, prog len: %d", n, (int) prog->len); + dasm_growpc(dasm, n); + + if (sre_vm_thompson_jit_prologue(&jit) != SRE_OK) { + return SRE_ERROR; + } + + for (path = jit.path; path; path = path->next) { + + dd("compiling path %p with pc %d", path, + (int) (path->from - jit.program->start)); + + if (sre_vm_thompson_jit_compile_path(&jit, path) != SRE_OK) { + return SRE_ERROR; + } + } + + if (sre_vm_thompson_jit_epilogue(&jit) != SRE_OK) { + return SRE_ERROR; + } + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_build_paths(sre_vm_thompson_jit_t *jit, sre_instruction_t *pc, + sre_vm_thompson_path_t ***plast_path) +{ + sre_vm_thompson_path_t *path; + sre_vm_thompson_state_t *state, **last_state; + + jit->bc_accessed[pc - jit->program->start] = 1; + + path = sre_pcalloc(jit->pool, sizeof(sre_vm_thompson_path_t)); + if (path == NULL) { + return SRE_ERROR; + } + + dd("build path from pc %d", (int) (pc - jit->program->start)); + + path->from = pc; + last_state = &path->to; + jit->tag = jit->program->tag + 1; + + if (pc == jit->program->start) { + if (sre_vm_thompson_jit_get_next_states(jit, pc, &last_state, + &path->nthreads, 0) + != SRE_OK) + { + jit->program->tag = jit->tag; + return SRE_ERROR; + } + + } else { + if (pc + 1 >= jit->program->start + jit->program->len) { + jit->program->tag = jit->tag; + return SRE_ERROR; + } + + if (sre_vm_thompson_jit_get_next_states(jit, pc + 1, &last_state, + &path->nthreads, 0) + != SRE_OK) + { + jit->program->tag = jit->tag; + return SRE_ERROR; + } + } + + jit->program->tag = jit->tag; + + if (path->to == NULL) { + return SRE_ERROR; + } + + **plast_path = path; + *plast_path = &path->next; + + for (state = path->to; state; state = state->next) { + if (state->bc->opcode == SRE_OPCODE_MATCH) { + continue; + } + + if (jit->bc_accessed[state->bc - jit->program->start]) { + continue; + } + + if (sre_vm_thompson_jit_build_paths(jit, state->bc, + plast_path) + != SRE_OK) + { + return SRE_ERROR; + } + } + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_compile_path(sre_vm_thompson_jit_t *jit, + sre_vm_thompson_path_t *path) +{ + sre_char c; + unsigned i, n, asserts, char_always_valid = 1; + int tid, prev_word; + unsigned bofs; + sre_int_t ofs; + dasm_State **dasm; + sre_vm_range_t *range; + sre_instruction_t *bc, *pc; + + sre_vm_thompson_state_t *state; + + dasm = jit->dasm; + pc = path->from; + ofs = pc - jit->program->start; + + if (dasm_getpclabel(dasm, ofs) >= 0) { + dd("bc %d already compiled", (int) ofs); + return SRE_ERROR; + } + + dd("compiling path at pc %d", (int) (pc - jit->program->start)); + + //|=>(ofs): + dasm_put(Dst, 0, (ofs)); +# 424 "src/sregex/sre_vm_thompson_x64.dasc" + + switch (pc->opcode) { + case SRE_OPCODE_ANY: + //| test LB, LB + //| jnz >1 + dasm_put(Dst, 2); +# 429 "src/sregex/sre_vm_thompson_x64.dasc" + + break; + + case SRE_OPCODE_CHAR: + c = pc->v.ch; + + //| test LB, LB + //| jnz >1 + //| + //| cmp C, byte (c) + //| jne >1 + dasm_put(Dst, 10, (c)); +# 440 "src/sregex/sre_vm_thompson_x64.dasc" + + break; + + case SRE_OPCODE_IN: + //| test LB, LB + //| jnz >1 + dasm_put(Dst, 2); +# 446 "src/sregex/sre_vm_thompson_x64.dasc" + + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + dd("compile opcode IN: [%d, %d] (%u)", (int) range->from, + (int) range->to, (unsigned) i); + + if (range->from == range->to) { + //| cmp C, byte (range->from) + //| je >2 + dasm_put(Dst, 27, (range->from)); +# 456 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + if (range->from != 0x00) { + //| cmp C, byte (range->from) + //| jb >3 + dasm_put(Dst, 37, (range->from)); +# 461 "src/sregex/sre_vm_thompson_x64.dasc" + } + + if (range->to == 0xff) { + //| jmp >2 + dasm_put(Dst, 47); +# 465 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + //| cmp C, byte (range->to) + //| jbe >2 + dasm_put(Dst, 52, (range->to)); +# 469 "src/sregex/sre_vm_thompson_x64.dasc" + } + + //|3: + dasm_put(Dst, 62); +# 472 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + + //| jmp >1 + //|2: + dasm_put(Dst, 65); +# 477 "src/sregex/sre_vm_thompson_x64.dasc" + + break; + + case SRE_OPCODE_NOTIN: + //| test LB, LB + //| jnz >1 + dasm_put(Dst, 2); +# 483 "src/sregex/sre_vm_thompson_x64.dasc" + + for (i = 0; i < pc->v.ranges->count; i++) { + range = &pc->v.ranges->head[i]; + + dd("compile opcode IN: [%d, %d] (%u)", (int) range->from, + (int) range->to, (unsigned) i); + + if (range->from == range->to) { + //| cmp C, byte (range->from) + //| je >1 + dasm_put(Dst, 72, (range->from)); +# 493 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + if (range->from != 0x00) { + //| cmp C, byte (range->from) + //| jb >2 + dasm_put(Dst, 82, (range->from)); +# 498 "src/sregex/sre_vm_thompson_x64.dasc" + } + + if (range->to == 0xff) { + //| jmp >1 + dasm_put(Dst, 92); +# 502 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + //| cmp C, byte (range->to) + //| jbe >1 + dasm_put(Dst, 97, (range->to)); +# 506 "src/sregex/sre_vm_thompson_x64.dasc" + } + + if (range->from != 0x00) { + //|2: + dasm_put(Dst, 69); +# 510 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + } + + break; + + default: + /* do nothing */ + break; + } + + prev_word = -1; + n = 0; + for (state = path->to; state; state = state->next) { + bc = state->bc; + asserts = state->asserts; + + if (state->is_thread) { + n++; + + if (n == 1) { + //| imul rax, TC, #T // thread index offset + //| lea T, [TL + rax + offsetof(sre_vm_thompson_thread_list_t, threads)] + dasm_put(Dst, 107, sizeof(sre_vm_thompson_thread_t), offsetof(sre_vm_thompson_thread_list_t, threads)); +# 533 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + + if (asserts) { + if (asserts & SRE_REGEX_ASSERT_BIG_A) { + asserts &= ~SRE_REGEX_ASSERT_BIG_A; + + if (pc != jit->program->start) { + /* assertion always does not hold */ + continue; + } + + /* assertion always holds when pc == jit->program->start */ + } + + if (asserts & SRE_REGEX_ASSERT_CARET) { + asserts &= ~SRE_REGEX_ASSERT_CARET; + + /* assertion always holds when pc == jit->program->start */ + + if (pc != jit->program->start) { + //| cmp C, byte '\n' + //| jne >9 + dasm_put(Dst, 118, '\n'); +# 556 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + + if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + if (pc == jit->program->start) { + //| xor al, al + dasm_put(Dst, 128); +# 562 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + //| testWordChar + if (!char_always_valid) { + dasm_put(Dst, 131); + } + dasm_put(Dst, 139, '0', '9', 'A', 'Z', 'a', 'z', '_'); + dasm_put(Dst, 205); +# 565 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + } + + if (bc->opcode == SRE_OPCODE_MATCH) { + + dd("seen a match bc: %d, len: %d", + (int) (bc - jit->program->start), (int) jit->program->len); + + if (asserts) { + ofs = bc - jit->program->start; + tid = jit->dup_thread_ids[state->thread_index]; + + dd("compiling asserts for match: %d", asserts); + + if (tid >= 0 && pc != jit->program->start) { + //| addThreadWithCheck ->match + if (jit->threads_added_in_memory) { + if (tid / 64 != prev_word) { + prev_word = tid / 64; + dasm_put(Dst, 218, Dt1(->threads_added[(tid / 64)])); + } + bofs = tid % 64; + } else { + bofs = tid; + } + dasm_put(Dst, 223, (bofs)); + if (jit->threads_added_in_memory) { + dasm_put(Dst, 234, Dt1(->threads_added[(tid / 64)])); + } + if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + dasm_put(Dst, 239, Dt3(->seen_word)); + } + dasm_put(Dst, 244, Dt3(->pc)); + if (jit->program->lookahead_asserts) { + if (asserts) { + dasm_put(Dst, 254, (jit->program->len + asserts - 1), Dt3(->asserts_handler)); + } else { + dasm_put(Dst, 263, Dt3(->asserts_handler)); + } + } + dasm_put(Dst, 271); + if (n != path->nthreads) { + dasm_put(Dst, 276, sizeof(sre_vm_thompson_thread_t)); + } + dasm_put(Dst, 69); +# 582 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + dd("seen a non thread entry match at bc %d", (int) ofs); + + //| addThreadWithoutCheck ->match + if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + dasm_put(Dst, 239, Dt3(->seen_word)); + } + dasm_put(Dst, 244, Dt3(->pc)); + if (jit->program->lookahead_asserts) { + if (asserts) { + dasm_put(Dst, 254, (jit->program->len + asserts - 1), Dt3(->asserts_handler)); + } else { + dasm_put(Dst, 263, Dt3(->asserts_handler)); + } + } + dasm_put(Dst, 271); + if (n != path->nthreads) { + dasm_put(Dst, 276, sizeof(sre_vm_thompson_thread_t)); + } +# 587 "src/sregex/sre_vm_thompson_x64.dasc" + } + + } else { + //| mov eax, 1 + //| ret + dasm_put(Dst, 281); +# 592 "src/sregex/sre_vm_thompson_x64.dasc" + } + + } else { + /* being bytecode ANY, CHAR, IN, or NOTIN */ + + ofs = bc - jit->program->start; + tid = jit->dup_thread_ids[state->thread_index]; + + if (tid >= 0 && pc != jit->program->start) { + dd("seen a thread entry bc at bc %d, id=%d", (int) ofs, + (int) tid); + + //| addThreadWithCheck =>(ofs) + if (jit->threads_added_in_memory) { + if (tid / 64 != prev_word) { + prev_word = tid / 64; + dasm_put(Dst, 218, Dt1(->threads_added[(tid / 64)])); + } + bofs = tid % 64; + } else { + bofs = tid; + } + dasm_put(Dst, 223, (bofs)); + if (jit->threads_added_in_memory) { + dasm_put(Dst, 234, Dt1(->threads_added[(tid / 64)])); + } + if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + dasm_put(Dst, 239, Dt3(->seen_word)); + } + dasm_put(Dst, 254, (ofs), Dt3(->pc)); + if (jit->program->lookahead_asserts) { + if (asserts) { + dasm_put(Dst, 254, (jit->program->len + asserts - 1), Dt3(->asserts_handler)); + } else { + dasm_put(Dst, 263, Dt3(->asserts_handler)); + } + } + dasm_put(Dst, 271); + if (n != path->nthreads) { + dasm_put(Dst, 276, sizeof(sre_vm_thompson_thread_t)); + } + dasm_put(Dst, 69); +# 605 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + dd("seen a non thread entry bc at bc %d", (int) ofs); + //| addThreadWithoutCheck =>(ofs) + if (asserts & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + dasm_put(Dst, 239, Dt3(->seen_word)); + } + dasm_put(Dst, 254, (ofs), Dt3(->pc)); + if (jit->program->lookahead_asserts) { + if (asserts) { + dasm_put(Dst, 254, (jit->program->len + asserts - 1), Dt3(->asserts_handler)); + } else { + dasm_put(Dst, 263, Dt3(->asserts_handler)); + } + } + dasm_put(Dst, 271); + if (n != path->nthreads) { + dasm_put(Dst, 276, sizeof(sre_vm_thompson_thread_t)); + } +# 609 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + + //|9: + dasm_put(Dst, 288); +# 613 "src/sregex/sre_vm_thompson_x64.dasc" + } /* for */ + + //|1: + //| xor eax, eax + //| ret + dasm_put(Dst, 291); +# 618 "src/sregex/sre_vm_thompson_x64.dasc" + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_get_next_states(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, sre_vm_thompson_state_t ***plast_state, + unsigned *nthreads, unsigned asserts) +{ + sre_vm_thompson_state_t *state; + + if (pc->tag == jit->tag) { + return SRE_OK; + } + + pc->tag = jit->tag; + + switch (pc->opcode) { + case SRE_OPCODE_SPLIT: + if (sre_vm_thompson_jit_get_next_states(jit, pc->x, plast_state, + nthreads, asserts) + != SRE_OK) + { + return SRE_ERROR; + } + + return sre_vm_thompson_jit_get_next_states(jit, pc->y, plast_state, + nthreads, asserts); + + case SRE_OPCODE_JMP: + return sre_vm_thompson_jit_get_next_states(jit, pc->x, plast_state, + nthreads, asserts); + + case SRE_OPCODE_SAVE: + if (++pc == jit->program->start + jit->program->len) { + return SRE_OK; + } + + return sre_vm_thompson_jit_get_next_states(jit, pc, plast_state, + nthreads, asserts); + + case SRE_OPCODE_MATCH: + dd("seen match bc %d, asserts %d", + (int) (pc - jit->program->start), (int) asserts); + + state = sre_pcalloc(jit->pool, sizeof(sre_vm_thompson_state_t)); + if (state == NULL) { + return SRE_ERROR; + } + + state->asserts = asserts; + state->bc = pc; + state->thread_index = sre_vm_thompson_jit_gen_thread_index(jit, pc, + asserts); + + if (asserts & SRE_REGEX_ASSERT_LOOKAHEAD) { + jit->dup_thread_ids[state->thread_index]++; + + state->is_thread = 1; + (*nthreads)++; + } + + **plast_state = state; + *plast_state = &state->next; + + return SRE_OK; + + case SRE_OPCODE_ASSERT: + dd("seen assert bc at %d", (int) (pc - jit->program->start)); + + asserts |= pc->v.assertion; + + jit->program->lookahead_asserts |= (asserts & SRE_REGEX_ASSERT_LOOKAHEAD); + + if (++pc == jit->program->start + jit->program->len) { + return SRE_OK; + } + + return sre_vm_thompson_jit_get_next_states(jit, pc, plast_state, + nthreads, asserts); + + default: + /* CHAR, ANY, IN, NOTIN */ + + state = sre_pcalloc(jit->pool, sizeof(sre_vm_thompson_state_t)); + if (state == NULL) { + return SRE_ERROR; + } + + state->asserts = asserts; + state->bc = pc; + state->thread_index = sre_vm_thompson_jit_gen_thread_index(jit, pc, + asserts); + + jit->dup_thread_ids[state->thread_index]++; + state->is_thread = 1; + + **plast_state = state; + *plast_state = &state->next; + + (*nthreads)++; + + dd("seen terminal bc: %d", (int) (pc - jit->program->start)); + return SRE_OK; + } + + /* impossible to reach here */ +} + + +static unsigned +sre_vm_thompson_jit_gen_thread_index(sre_vm_thompson_jit_t *jit, + sre_instruction_t *pc, unsigned asserts) +{ + return (pc - jit->program->start) * jit->thread_index_factor + + (asserts & SRE_REGEX_ASSERT_LOOKAHEAD); +} + + +static sre_int_t +sre_vm_thompson_jit_prologue(sre_vm_thompson_jit_t *jit) +{ + size_t size; + dasm_State **dasm; + + dasm = jit->dasm; + + //| push TC; push TL; push T; push SW; push LAST; push SP; + //| push CTL; push CT; push LT; push rbx; push r11; push ADDED + //| + //| // check the 4th arg, "eof" + //| test ecx, ecx + //| jz >1 + //| mov EOF, 1 + //| jmp >2 + //| + //|1: + //| xor EOF, EOF + //| + //|2: + //| mov CTL, CTX->current_threads + //| mov TC, CTL->count + //| xor LB, LB + //| + //| mov al, CTX->first_buf + //| test al, al + //| jz ->not_first_buf + //| + //|->first_buf: + //| mov byte CTX->first_buf, 0 + //| + //| mov TL, CTL + //| xor SW, SW + //| call =>0 + //| test eax, eax + //| jz ->not_first_buf + //| xor rax, rax // (SRE_OK) + //| jmp ->return + //| + //|->not_first_buf: + //| add LAST, INPUT // last = input + size + dasm_put(Dst, 297, Dt1(->current_threads), Dt5(->count), Dt1(->first_buf), Dt1(->first_buf), 0); +# 780 "src/sregex/sre_vm_thompson_x64.dasc" + //| mov TL, CTX->next_threads + //| mov SP, INPUT + //| + //| jmp ->sp_loop_start + //| + //|->sp_loop_next: + //| add SP, 1 + //| + //|->sp_loop_start: + //| cmp SP, LAST + //| je ->buf_consumed + //| + //| // sp != last + //| mov C, byte [SP] + //| jmp ->run_cur_threads + //| + //|->buf_consumed: + //| test EOF, EOF + //| jz ->again + //| mov LB, 1 + //| + //|->run_cur_threads: + //| test TC, TC + //| jz ->done + //| + dasm_put(Dst, 386, Dt1(->next_threads)); +# 805 "src/sregex/sre_vm_thompson_x64.dasc" + + if (jit->threads_added_in_memory) { + size = sre_vm_thompson_jit_get_threads_added_size(jit->program); + + /* clear the CTX->threads_added bit array */ + + //| // rcx is for ADDED, and r8 is for T + //| lea r8, CTX->threads_added + //| xor rax, rax + //| mov rcx, (size / 8) + //|1: + //| mov qword [r8], rax + //| add r8, 8 + //| dec rcx + //| jnz <1 + dasm_put(Dst, 446, Dt1(->threads_added), (size / 8)); +# 820 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + //| xor ADDED, ADDED + dasm_put(Dst, 475); +# 823 "src/sregex/sre_vm_thompson_x64.dasc" + } + + //| imul rax, TC, #T // thread index offset + //| lea LT, [CTL + rax + offsetof(sre_vm_thompson_thread_list_t, threads)] + //| lea CT, [CTL + offsetof(sre_vm_thompson_thread_list_t, threads)] + //| xor TC, TC + //| jmp ->run_thread + //| + //|->run_next_thread: + //| add CT, #T + //| + //|->run_thread: + //| cmp CT, LT + //| je ->run_threads_done + //| + dasm_put(Dst, 479, sizeof(sre_vm_thompson_thread_t), offsetof(sre_vm_thompson_thread_list_t, threads), offsetof(sre_vm_thompson_thread_list_t, threads), sizeof(sre_vm_thompson_thread_t)); +# 838 "src/sregex/sre_vm_thompson_x64.dasc" + + if (jit->program->lookahead_asserts) { + //| mov rax, CT->asserts_handler + //| test rax, rax + //| jz >1 + //| call rax + //| test eax, eax + //| jz ->run_next_thread + //| + //|1: + dasm_put(Dst, 517, Dt4(->asserts_handler)); +# 848 "src/sregex/sre_vm_thompson_x64.dasc" + } + + //| call aword CT->pc + //| + //| test eax, eax + //| jz ->run_next_thread + //| + //| // matched + //| xor rax, rax // (SRE_OK) + //| jmp ->return + //| + //|->run_threads_done: + //| mov rax, CTL + //| mov CTL, TL + //| mov TL, rax + //| + //| test LB, LB + //| jz ->sp_loop_next + //| + //|->done: + //| test EOF, EOF + //| jz ->again + //| mov rax, (SRE_DECLINED) + //| jmp ->return + //| + //|->again: + //| mov rax, (SRE_AGAIN) + //| + //|->return: + //| mov CTX->current_threads, CTL + //| mov CTL->count, TC + //| + //| mov CTX->next_threads, TL + //| xor TC, TC + dasm_put(Dst, 540, Dt4(->pc), (SRE_DECLINED), (SRE_AGAIN), Dt1(->current_threads), Dt5(->count), Dt1(->next_threads)); +# 882 "src/sregex/sre_vm_thompson_x64.dasc" + //| mov TL->count, TC + //| + //| pop ADDED; pop r11; pop rbx; pop LT; pop CT; pop CTL; + //| pop SP; pop LAST; pop SW; pop T; pop TL; pop TC + //| ret + dasm_put(Dst, 613, Dt2(->count)); +# 887 "src/sregex/sre_vm_thompson_x64.dasc" + + return SRE_OK; +} + + +static sre_int_t +sre_vm_thompson_jit_epilogue(sre_vm_thompson_jit_t *jit) +{ + unsigned flags, char_always_valid = 0; + sre_uint_t len; + dasm_State **dasm; + + if (jit->program->lookahead_asserts) { + + dasm = jit->dasm; + len = jit->program->len; + + //|->match: + //| mov eax, 1 + //| ret + dasm_put(Dst, 643); +# 907 "src/sregex/sre_vm_thompson_x64.dasc" + + for (flags = 1; flags <= SRE_REGEX_ASSERT_LOOKAHEAD; flags++) { + + if ((flags & jit->program->lookahead_asserts) != flags) { + continue; + } + + //|=>(len + flags - 1): + dasm_put(Dst, 0, (len + flags - 1)); +# 915 "src/sregex/sre_vm_thompson_x64.dasc" + + if (flags & SRE_REGEX_ASSERT_SMALL_Z) { + //| test LB, LB + //| jz >1 + dasm_put(Dst, 652); +# 919 "src/sregex/sre_vm_thompson_x64.dasc" + } + + if (flags & SRE_REGEX_ASSERT_DOLLAR) { + if (!(flags & SRE_REGEX_ASSERT_SMALL_Z)) { + //| test LB, LB + //| jnz >2 + dasm_put(Dst, 131); +# 925 "src/sregex/sre_vm_thompson_x64.dasc" + } + + //| cmp C, '\n' + //| jne >1 + //|2: + dasm_put(Dst, 660, '\n'); +# 930 "src/sregex/sre_vm_thompson_x64.dasc" + } + + if (flags & SRE_REGEX_ASSERT_WORD_BOUNDARY) { + //| mov ah, byte CT->seen_word + //| testWordChar + dasm_put(Dst, 672, Dt4(->seen_word)); + if (!char_always_valid) { + dasm_put(Dst, 131); + } + dasm_put(Dst, 139, '0', '9', 'A', 'Z', 'a', 'z', '_'); +# 935 "src/sregex/sre_vm_thompson_x64.dasc" + //| xor al, ah + dasm_put(Dst, 676); +# 936 "src/sregex/sre_vm_thompson_x64.dasc" + + if (flags & SRE_REGEX_ASSERT_SMALL_B) { + //| jz >1 + dasm_put(Dst, 77); +# 939 "src/sregex/sre_vm_thompson_x64.dasc" + + } else { + /* SRE_REGEX_ASSERT_BIG_B */ + //| jnz >1 + dasm_put(Dst, 5); +# 943 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + + //| mov eax, 1 + //| ret + //|1: + //| xor eax, eax + //| ret + dasm_put(Dst, 691); +# 951 "src/sregex/sre_vm_thompson_x64.dasc" + } + } + + return SRE_OK; +} diff --git a/lib/sregex/src/sregex/sre_yyparser.c b/lib/sregex/src/sregex/sre_yyparser.c new file mode 100644 index 0000000..d62d3fc --- /dev/null +++ b/lib/sregex/src/sregex/sre_yyparser.c @@ -0,0 +1,3635 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison implementation for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "3.0.4" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 1 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + + +/* Substitute the variable and function names. */ +#define yyparse sregex_yyparse +#define yylex sregex_yylex +#define yyerror sregex_yyerror +#define yydebug sregex_yydebug +#define yynerrs sregex_yynerrs + + +/* Copy the first part of user declarations. */ +#line 10 "src/sregex/sre_yyparser.y" + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include +#include + + +#define YYLTYPE YYLTYPE +typedef struct YYLTYPE { + sre_char *pos; + sre_char *last; +} YYLTYPE; + + +#define YYLLOC_DEFAULT(Cur, Rhs, N) \ + do { \ + if (N) { \ + (Cur).pos = YYRHSLOC(Rhs, 1).pos; \ + (Cur).last = YYRHSLOC(Rhs, N).last; \ + } else { \ + (Cur).pos = YYRHSLOC(Rhs, 0).last; \ + (Cur).last = (Cur).pos; \ + } \ + } while (0) + + +#include +#include + + +#define sre_read_char(sp) *(*(sp))++ + + +static int yylex(YYSTYPE *lvalp, YYLTYPE *locp, sre_pool_t *pool, + sre_char **src); +static void yyerror(YYLTYPE *locp, sre_pool_t *pool, sre_char **src, + sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos, + char *s); +static sre_regex_t *sre_regex_desugar_counted_repetition(sre_pool_t *pool, + sre_regex_t *subj, sre_regex_cquant_t *cquant, unsigned greedy); + + +#line 121 "src/sregex/sre_yyparser.c" + +# ifndef YY_NULLPTR +# if defined __cplusplus && 201103L <= __cplusplus +# define YY_NULLPTR nullptr +# else +# define YY_NULLPTR 0 +# endif +# endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* In a future release of Bison, this section will be replaced + by #include "sre_yyparser.h". */ +#ifndef YY_SREGEX_YY_SRC_SREGEX_SRE_YYPARSER_H_INCLUDED +# define YY_SREGEX_YY_SRC_SREGEX_SRE_YYPARSER_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int sregex_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + SRE_REGEX_TOKEN_CHAR = 258, + SRE_REGEX_TOKEN_EOF = 259, + SRE_REGEX_TOKEN_BAD = 260, + SRE_REGEX_TOKEN_CQUANT = 261, + SRE_REGEX_TOKEN_CHAR_CLASS = 262, + SRE_REGEX_TOKEN_ASSERTION = 263 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 82 "src/sregex/sre_yyparser.y" + + sre_regex_t *re; + sre_char ch; + sre_uint_t group; + sre_regex_cquant_t cquant; + +#line 177 "src/sregex/sre_yyparser.c" +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + +int sregex_yyparse (sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos); + +#endif /* !YY_SREGEX_YY_SRC_SREGEX_SRE_YYPARSER_H_INCLUDED */ + +/* Copy the second part of user declarations. */ + +#line 207 "src/sregex/sre_yyparser.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#else +typedef signed char yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T +# include /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if defined YYENABLE_NLS && YYENABLE_NLS +# if ENABLE_NLS +# include /* INFRINGES ON USER NAME SPACE */ +# define YY_(Msgid) dgettext ("bison-runtime", Msgid) +# endif +# endif +# ifndef YY_ +# define YY_(Msgid) Msgid +# endif +#endif + +#ifndef YY_ATTRIBUTE +# if (defined __GNUC__ \ + && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \ + || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C +# define YY_ATTRIBUTE(Spec) __attribute__(Spec) +# else +# define YY_ATTRIBUTE(Spec) /* empty */ +# endif +#endif + +#ifndef YY_ATTRIBUTE_PURE +# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__)) +#endif + +#ifndef YY_ATTRIBUTE_UNUSED +# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__)) +#endif + +#if !defined _Noreturn \ + && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112) +# if defined _MSC_VER && 1200 <= _MSC_VER +# define _Noreturn __declspec (noreturn) +# else +# define _Noreturn YY_ATTRIBUTE ((__noreturn__)) +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(E) ((void) (E)) +#else +# define YYUSE(E) /* empty */ +#endif + +#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__ +/* Suppress an incorrect diagnostic about yylval being uninitialized. */ +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \ + _Pragma ("GCC diagnostic push") \ + _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\ + _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"") +# define YY_IGNORE_MAYBE_UNINITIALIZED_END \ + _Pragma ("GCC diagnostic pop") +#else +# define YY_INITIAL_VALUE(Value) Value +#endif +#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN +# define YY_IGNORE_MAYBE_UNINITIALIZED_END +#endif +#ifndef YY_INITIAL_VALUE +# define YY_INITIAL_VALUE(Value) /* Nothing. */ +#endif + + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS +# include /* INFRINGES ON USER NAME SPACE */ + /* Use EXIT_SUCCESS as a witness for stdlib.h. */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's 'empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined EXIT_SUCCESS \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include /* INFRINGES ON USER NAME SPACE */ +# ifndef EXIT_SUCCESS +# define EXIT_SUCCESS 0 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined EXIT_SUCCESS +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined EXIT_SUCCESS +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL \ + && defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; + YYLTYPE yyls_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE) + sizeof (YYLTYPE)) \ + + 2 * YYSTACK_GAP_MAXIMUM) + +# define YYCOPY_NEEDED 1 + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (0) + +#endif + +#if defined YYCOPY_NEEDED && YYCOPY_NEEDED +/* Copy COUNT objects from SRC to DST. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(Dst, Src, Count) \ + __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src))) +# else +# define YYCOPY(Dst, Src, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (Dst)[yyi] = (Src)[yyi]; \ + } \ + while (0) +# endif +# endif +#endif /* !YYCOPY_NEEDED */ + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 16 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 30 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 19 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 7 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 26 +/* YYNSTATES -- Number of states. */ +#define YYNSTATES 34 + +/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned + by yylex, with out-of-bounds checking. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 263 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM + as returned by yylex, without out-of-bounds checking. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 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, 18, 2, 2, 2, + 13, 14, 10, 12, 2, 2, 16, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 15, 2, + 2, 2, 2, 11, 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, 17, 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, 9, 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, 1, 2, 3, 4, + 5, 6, 7, 8 +}; + +#if YYDEBUG + /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 103, 103, 111, 112, 122, 123, 131, 140, 141, + 152, 161, 172, 181, 192, 201, 210, 221, 225, 235, + 240, 289, 297, 307, 317, 318, 329 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || 0 +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "SRE_REGEX_TOKEN_CHAR", + "SRE_REGEX_TOKEN_EOF", "SRE_REGEX_TOKEN_BAD", "SRE_REGEX_TOKEN_CQUANT", + "SRE_REGEX_TOKEN_CHAR_CLASS", "SRE_REGEX_TOKEN_ASSERTION", "'|'", "'*'", + "'?'", "'+'", "'('", "')'", "':'", "'.'", "'^'", "'$'", "$accept", + "regex", "alt", "concat", "repeat", "count", "atom", YY_NULLPTR +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[NUM] -- (External) token number corresponding to the + (internal) symbol number NUM (which must be that of a token). */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 124, + 42, 63, 43, 40, 41, 58, 46, 94, 36 +}; +# endif + +#define YYPACT_NINF -14 + +#define yypact_value_is_default(Yystate) \ + (!!((Yystate) == (-14))) + +#define YYTABLE_NINF -1 + +#define yytable_value_is_error(Yytable_value) \ + 0 + + /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +static const yytype_int8 yypact[] = +{ + -3, -14, -14, -14, -5, -14, -14, -14, -14, 7, + -1, -3, -14, 11, -6, -3, -14, -14, -3, -14, + 9, 15, 17, 18, -3, 10, -3, -14, -14, -14, + -14, 16, -14, -14 +}; + + /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM. + Performed when YYTABLE does not specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 7, 20, 25, 24, 17, 26, 21, 22, 23, 0, + 0, 3, 5, 8, 0, 7, 1, 2, 7, 6, + 15, 9, 13, 11, 7, 0, 4, 16, 10, 14, + 12, 0, 18, 19 +}; + + /* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -14, -14, -13, 0, -10, -14, -14 +}; + + /* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 9, 10, 11, 12, 15, 13 +}; + + /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule whose + number is the opposite. If YYTABLE_NINF, syntax error. */ +static const yytype_uint8 yytable[] = +{ + 1, 19, 25, 17, 2, 3, 14, 16, 18, 24, + 4, 31, 5, 6, 7, 8, 19, 20, 26, 18, + 27, 21, 22, 23, 32, 18, 28, 0, 29, 30, + 33 +}; + +static const yytype_int8 yycheck[] = +{ + 3, 11, 15, 4, 7, 8, 11, 0, 9, 15, + 13, 24, 15, 16, 17, 18, 26, 6, 18, 9, + 11, 10, 11, 12, 14, 9, 11, -1, 11, 11, + 14 +}; + + /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 3, 7, 8, 13, 15, 16, 17, 18, 20, + 21, 22, 23, 25, 11, 24, 0, 4, 9, 23, + 6, 10, 11, 12, 15, 21, 22, 11, 11, 11, + 11, 21, 14, 14 +}; + + /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 19, 20, 21, 21, 22, 22, 22, 23, 23, + 23, 23, 23, 23, 23, 23, 23, 24, 25, 25, + 25, 25, 25, 25, 25, 25, 25 +}; + + /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 2, 1, 3, 1, 2, 0, 1, 2, + 3, 2, 3, 2, 3, 2, 3, 0, 4, 5, + 1, 1, 1, 1, 1, 1, 1 +}; + + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + YYPOPSTACK (yylen); \ + yystate = *yyssp; \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (&yylloc, pool, src, ncaps, flags, parsed, err_pos, YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (0) + +/* Error token number */ +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (N) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (0) +#endif + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) + + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (0) + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + +/* Print *YYLOCP on YYO. Private, do not rely on its existence. */ + +YY_ATTRIBUTE_UNUSED +static unsigned +yy_location_print_ (FILE *yyo, YYLTYPE const * const yylocp) +{ + unsigned res = 0; + int end_col = 0 != yylocp->last_column ? yylocp->last_column - 1 : 0; + if (0 <= yylocp->first_line) + { + res += YYFPRINTF (yyo, "%d", yylocp->first_line); + if (0 <= yylocp->first_column) + res += YYFPRINTF (yyo, ".%d", yylocp->first_column); + } + if (0 <= yylocp->last_line) + { + if (yylocp->first_line < yylocp->last_line) + { + res += YYFPRINTF (yyo, "-%d", yylocp->last_line); + if (0 <= end_col) + res += YYFPRINTF (yyo, ".%d", end_col); + } + else if (0 <= end_col && yylocp->first_column < end_col) + res += YYFPRINTF (yyo, "-%d", end_col); + } + return res; + } + +# define YY_LOCATION_PRINT(File, Loc) \ + yy_location_print_ (File, &(Loc)) + +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value, Location, pool, src, ncaps, flags, parsed, err_pos); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (0) + + +/*----------------------------------------. +| Print this symbol's value on YYOUTPUT. | +`----------------------------------------*/ + +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos) +{ + FILE *yyo = yyoutput; + YYUSE (yyo); + YYUSE (yylocationp); + YYUSE (pool); + YYUSE (src); + YYUSE (ncaps); + YYUSE (flags); + YYUSE (parsed); + YYUSE (err_pos); + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# endif + YYUSE (yytype); +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep, YYLTYPE const * const yylocationp, sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos) +{ + YYFPRINTF (yyoutput, "%s %s (", + yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]); + + YY_LOCATION_PRINT (yyoutput, *yylocationp); + YYFPRINTF (yyoutput, ": "); + yy_symbol_value_print (yyoutput, yytype, yyvaluep, yylocationp, pool, src, ncaps, flags, parsed, err_pos); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (0) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +static void +yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, YYLTYPE *yylsp, int yyrule, sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos) +{ + unsigned long int yylno = yyrline[yyrule]; + int yynrhs = yyr2[yyrule]; + int yyi; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, + yystos[yyssp[yyi + 1 - yynrhs]], + &(yyvsp[(yyi + 1) - (yynrhs)]) + , &(yylsp[(yyi + 1) - (yynrhs)]) , pool, src, ncaps, flags, parsed, err_pos); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyssp, yyvsp, yylsp, Rule, pool, src, ncaps, flags, parsed, err_pos); \ +} while (0) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +static YYSIZE_T +yystrlen (const char *yystr) +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +static char * +yystpcpy (char *yydest, const char *yysrc) +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message + about the unexpected token YYTOKEN for the state stack whose top is + YYSSP. + + Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is + not large enough to hold the message. In that case, also set + *YYMSG_ALLOC to the required number of bytes. Return 2 if the + required number of bytes is too large to store. */ +static int +yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg, + yytype_int16 *yyssp, int yytoken) +{ + YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]); + YYSIZE_T yysize = yysize0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + /* Internationalized format string. */ + const char *yyformat = YY_NULLPTR; + /* Arguments of yyformat. */ + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + /* Number of reported tokens (one for the "unexpected", one per + "expected"). */ + int yycount = 0; + + /* There are many possibilities here to consider: + - If this state is a consistent state with a default action, then + the only way this function was invoked is if the default action + is an error action. In that case, don't check for expected + tokens because there are none. + - The only way there can be no lookahead present (in yychar) is if + this state is a consistent state with a default action. Thus, + detecting the absence of a lookahead is sufficient to determine + that there is no unexpected or expected token to report. In that + case, just report a simple "syntax error". + - Don't assume there isn't a lookahead just because this state is a + consistent state with a default action. There might have been a + previous inconsistent state, consistent state with a non-default + action, or user semantic action that manipulated yychar. + - Of course, the expected token list depends on states to have + correct lookahead information, and it depends on the parser not + to perform extra reductions after fetching a lookahead from the + scanner and before detecting a syntax error. Thus, state merging + (from LALR or IELR) and default reductions corrupt the expected + token list. However, the list is correct for canonical LR with + one exception: it will still contain any token that will not be + accepted due to an error action in a later state. + */ + if (yytoken != YYEMPTY) + { + int yyn = yypact[*yyssp]; + yyarg[yycount++] = yytname[yytoken]; + if (!yypact_value_is_default (yyn)) + { + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. In other words, skip the first -YYN actions for + this state because they are default actions. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yyx; + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR + && !yytable_value_is_error (yytable[yyx + yyn])) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + break; + } + yyarg[yycount++] = yytname[yyx]; + { + YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]); + if (! (yysize <= yysize1 + && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + } + } + } + + switch (yycount) + { +# define YYCASE_(N, S) \ + case N: \ + yyformat = S; \ + break + YYCASE_(0, YY_("syntax error")); + YYCASE_(1, YY_("syntax error, unexpected %s")); + YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s")); + YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s")); + YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s")); + YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s")); +# undef YYCASE_ + } + + { + YYSIZE_T yysize1 = yysize + yystrlen (yyformat); + if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM)) + return 2; + yysize = yysize1; + } + + if (*yymsg_alloc < yysize) + { + *yymsg_alloc = 2 * yysize; + if (! (yysize <= *yymsg_alloc + && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM)) + *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM; + return 1; + } + + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + { + char *yyp = *yymsg; + int yyi = 0; + while ((*yyp = *yyformat) != '\0') + if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyformat += 2; + } + else + { + yyp++; + yyformat++; + } + } + return 0; +} +#endif /* YYERROR_VERBOSE */ + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep, YYLTYPE *yylocationp, sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos) +{ + YYUSE (yyvaluep); + YYUSE (yylocationp); + YYUSE (pool); + YYUSE (src); + YYUSE (ncaps); + YYUSE (flags); + YYUSE (parsed); + YYUSE (err_pos); + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + YYUSE (yytype); + YY_IGNORE_MAYBE_UNINITIALIZED_END +} + + + + +/*----------. +| yyparse. | +`----------*/ + +int +yyparse (sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos) +{ +/* The lookahead symbol. */ +int yychar; + + +/* The semantic value of the lookahead symbol. */ +/* Default value used for initialization, for pacifying older GCCs + or non-GCC compilers. */ +YY_INITIAL_VALUE (static YYSTYPE yyval_default;) +YYSTYPE yylval YY_INITIAL_VALUE (= yyval_default); + +/* Location data for the lookahead symbol. */ +static YYLTYPE yyloc_default +# if defined YYLTYPE_IS_TRIVIAL && YYLTYPE_IS_TRIVIAL + = { 1, 1, 1, 1 } +# endif +; +YYLTYPE yylloc = yyloc_default; + + /* Number of syntax errors so far. */ + int yynerrs; + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + 'yyss': related to states. + 'yyvs': related to semantic values. + 'yyls': related to locations. + + Refer to the stacks through separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + /* The location stack. */ + YYLTYPE yylsa[YYINITDEPTH]; + YYLTYPE *yyls; + YYLTYPE *yylsp; + + /* The locations where the error started and ended. */ + YYLTYPE yyerror_range[3]; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken = 0; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + YYLTYPE yyloc; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N), yylsp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yyssp = yyss = yyssa; + yyvsp = yyvs = yyvsa; + yylsp = yyls = yylsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + yylsp[0] = yylloc; + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + YYLTYPE *yyls1 = yyls; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yyls1, yysize * sizeof (*yylsp), + &yystacksize); + + yyls = yyls1; + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); + YYSTACK_RELOCATE (yyls_alloc, yyls); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + yylsp = yyls + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yypact_value_is_default (yyn)) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = yylex (&yylval, &yylloc, pool, src); + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yytable_value_is_error (yyn)) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + *++yylsp = yylloc; + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + '$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + /* Default location. */ + YYLLOC_DEFAULT (yyloc, (yylsp - yylen), yylen); + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 2: +#line 104 "src/sregex/sre_yyparser.y" + { + *parsed = (yyvsp[-1].re); + return SRE_OK; + } +#line 1414 "src/sregex/sre_yyparser.c" + break; + + case 4: +#line 113 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_ALT, (yyvsp[-2].re), (yyvsp[0].re)); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1425 "src/sregex/sre_yyparser.c" + break; + + case 6: +#line 124 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, (yyvsp[-1].re), (yyvsp[0].re)); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1436 "src/sregex/sre_yyparser.c" + break; + + case 7: +#line 131 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_NIL, NULL, NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1447 "src/sregex/sre_yyparser.c" + break; + + case 9: +#line 142 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, (yyvsp[-1].re), + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.greedy = 1; + } +#line 1461 "src/sregex/sre_yyparser.c" + break; + + case 10: +#line 153 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, (yyvsp[-2].re), + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1473 "src/sregex/sre_yyparser.c" + break; + + case 11: +#line 162 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_PLUS, (yyvsp[-1].re), + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.greedy = 1; + } +#line 1487 "src/sregex/sre_yyparser.c" + break; + + case 12: +#line 173 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_PLUS, (yyvsp[-2].re), + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1499 "src/sregex/sre_yyparser.c" + break; + + case 13: +#line 182 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_QUEST, (yyvsp[-1].re), + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.greedy = 1; + } +#line 1513 "src/sregex/sre_yyparser.c" + break; + + case 14: +#line 193 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_QUEST, (yyvsp[-2].re), + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1525 "src/sregex/sre_yyparser.c" + break; + + case 15: +#line 202 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_desugar_counted_repetition(pool, (yyvsp[-1].re), &(yyvsp[0].cquant), + 1 /* greedy */); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1537 "src/sregex/sre_yyparser.c" + break; + + case 16: +#line 211 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_desugar_counted_repetition(pool, (yyvsp[-2].re), &(yyvsp[-1].cquant), + 0 /* greedy */); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1549 "src/sregex/sre_yyparser.c" + break; + + case 17: +#line 221 "src/sregex/sre_yyparser.y" + { (yyval.group) = ++(*ncaps); } +#line 1555 "src/sregex/sre_yyparser.c" + break; + + case 18: +#line 226 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_PAREN, (yyvsp[-1].re), NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.group = (yyvsp[-2].group); + } +#line 1568 "src/sregex/sre_yyparser.c" + break; + + case 19: +#line 236 "src/sregex/sre_yyparser.y" + { + (yyval.re) = (yyvsp[-1].re); + } +#line 1576 "src/sregex/sre_yyparser.c" + break; + + case 20: +#line 241 "src/sregex/sre_yyparser.y" + { + if ((flags & SRE_REGEX_CASELESS) + && (((yyvsp[0].ch) >= 'A' && (yyvsp[0].ch) <= 'Z') + || ((yyvsp[0].ch) >= 'a' && (yyvsp[0].ch) <= 'z'))) + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if ((yyval.re)->data.range == NULL) { + YYABORT; + } + + (yyval.re)->data.range->from = (yyvsp[0].ch); + (yyval.re)->data.range->to = (yyvsp[0].ch); + + (yyval.re)->data.range->next = sre_palloc(pool, sizeof(sre_regex_range_t)); + if ((yyval.re)->data.range->next == NULL) { + YYABORT; + } + + if ((yyvsp[0].ch) <= 'Z') { + /* upper case */ + (yyval.re)->data.range->next->from = (yyvsp[0].ch) + 32; + (yyval.re)->data.range->next->to = (yyvsp[0].ch) + 32; + + } else { + /* lower case */ + + (yyval.re)->data.range->next->from = (yyvsp[0].ch) - 32; + (yyval.re)->data.range->next->to = (yyvsp[0].ch) - 32; + } + + (yyval.re)->data.range->next->next = NULL; + + } else { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_LIT, NULL, NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.ch = (yyvsp[0].ch); + } + } +#line 1628 "src/sregex/sre_yyparser.c" + break; + + case 21: +#line 290 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + } +#line 1639 "src/sregex/sre_yyparser.c" + break; + + case 22: +#line 298 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.assertion = SRE_REGEX_ASSERT_CARET; + } +#line 1652 "src/sregex/sre_yyparser.c" + break; + + case 23: +#line 308 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.assertion = SRE_REGEX_ASSERT_DOLLAR; + } +#line 1665 "src/sregex/sre_yyparser.c" + break; + + case 25: +#line 319 "src/sregex/sre_yyparser.y" + { + if (flags & SRE_REGEX_CASELESS) { + (yyval.re)->data.range = sre_regex_turn_char_class_caseless(pool, + (yyvsp[0].re)->data.range); + if ((yyval.re) == NULL) { + YYABORT; + } + } + } +#line 1679 "src/sregex/sre_yyparser.c" + break; + + case 26: +#line 330 "src/sregex/sre_yyparser.y" + { + (yyval.re) = sre_regex_create(pool, SRE_REGEX_TYPE_LIT, NULL, NULL); + if ((yyval.re) == NULL) { + YYABORT; + } + + (yyval.re)->data.ch = ':'; + } +#line 1692 "src/sregex/sre_yyparser.c" + break; + + +#line 1696 "src/sregex/sre_yyparser.c" + default: break; + } + /* User semantic actions sometimes alter yychar, and that requires + that yytoken be updated with the new translation. We take the + approach of translating immediately before every use of yytoken. + One alternative is translating here after every semantic action, + but that translation would be missed if the semantic action invokes + YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or + if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an + incorrect destructor might then be invoked immediately. In the + case of YYERROR or YYBACKUP, subsequent parser actions might lead + to an incorrect destructor call or verbose syntax error message + before the lookahead is translated. */ + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + *++yylsp = yyloc; + + /* Now 'shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*--------------------------------------. +| yyerrlab -- here on detecting error. | +`--------------------------------------*/ +yyerrlab: + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar); + + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (&yylloc, pool, src, ncaps, flags, parsed, err_pos, YY_("syntax error")); +#else +# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \ + yyssp, yytoken) + { + char const *yymsgp = YY_("syntax error"); + int yysyntax_error_status; + yysyntax_error_status = YYSYNTAX_ERROR; + if (yysyntax_error_status == 0) + yymsgp = yymsg; + else if (yysyntax_error_status == 1) + { + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc); + if (!yymsg) + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + yysyntax_error_status = 2; + } + else + { + yysyntax_error_status = YYSYNTAX_ERROR; + yymsgp = yymsg; + } + } + yyerror (&yylloc, pool, src, ncaps, flags, parsed, err_pos, yymsgp); + if (yysyntax_error_status == 2) + goto yyexhaustedlab; + } +# undef YYSYNTAX_ERROR +#endif + } + + yyerror_range[1] = yylloc; + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval, &yylloc, pool, src, ncaps, flags, parsed, err_pos); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + yyerror_range[1] = yylsp[1-yylen]; + /* Do not reclaim the symbols of the rule whose action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (!yypact_value_is_default (yyn)) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + yyerror_range[1] = *yylsp; + yydestruct ("Error: popping", + yystos[yystate], yyvsp, yylsp, pool, src, ncaps, flags, parsed, err_pos); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN + *++yyvsp = yylval; + YY_IGNORE_MAYBE_UNINITIALIZED_END + + yyerror_range[2] = yylloc; + /* Using YYLLOC is tempting, but would change the location of + the lookahead. YYLOC is available though. */ + YYLLOC_DEFAULT (yyloc, yyerror_range, 2); + *++yylsp = yyloc; + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined yyoverflow || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (&yylloc, pool, src, ncaps, flags, parsed, err_pos, YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + { + /* Make sure we have latest lookahead translation. See comments at + user semantic actions for why this is necessary. */ + yytoken = YYTRANSLATE (yychar); + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval, &yylloc, pool, src, ncaps, flags, parsed, err_pos); + } + /* Do not reclaim the symbols of the rule whose action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp, yylsp, pool, src, ncaps, flags, parsed, err_pos); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + return yyresult; +} +#line 340 "src/sregex/sre_yyparser.y" + + + +static int +yylex(YYSTYPE *lvalp, YYLTYPE *locp, sre_pool_t *pool, sre_char **src) +{ + sre_char c; + int from, to; + sre_uint_t i, n, num; + unsigned seen_dash, no_dash, seen_curly_bracket; + sre_regex_t *r; + sre_regex_range_t *range, *last = NULL; + sre_regex_type_t type; + + static sre_char esc_D_ranges[] = { 0, 47, 58, 255 }; + + static sre_char esc_w_ranges[] = { 'A', 'Z', 'a', 'z', '0', '9', + '_', '_' }; + + static sre_char esc_W_ranges[] = { 0, 47, 58, 64, 91, 94, 96, 96, + 123, 255 }; + + static sre_char esc_s_ranges[] = { ' ', ' ', '\f', '\f', '\n', '\n', + '\r', '\r', '\t', '\t' }; + + static sre_char esc_S_ranges[] = { 0, 8, 11, 11, 14, 31, 33, 255 }; + + static sre_char esc_h_ranges[] = { 0x09, 0x09, 0x20, 0x20, 0xa0, + 0xa0 }; + + static sre_char esc_H_ranges[] = { 0x00, 0x08, 0x0a, 0x1f, 0x21, 0x9f, + 0xa1, 0xff }; + + static sre_char esc_v_ranges[] = { 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0d, 0x0d, 0x85, 0x85 }; + + static sre_char esc_V_ranges[] = { 0x00, 0x09, 0x0e, 0x84, 0x86, + 0xff }; + + locp->pos = *src; + + if (*src == NULL || **src == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_EOF; + } + + c = sre_read_char(src); + if (strchr("|*+?():.^$", (int) c)) { + locp->last = *src; + return c; + } + + if (c == '\\') { + c = sre_read_char(src); + + if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (!isprint(c)) { + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + + if (strchr("'\" iM%@!,_-|*+?():.^$&\\/[]{}", (int) c)) { + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + + if (c >= '0' && c <= '7') { + + num = c - '0'; + i = 1; + + for (;;) { + c = **src; + + if (c < '0' || c > '7') { + if (++i != 3 && num != 0) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + + num = (c - '0') + (num << 3); + + (*src)++; + + if (++i == 3) { + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + } + } + + switch (c) { + case 'c': + c = sre_read_char(src); + if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (c >= 'a' && c <= 'z') { + c -= 32; + } + + lvalp->ch = (sre_char) (c ^ 64); + + dd("\\cK: %d", lvalp->ch); + + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'o': + c = sre_read_char(src); + if (c != '{') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = sre_read_char(src); + + num = 0; + i = 0; + + for (;;) { + dd("%d: oct digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '7') { + num = (c - '0') + (num << 3); + + } else if (c == '}') { + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + } else if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + } else { + (*src)--; + break; + } + + if (++i == 3) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + +#if 1 + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } +#endif + + break; + } + + c = sre_read_char(src); + } + + dd("\\o{...}: %u, next: %c", (unsigned) num, **src); + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'x': + c = sre_read_char(src); + if (c == '{') { + c = sre_read_char(src); + seen_curly_bracket = 1; + + } else { + seen_curly_bracket = 0; + } + + num = 0; + i = 0; + + for (;;) { + dd("%d: hex digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '9') { + num = (c - '0') + (num << 4); + + } else if (c >= 'A' && c <= 'F') { + num = (c - 'A' + 10) + (num << 4); + + } else if (c >= 'a' && c <= 'f') { + num = (c - 'a' + 10) + (num << 4); + + } else if (seen_curly_bracket) { + if (c != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + } else { + (*src)--; + break; + } + + if (++i == 2) { + if (seen_curly_bracket) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + } + + break; + } + + c = sre_read_char(src); + } + + dd("\\x{...}: %u, next: %c", (unsigned) num, **src); + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'B': + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_BIG_B; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'b': + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_SMALL_B; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'z': + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_SMALL_Z; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'A': + + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_BIG_A; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'd': + /* \d is defined as [0-9] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + break; + } + + range->from = '0'; + range->to = '9'; + range->next = NULL; + + r->data.range = range; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'D': + /* \D is defined as [^0-9] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + break; + } + + range->from = '0'; + range->to = '9'; + range->next = NULL; + + r->data.range = range; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'w': + /* \w is defined as [A-Za-z0-9_] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_w_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_w_ranges[i]; + range->to = esc_w_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_w_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'W': + /* \W is defined as [^A-Za-z0-9_] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_w_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + lvalp->ch = 0; + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_w_ranges[i]; + range->to = esc_w_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_w_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 's': + /* \s is defined as [ \f\n\r\t] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_s_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_s_ranges[i]; + range->to = esc_s_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_s_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'S': + /* \S is defined as [^ \f\n\r\t] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_s_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_s_ranges[i]; + range->to = esc_s_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_s_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'N': + /* \N is defined as [^\n] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + break; + } + + range->from = '\n'; + range->to = '\n'; + range->next = NULL; + + r->data.range = range; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'C': + /* \C is defined as . */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, + NULL); + if (r == NULL) { + break; + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'h': + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_h_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_h_ranges[i]; + range->to = esc_h_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_h_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'H': + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_h_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_h_ranges[i]; + range->to = esc_h_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_h_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'v': + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_v_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_v_ranges[i]; + range->to = esc_v_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_v_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'V': + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_v_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_v_ranges[i]; + range->to = esc_v_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_v_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 't': + lvalp->ch = '\t'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'n': + lvalp->ch = '\n'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'r': + lvalp->ch = '\r'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'f': + lvalp->ch = '\f'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'a': + lvalp->ch = '\a'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'e': + lvalp->ch = '\e'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case '"': + case '\'': + case '#': + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + default: + break; + } + + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + switch (c) { + case '[': + /* get character class */ + + if (**src == '^') { + type = SRE_REGEX_TYPE_NCLASS; + (*src)++; + + } else { + type = SRE_REGEX_TYPE_CLASS; + } + + r = sre_regex_create(pool, type, NULL, NULL); + if (r == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + last = NULL; + seen_dash = 0; + no_dash = 0; + n = 0; + + for ( ;; ) { + n++; + + c = sre_read_char(src); + + dd("read char: %d", c); + + switch (c) { + case '\0': + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + case ']': + dd("n == %d", (int) n); + + if (n == 1) { + goto process_char; + } + + if (seen_dash) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = '-'; + range->to = '-'; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case '\\': + c = sre_read_char(src); + + if (c >= '0' && c <= '7') { + + num = c - '0'; + i = 1; + + dd("\\ddd: %d", (int) num); + + for (;;) { + c = **src; + + if (c < '0' || c > '7') { + dd("c before: %d", c); + + c = (sre_char) num; + + dd("c after: %d", c); + goto process_char; + } + + num = (c - '0') + (num << 3); + + (*src)++; + + if (++i == 3) { + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = (sre_char) num; + goto process_char; + } + } + } + + switch (c) { + case 'c': + c = sre_read_char(src); + + if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (c >= 'a' && c <= 'z') { + c -= 32; + } + + c = (sre_char) (c ^ 64); + + dd("\\cK: %d", lvalp->ch); + + goto process_char; + + case 'o': + c = sre_read_char(src); + if (c != '{') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = sre_read_char(src); + + num = 0; + i = 0; + + for (;;) { + dd("%d: oct digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '7') { + num = (c - '0') + (num << 3); + + } else if (c == '}') { + c = (sre_char) num; + goto process_char; + + } else { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (++i == 3) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + break; + } + + c = sre_read_char(src); + } + + dd("\\x{...}: %u, next: %c", (unsigned) num, **src); + + c = (sre_char) num; + goto process_char; + + case 'x': + c = sre_read_char(src); + if (c == '{') { + c = sre_read_char(src); + seen_curly_bracket = 1; + + } else { + seen_curly_bracket = 0; + } + + num = 0; + i = 0; + + for (;;) { + dd("%d: hex digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '9') { + num = (c - '0') + (num << 4); + + } else if (c >= 'A' && c <= 'F') { + num = (c - 'A' + 10) + (num << 4); + + } else if (c >= 'a' && c <= 'f') { + num = (c - 'a' + 10) + (num << 4); + + } else if (seen_curly_bracket) { + if (c != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = (sre_char) num; + goto process_char; + + } else if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + } else { + (*src)--; + break; + } + + if (++i == 2) { + if (seen_curly_bracket) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + } + + break; + } + + c = sre_read_char(src); + } + + dd("\\x{...}: %u, next: %c", (int) num, **src); + + c = (sre_char) num; + goto process_char; + + case 't': + c = '\t'; + goto process_char; + + case 'n': + c = '\n'; + goto process_char; + + case 'r': + c = '\r'; + goto process_char; + + case 'f': + c = '\f'; + goto process_char; + + case 'a': + c = '\a'; + goto process_char; + + case 'e': + c = '\e'; + goto process_char; + + case 'b': + c = '\b'; + goto process_char; + + case '\0': + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + case '"': + case '\'': + case '#': + goto process_char; + + default: + break; + } + + if (!isprint(c)) { + goto process_char; + } + + if (strchr("'\" iMzC%@!,_-|*+?():.^$&\\/[]{}", (int) c)) { + goto process_char; + } + + if (seen_dash) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = '-'; + range->to = '-'; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + last = range; + seen_dash = 0; + } + + switch (c) { + case 'd': + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = '0'; + range->to = '9'; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + last = range; + + break; + + case 'D': + for (i = 0; i < sre_nelems(esc_D_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_D_ranges[i]; + range->to = esc_D_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'w': + for (i = 0; i < sre_nelems(esc_w_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_w_ranges[i]; + range->to = esc_w_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'W': + for (i = 0; i < sre_nelems(esc_W_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_W_ranges[i]; + range->to = esc_W_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 's': + for (i = 0; i < sre_nelems(esc_s_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_s_ranges[i]; + range->to = esc_s_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'S': + for (i = 0; i < sre_nelems(esc_S_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_S_ranges[i]; + range->to = esc_S_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'v': + for (i = 0; i < sre_nelems(esc_v_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_v_ranges[i]; + range->to = esc_v_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'V': + for (i = 0; i < sre_nelems(esc_V_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_V_ranges[i]; + range->to = esc_V_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'h': + for (i = 0; i < sre_nelems(esc_h_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_h_ranges[i]; + range->to = esc_h_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'H': + for (i = 0; i < sre_nelems(esc_H_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_H_ranges[i]; + range->to = esc_H_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + default: + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + no_dash = 1; + break; + + case '-': + if (!seen_dash && last && !no_dash) { + seen_dash = 1; + break; + } + + default: +process_char: + dd("next: %d", **src); + + if (seen_dash) { + last->to = c; + + if (last->to < last->from) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + seen_dash = 0; + no_dash = 1; + break; + } + + if (no_dash) { + no_dash = 0; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = c; + range->to = c; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + last = range; + break; + } + } + + break; + + case '{': + /* quantifier for counted repetition */ + + c = **src; + if (c < '0' || c > '9') { + c = (*src)[-1]; + break; + } + + i = 0; + from = 0; + do { + from = c - '0' + from * 10; + c = (*src)[++i]; + } while (c >= '0' && c <= '9'); + + dd("from parsed: %d, next: %c", from, (*src)[i]); + + if (c == '}') { + to = from; + (*src) += i + 1; + goto cquant_parsed; + } + + if (c != ',') { + dd("',' expected but got %c", c); + c = (*src)[-1]; + break; + } + + c = (*src)[++i]; + + if (c == '}') { + to = -1; + (*src) += i + 1; + goto cquant_parsed; + } + + if (c < '0' || c > '9') { + c = (*src)[-1]; + break; + } + + to = 0; + do { + to = c - '0' + to * 10; + c = (*src)[++i]; + } while (c >= '0' && c <= '9'); + + if (c != '}') { + c = (*src)[-1]; + break; + } + + (*src) += i + 1; + +cquant_parsed: + dd("from = %d, to = %d, next: %d", from, to, (*src)[0]); + + if (from >= 500 || to >= 500) { + dd("from or to too large: %d %d", from, to); + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (to >= 0 && from > to) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (from == 0) { + if (to == 1) { + locp->last = *src; + return '?'; + } + + if (to == -1) { + locp->last = *src; + return '*'; + } + + } else if (from == 1) { + if (to == -1) { + locp->last = *src; + return '+'; + } + } + + lvalp->cquant.from = from; + lvalp->cquant.to = to; + locp->last = *src; + return SRE_REGEX_TOKEN_CQUANT; + + default: + break; + } + + dd("token char: %c(%d)", c, c); + + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; +} + + +static void +yyerror(YYLTYPE *locp, sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, + int flags, sre_regex_t **parsed, sre_char **err_pos, char *msg) +{ + *err_pos = locp->pos; +} + + +SRE_API sre_regex_t * +sre_regex_parse(sre_pool_t *pool, sre_char *src, sre_uint_t *ncaps, int flags, + sre_int_t *err_offset) +{ + sre_char *start, *err_pos = NULL; + sre_regex_t *re, *r; + sre_regex_t *parsed = NULL; + + start = src; + *ncaps = 0; + *err_offset = -1; + + if (yyparse(pool, &src, ncaps, flags, &parsed, &err_pos) != SRE_OK) { + if (err_pos) { + *err_offset = (sre_int_t) (err_pos - start); + } + + return NULL; + } + + if (parsed == NULL) { + return NULL; + } + + /* assemble the regex ".*?(regex)" */ + + re = sre_regex_create(pool, SRE_REGEX_TYPE_PAREN, parsed, NULL); + /* $0 capture */ + + if (re == NULL) { + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_TOPLEVEL, re, NULL); + if (re == NULL) { + return NULL; + } + + r = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, NULL); + if (r == NULL) { + return NULL; + } + + r = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, r, NULL); + if (r == NULL) { + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, r, re); + if (re == NULL) { + return NULL; + } + + re->nregexes = 1; + re->data.multi_ncaps = sre_palloc(pool, sizeof(sre_uint_t)); + if (re->data.multi_ncaps == NULL) { + return NULL; + } + + re->data.multi_ncaps[0] = *ncaps; + + return re; +} + + +SRE_API sre_regex_t * +sre_regex_parse_multi(sre_pool_t *pool, sre_char **regexes, + sre_int_t nregexes, sre_uint_t *max_ncaps, int *multi_flags, + sre_int_t *err_offset, sre_int_t *err_regex_id) +{ + sre_char *start, *err_pos = NULL; + sre_regex_t *re, *r; + sre_regex_t *parsed = NULL; + sre_uint_t ncaps, saved_ncaps, *multi_ncaps, group; + sre_int_t i; + sre_char *src; + + ncaps = 0; + saved_ncaps = 0; + *max_ncaps = 0; + *err_offset = -1; + *err_regex_id = -1; + + if (nregexes <= 0) { + return NULL; + } + + multi_ncaps = sre_palloc(pool, nregexes * sizeof(sre_uint_t)); + if (multi_ncaps == NULL) { + return NULL; + } + + /* assemble /re1|re2|re3|.../ */ + + r = NULL; + + for (i = 0; i < nregexes; i++) { + src = regexes[i]; + start = src; + *err_regex_id = i; + + group = ncaps; + + if (yyparse(pool, &src, &ncaps, multi_flags ? multi_flags[i] : 0, + &parsed, &err_pos) != SRE_OK) + { + if (err_pos) { + *err_offset = (sre_int_t) (err_pos - start); + } + + return NULL; + } + + if (parsed == NULL) { + *err_regex_id = i; + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_PAREN, parsed, NULL); + /* $0 capture */ + + if (re == NULL) { + return NULL; + } + + re->data.group = group; + + re = sre_regex_create(pool, SRE_REGEX_TYPE_TOPLEVEL, re, NULL); + if (re == NULL) { + return NULL; + } + + re->data.regex_id = i; + + if (r == NULL) { + r = re; + multi_ncaps[i] = ncaps; + *max_ncaps = ncaps; + + } else { + r = sre_regex_create(pool, SRE_REGEX_TYPE_ALT, r, re); + if (r == NULL) { + return NULL; + } + + multi_ncaps[i] = ncaps - saved_ncaps; + if (multi_ncaps[i] > *max_ncaps) { + *max_ncaps = multi_ncaps[i]; + } + } + + dd("%d: ncaps: %d, max_ncaps: %d", (int) i, (int) ncaps, + (int) *max_ncaps); + + ncaps++; + saved_ncaps = ncaps; + } + + /* assemble the regex ".*?(regex)" */ + + re = r; + + r = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, NULL); + if (r == NULL) { + return NULL; + } + + r = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, r, NULL); + if (r == NULL) { + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, r, re); + if (re == NULL) { + return NULL; + } + + re->data.multi_ncaps = multi_ncaps; + re->nregexes = nregexes; + return re; +} + + +static sre_regex_t * +sre_regex_desugar_counted_repetition(sre_pool_t *pool, sre_regex_t *subj, + sre_regex_cquant_t *cquant, unsigned greedy) +{ + int i; + sre_regex_t *concat, *quest, *star; + + if (cquant->from == 1 && cquant->to == 1) { + return subj; + } + + /* generate subj{from} first */ + + if (cquant->from == 0) { + concat = sre_regex_create(pool, SRE_REGEX_TYPE_NIL, NULL, NULL); + if (concat == NULL) { + return NULL; + } + + i = 0; + + } else { + concat = subj; + + for (i = 1; i < cquant->from; i++) { + concat = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, concat, subj); + if (concat == NULL) { + return NULL; + } + } + } + + if (cquant->from == cquant->to) { + return concat; + } + + if (cquant->to == -1) { + /* append subj* to concat */ + + star = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, subj, + NULL); + if (star == NULL) { + return NULL; + } + + star->data.greedy = greedy; + + concat = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, concat, star); + if (concat == NULL) { + return NULL; + } + + return concat; + } + + /* append (?:subj?){to - from} */ + + quest = sre_regex_create(pool, SRE_REGEX_TYPE_QUEST, subj, + NULL); + if (quest == NULL) { + return NULL; + } + + quest->data.greedy = greedy; + + for ( ; i < cquant->to; i++) { + concat = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, concat, quest); + if (concat == NULL) { + return NULL; + } + } + + return concat; +} + diff --git a/lib/sregex/src/sregex/sre_yyparser.h b/lib/sregex/src/sregex/sre_yyparser.h new file mode 100644 index 0000000..8a1beef --- /dev/null +++ b/lib/sregex/src/sregex/sre_yyparser.h @@ -0,0 +1,95 @@ +/* A Bison parser, made by GNU Bison 3.0.4. */ + +/* Bison interface for Yacc-like parsers in C + + Copyright (C) 1984, 1989-1990, 2000-2015 Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +#ifndef YY_SREGEX_YY_SRC_SREGEX_SRE_YYPARSER_H_INCLUDED +# define YY_SREGEX_YY_SRC_SREGEX_SRE_YYPARSER_H_INCLUDED +/* Debug traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif +#if YYDEBUG +extern int sregex_yydebug; +#endif + +/* Token type. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + enum yytokentype + { + SRE_REGEX_TOKEN_CHAR = 258, + SRE_REGEX_TOKEN_EOF = 259, + SRE_REGEX_TOKEN_BAD = 260, + SRE_REGEX_TOKEN_CQUANT = 261, + SRE_REGEX_TOKEN_CHAR_CLASS = 262, + SRE_REGEX_TOKEN_ASSERTION = 263 + }; +#endif + +/* Value type. */ +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED + +union YYSTYPE +{ +#line 82 "src/sregex/sre_yyparser.y" + + sre_regex_t *re; + sre_char ch; + sre_uint_t group; + sre_regex_cquant_t cquant; + +#line 70 "src/sregex/sre_yyparser.h" +}; + +typedef union YYSTYPE YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define YYSTYPE_IS_DECLARED 1 +#endif + +/* Location type. */ +#if ! defined YYLTYPE && ! defined YYLTYPE_IS_DECLARED +typedef struct YYLTYPE YYLTYPE; +struct YYLTYPE +{ + int first_line; + int first_column; + int last_line; + int last_column; +}; +# define YYLTYPE_IS_DECLARED 1 +# define YYLTYPE_IS_TRIVIAL 1 +#endif + + + +int sregex_yyparse (sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos); + +#endif /* !YY_SREGEX_YY_SRC_SREGEX_SRE_YYPARSER_H_INCLUDED */ diff --git a/lib/sregex/src/sregex/sre_yyparser.y b/lib/sregex/src/sregex/sre_yyparser.y new file mode 100644 index 0000000..ac422f6 --- /dev/null +++ b/lib/sregex/src/sregex/sre_yyparser.y @@ -0,0 +1,2044 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang. + * Copyright 2007-2009 Russ Cox. All Rights Reserved. + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +%{ + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include + + +#include +#include +#include + + +#define YYLTYPE YYLTYPE +typedef struct YYLTYPE { + sre_char *pos; + sre_char *last; +} YYLTYPE; + + +#define YYLLOC_DEFAULT(Cur, Rhs, N) \ + do { \ + if (N) { \ + (Cur).pos = YYRHSLOC(Rhs, 1).pos; \ + (Cur).last = YYRHSLOC(Rhs, N).last; \ + } else { \ + (Cur).pos = YYRHSLOC(Rhs, 0).last; \ + (Cur).last = (Cur).pos; \ + } \ + } while (0) + + +#include +#include + + +#define sre_read_char(sp) *(*(sp))++ + + +static int yylex(YYSTYPE *lvalp, YYLTYPE *locp, sre_pool_t *pool, + sre_char **src); +static void yyerror(YYLTYPE *locp, sre_pool_t *pool, sre_char **src, + sre_uint_t *ncaps, int flags, sre_regex_t **parsed, sre_char **err_pos, + char *s); +static sre_regex_t *sre_regex_desugar_counted_repetition(sre_pool_t *pool, + sre_regex_t *subj, sre_regex_cquant_t *cquant, unsigned greedy); + +%} + + +%output "src/sregex/sre_yyparser.c" +%defines "src/sregex/sre_yyparser.h" + + +%define api.pure + + +%lex-param {sre_pool_t *pool} +%lex-param {sre_char *src} + + +%parse-param {sre_pool_t *pool} +%parse-param {sre_char **src} +%parse-param {sre_uint_t *ncaps} +%parse-param {int flags} +%parse-param {sre_regex_t **parsed} +%parse-param {sre_char **err_pos} + +%locations + +%expect 32 + +%union { + sre_regex_t *re; + sre_char ch; + sre_uint_t group; + sre_regex_cquant_t cquant; +} + + +%token SRE_REGEX_TOKEN_CHAR SRE_REGEX_TOKEN_EOF SRE_REGEX_TOKEN_BAD + +%token SRE_REGEX_TOKEN_CQUANT + +%token SRE_REGEX_TOKEN_CHAR_CLASS SRE_REGEX_TOKEN_ASSERTION +%type alt concat repeat atom regex + +%type count + +%start regex + +%% + +regex: alt SRE_REGEX_TOKEN_EOF + { + *parsed = $1; + return SRE_OK; + } + ; + + +alt: concat + | alt '|' concat + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_ALT, $1, $3); + if ($$ == NULL) { + YYABORT; + } + } + ; + + +concat: repeat + | concat repeat + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, $1, $2); + if ($$ == NULL) { + YYABORT; + } + } + | + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_NIL, NULL, NULL); + if ($$ == NULL) { + YYABORT; + } + } + ; + + +repeat: atom + | atom '*' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, $1, + NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.greedy = 1; + } + + | atom '*' '?' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, $1, + NULL); + if ($$ == NULL) { + YYABORT; + } + } + + | atom '+' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_PLUS, $1, + NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.greedy = 1; + } + + | atom '+' '?' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_PLUS, $1, + NULL); + if ($$ == NULL) { + YYABORT; + } + } + + | atom '?' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_QUEST, $1, + NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.greedy = 1; + } + + | atom '?' '?' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_QUEST, $1, + NULL); + if ($$ == NULL) { + YYABORT; + } + } + + | atom SRE_REGEX_TOKEN_CQUANT + { + $$ = sre_regex_desugar_counted_repetition(pool, $1, &$2, + 1 /* greedy */); + if ($$ == NULL) { + YYABORT; + } + } + + | atom SRE_REGEX_TOKEN_CQUANT '?' + { + $$ = sre_regex_desugar_counted_repetition(pool, $1, &$2, + 0 /* greedy */); + if ($$ == NULL) { + YYABORT; + } + } + ; + + +count: { $$ = ++(*ncaps); } + ; + + +atom: '(' count alt ')' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_PAREN, $3, NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.group = $2; + } + + | '(' '?' ':' alt ')' + { + $$ = $4; + } + + | SRE_REGEX_TOKEN_CHAR + { + if ((flags & SRE_REGEX_CASELESS) + && (($1 >= 'A' && $1 <= 'Z') + || ($1 >= 'a' && $1 <= 'z'))) + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if ($$->data.range == NULL) { + YYABORT; + } + + $$->data.range->from = $1; + $$->data.range->to = $1; + + $$->data.range->next = sre_palloc(pool, sizeof(sre_regex_range_t)); + if ($$->data.range->next == NULL) { + YYABORT; + } + + if ($1 <= 'Z') { + /* upper case */ + $$->data.range->next->from = $1 + 32; + $$->data.range->next->to = $1 + 32; + + } else { + /* lower case */ + + $$->data.range->next->from = $1 - 32; + $$->data.range->next->to = $1 - 32; + } + + $$->data.range->next->next = NULL; + + } else { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_LIT, NULL, NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.ch = $1; + } + } + + | '.' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, NULL); + if ($$ == NULL) { + YYABORT; + } + } + + | '^' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.assertion = SRE_REGEX_ASSERT_CARET; + } + + | '$' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.assertion = SRE_REGEX_ASSERT_DOLLAR; + } + + | SRE_REGEX_TOKEN_ASSERTION + | SRE_REGEX_TOKEN_CHAR_CLASS + { + if (flags & SRE_REGEX_CASELESS) { + $$->data.range = sre_regex_turn_char_class_caseless(pool, + $1->data.range); + if ($$ == NULL) { + YYABORT; + } + } + } + + | ':' + { + $$ = sre_regex_create(pool, SRE_REGEX_TYPE_LIT, NULL, NULL); + if ($$ == NULL) { + YYABORT; + } + + $$->data.ch = ':'; + } + ; + +%% + + +static int +yylex(YYSTYPE *lvalp, YYLTYPE *locp, sre_pool_t *pool, sre_char **src) +{ + sre_char c; + int from, to; + sre_uint_t i, n, num; + unsigned seen_dash, no_dash, seen_curly_bracket; + sre_regex_t *r; + sre_regex_range_t *range, *last = NULL; + sre_regex_type_t type; + + static sre_char esc_D_ranges[] = { 0, 47, 58, 255 }; + + static sre_char esc_w_ranges[] = { 'A', 'Z', 'a', 'z', '0', '9', + '_', '_' }; + + static sre_char esc_W_ranges[] = { 0, 47, 58, 64, 91, 94, 96, 96, + 123, 255 }; + + static sre_char esc_s_ranges[] = { ' ', ' ', '\f', '\f', '\n', '\n', + '\r', '\r', '\t', '\t' }; + + static sre_char esc_S_ranges[] = { 0, 8, 11, 11, 14, 31, 33, 255 }; + + static sre_char esc_h_ranges[] = { 0x09, 0x09, 0x20, 0x20, 0xa0, + 0xa0 }; + + static sre_char esc_H_ranges[] = { 0x00, 0x08, 0x0a, 0x1f, 0x21, 0x9f, + 0xa1, 0xff }; + + static sre_char esc_v_ranges[] = { 0x0a, 0x0a, 0x0b, 0x0b, 0x0c, 0x0c, + 0x0d, 0x0d, 0x85, 0x85 }; + + static sre_char esc_V_ranges[] = { 0x00, 0x09, 0x0e, 0x84, 0x86, + 0xff }; + + locp->pos = *src; + + if (*src == NULL || **src == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_EOF; + } + + c = sre_read_char(src); + if (strchr("|*+?():.^$", (int) c)) { + locp->last = *src; + return c; + } + + if (c == '\\') { + c = sre_read_char(src); + + if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (!isprint(c)) { + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + + if (strchr("'\" iM%@!,_-|*+?():.^$&\\/[]{}", (int) c)) { + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + + if (c >= '0' && c <= '7') { + + num = c - '0'; + i = 1; + + for (;;) { + c = **src; + + if (c < '0' || c > '7') { + if (++i != 3 && num != 0) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + + num = (c - '0') + (num << 3); + + (*src)++; + + if (++i == 3) { + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + } + } + } + + switch (c) { + case 'c': + c = sre_read_char(src); + if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (c >= 'a' && c <= 'z') { + c -= 32; + } + + lvalp->ch = (sre_char) (c ^ 64); + + dd("\\cK: %d", lvalp->ch); + + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'o': + c = sre_read_char(src); + if (c != '{') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = sre_read_char(src); + + num = 0; + i = 0; + + for (;;) { + dd("%d: oct digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '7') { + num = (c - '0') + (num << 3); + + } else if (c == '}') { + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + } else if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + } else { + (*src)--; + break; + } + + if (++i == 3) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + +#if 1 + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } +#endif + + break; + } + + c = sre_read_char(src); + } + + dd("\\o{...}: %u, next: %c", (unsigned) num, **src); + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'x': + c = sre_read_char(src); + if (c == '{') { + c = sre_read_char(src); + seen_curly_bracket = 1; + + } else { + seen_curly_bracket = 0; + } + + num = 0; + i = 0; + + for (;;) { + dd("%d: hex digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '9') { + num = (c - '0') + (num << 4); + + } else if (c >= 'A' && c <= 'F') { + num = (c - 'A' + 10) + (num << 4); + + } else if (c >= 'a' && c <= 'f') { + num = (c - 'a' + 10) + (num << 4); + + } else if (seen_curly_bracket) { + if (c != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + } else { + (*src)--; + break; + } + + if (++i == 2) { + if (seen_curly_bracket) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + } + + break; + } + + c = sre_read_char(src); + } + + dd("\\x{...}: %u, next: %c", (unsigned) num, **src); + + lvalp->ch = (sre_char) num; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'B': + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_BIG_B; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'b': + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_SMALL_B; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'z': + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_SMALL_Z; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'A': + + r = sre_regex_create(pool, SRE_REGEX_TYPE_ASSERT, NULL, + NULL); + if (r == NULL) { + break; + } + + r->data.assertion = SRE_REGEX_ASSERT_BIG_A; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_ASSERTION; + + case 'd': + /* \d is defined as [0-9] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + break; + } + + range->from = '0'; + range->to = '9'; + range->next = NULL; + + r->data.range = range; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'D': + /* \D is defined as [^0-9] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + break; + } + + range->from = '0'; + range->to = '9'; + range->next = NULL; + + r->data.range = range; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'w': + /* \w is defined as [A-Za-z0-9_] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_w_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_w_ranges[i]; + range->to = esc_w_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_w_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'W': + /* \W is defined as [^A-Za-z0-9_] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_w_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + lvalp->ch = 0; + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_w_ranges[i]; + range->to = esc_w_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_w_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 's': + /* \s is defined as [ \f\n\r\t] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_s_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_s_ranges[i]; + range->to = esc_s_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_s_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'S': + /* \S is defined as [^ \f\n\r\t] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_s_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_s_ranges[i]; + range->to = esc_s_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_s_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'N': + /* \N is defined as [^\n] */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + break; + } + + range->from = '\n'; + range->to = '\n'; + range->next = NULL; + + r->data.range = range; + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'C': + /* \C is defined as . */ + + r = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, + NULL); + if (r == NULL) { + break; + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'h': + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_h_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_h_ranges[i]; + range->to = esc_h_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_h_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'H': + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_h_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_h_ranges[i]; + range->to = esc_h_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_h_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'v': + r = sre_regex_create(pool, SRE_REGEX_TYPE_CLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_v_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_v_ranges[i]; + range->to = esc_v_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_v_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 'V': + r = sre_regex_create(pool, SRE_REGEX_TYPE_NCLASS, NULL, + NULL); + if (r == NULL) { + break; + } + + for (i = 0; i < sre_nelems(esc_v_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_v_ranges[i]; + range->to = esc_v_ranges[i + 1]; + + if (i == 0) { + r->data.range = range; + + } else { + last->next = range; + } + + if (i == sre_nelems(esc_v_ranges) - 2) { + range->next = NULL; + + } else { + last = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case 't': + lvalp->ch = '\t'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'n': + lvalp->ch = '\n'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'r': + lvalp->ch = '\r'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'f': + lvalp->ch = '\f'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'a': + lvalp->ch = '\a'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case 'e': + lvalp->ch = '\e'; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + case '"': + case '\'': + case '#': + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; + + default: + break; + } + + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + switch (c) { + case '[': + /* get character class */ + + if (**src == '^') { + type = SRE_REGEX_TYPE_NCLASS; + (*src)++; + + } else { + type = SRE_REGEX_TYPE_CLASS; + } + + r = sre_regex_create(pool, type, NULL, NULL); + if (r == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + last = NULL; + seen_dash = 0; + no_dash = 0; + n = 0; + + for ( ;; ) { + n++; + + c = sre_read_char(src); + + dd("read char: %d", c); + + switch (c) { + case '\0': + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + case ']': + dd("n == %d", (int) n); + + if (n == 1) { + goto process_char; + } + + if (seen_dash) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = '-'; + range->to = '-'; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + } + + lvalp->re = r; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR_CLASS; + + case '\\': + c = sre_read_char(src); + + if (c >= '0' && c <= '7') { + + num = c - '0'; + i = 1; + + dd("\\ddd: %d", (int) num); + + for (;;) { + c = **src; + + if (c < '0' || c > '7') { + dd("c before: %d", c); + + c = (sre_char) num; + + dd("c after: %d", c); + goto process_char; + } + + num = (c - '0') + (num << 3); + + (*src)++; + + if (++i == 3) { + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = (sre_char) num; + goto process_char; + } + } + } + + switch (c) { + case 'c': + c = sre_read_char(src); + + if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (c >= 'a' && c <= 'z') { + c -= 32; + } + + c = (sre_char) (c ^ 64); + + dd("\\cK: %d", lvalp->ch); + + goto process_char; + + case 'o': + c = sre_read_char(src); + if (c != '{') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = sre_read_char(src); + + num = 0; + i = 0; + + for (;;) { + dd("%d: oct digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '7') { + num = (c - '0') + (num << 3); + + } else if (c == '}') { + c = (sre_char) num; + goto process_char; + + } else { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (++i == 3) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (num > 255) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + break; + } + + c = sre_read_char(src); + } + + dd("\\x{...}: %u, next: %c", (unsigned) num, **src); + + c = (sre_char) num; + goto process_char; + + case 'x': + c = sre_read_char(src); + if (c == '{') { + c = sre_read_char(src); + seen_curly_bracket = 1; + + } else { + seen_curly_bracket = 0; + } + + num = 0; + i = 0; + + for (;;) { + dd("%d: hex digit: %c (%d)", (int) i, (int) c, c); + + if (c >= '0' && c <= '9') { + num = (c - '0') + (num << 4); + + } else if (c >= 'A' && c <= 'F') { + num = (c - 'A' + 10) + (num << 4); + + } else if (c >= 'a' && c <= 'f') { + num = (c - 'a' + 10) + (num << 4); + + } else if (seen_curly_bracket) { + if (c != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + c = (sre_char) num; + goto process_char; + + } else if (c == '\0') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + } else { + (*src)--; + break; + } + + if (++i == 2) { + if (seen_curly_bracket) { + dd("cur: '%c' (%d)", **src, **src); + + if (sre_read_char(src) != '}') { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + } + + break; + } + + c = sre_read_char(src); + } + + dd("\\x{...}: %u, next: %c", (int) num, **src); + + c = (sre_char) num; + goto process_char; + + case 't': + c = '\t'; + goto process_char; + + case 'n': + c = '\n'; + goto process_char; + + case 'r': + c = '\r'; + goto process_char; + + case 'f': + c = '\f'; + goto process_char; + + case 'a': + c = '\a'; + goto process_char; + + case 'e': + c = '\e'; + goto process_char; + + case 'b': + c = '\b'; + goto process_char; + + case '\0': + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + + case '"': + case '\'': + case '#': + goto process_char; + + default: + break; + } + + if (!isprint(c)) { + goto process_char; + } + + if (strchr("'\" iMzC%@!,_-|*+?():.^$&\\/[]{}", (int) c)) { + goto process_char; + } + + if (seen_dash) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = '-'; + range->to = '-'; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + last = range; + seen_dash = 0; + } + + switch (c) { + case 'd': + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = '0'; + range->to = '9'; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + last = range; + + break; + + case 'D': + for (i = 0; i < sre_nelems(esc_D_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_D_ranges[i]; + range->to = esc_D_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'w': + for (i = 0; i < sre_nelems(esc_w_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_w_ranges[i]; + range->to = esc_w_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'W': + for (i = 0; i < sre_nelems(esc_W_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_W_ranges[i]; + range->to = esc_W_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 's': + for (i = 0; i < sre_nelems(esc_s_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_s_ranges[i]; + range->to = esc_s_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'S': + for (i = 0; i < sre_nelems(esc_S_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_S_ranges[i]; + range->to = esc_S_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'v': + for (i = 0; i < sre_nelems(esc_v_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_v_ranges[i]; + range->to = esc_v_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'V': + for (i = 0; i < sre_nelems(esc_V_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_V_ranges[i]; + range->to = esc_V_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'h': + for (i = 0; i < sre_nelems(esc_h_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_h_ranges[i]; + range->to = esc_h_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + case 'H': + for (i = 0; i < sre_nelems(esc_H_ranges); i += 2) { + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = esc_H_ranges[i]; + range->to = esc_H_ranges[i + 1]; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + range->next = NULL; + last = range; + } + + break; + + default: + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + no_dash = 1; + break; + + case '-': + if (!seen_dash && last && !no_dash) { + seen_dash = 1; + break; + } + + default: +process_char: + dd("next: %d", **src); + + if (seen_dash) { + last->to = c; + + if (last->to < last->from) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + seen_dash = 0; + no_dash = 1; + break; + } + + if (no_dash) { + no_dash = 0; + } + + range = sre_palloc(pool, sizeof(sre_regex_range_t)); + if (range == NULL) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + range->from = c; + range->to = c; + range->next = NULL; + + if (last) { + last->next = range; + + } else { + r->data.range = range; + } + + last = range; + break; + } + } + + break; + + case '{': + /* quantifier for counted repetition */ + + c = **src; + if (c < '0' || c > '9') { + c = (*src)[-1]; + break; + } + + i = 0; + from = 0; + do { + from = c - '0' + from * 10; + c = (*src)[++i]; + } while (c >= '0' && c <= '9'); + + dd("from parsed: %d, next: %c", from, (*src)[i]); + + if (c == '}') { + to = from; + (*src) += i + 1; + goto cquant_parsed; + } + + if (c != ',') { + dd("',' expected but got %c", c); + c = (*src)[-1]; + break; + } + + c = (*src)[++i]; + + if (c == '}') { + to = -1; + (*src) += i + 1; + goto cquant_parsed; + } + + if (c < '0' || c > '9') { + c = (*src)[-1]; + break; + } + + to = 0; + do { + to = c - '0' + to * 10; + c = (*src)[++i]; + } while (c >= '0' && c <= '9'); + + if (c != '}') { + c = (*src)[-1]; + break; + } + + (*src) += i + 1; + +cquant_parsed: + dd("from = %d, to = %d, next: %d", from, to, (*src)[0]); + + if (from >= 500 || to >= 500) { + dd("from or to too large: %d %d", from, to); + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (to >= 0 && from > to) { + locp->last = *src; + return SRE_REGEX_TOKEN_BAD; + } + + if (from == 0) { + if (to == 1) { + locp->last = *src; + return '?'; + } + + if (to == -1) { + locp->last = *src; + return '*'; + } + + } else if (from == 1) { + if (to == -1) { + locp->last = *src; + return '+'; + } + } + + lvalp->cquant.from = from; + lvalp->cquant.to = to; + locp->last = *src; + return SRE_REGEX_TOKEN_CQUANT; + + default: + break; + } + + dd("token char: %c(%d)", c, c); + + lvalp->ch = c; + locp->last = *src; + return SRE_REGEX_TOKEN_CHAR; +} + + +static void +yyerror(YYLTYPE *locp, sre_pool_t *pool, sre_char **src, sre_uint_t *ncaps, + int flags, sre_regex_t **parsed, sre_char **err_pos, char *msg) +{ + *err_pos = locp->pos; +} + + +SRE_API sre_regex_t * +sre_regex_parse(sre_pool_t *pool, sre_char *src, sre_uint_t *ncaps, int flags, + sre_int_t *err_offset) +{ + sre_char *start, *err_pos = NULL; + sre_regex_t *re, *r; + sre_regex_t *parsed = NULL; + + start = src; + *ncaps = 0; + *err_offset = -1; + + if (yyparse(pool, &src, ncaps, flags, &parsed, &err_pos) != SRE_OK) { + if (err_pos) { + *err_offset = (sre_int_t) (err_pos - start); + } + + return NULL; + } + + if (parsed == NULL) { + return NULL; + } + + /* assemble the regex ".*?(regex)" */ + + re = sre_regex_create(pool, SRE_REGEX_TYPE_PAREN, parsed, NULL); + /* $0 capture */ + + if (re == NULL) { + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_TOPLEVEL, re, NULL); + if (re == NULL) { + return NULL; + } + + r = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, NULL); + if (r == NULL) { + return NULL; + } + + r = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, r, NULL); + if (r == NULL) { + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, r, re); + if (re == NULL) { + return NULL; + } + + re->nregexes = 1; + re->data.multi_ncaps = sre_palloc(pool, sizeof(sre_uint_t)); + if (re->data.multi_ncaps == NULL) { + return NULL; + } + + re->data.multi_ncaps[0] = *ncaps; + + return re; +} + + +SRE_API sre_regex_t * +sre_regex_parse_multi(sre_pool_t *pool, sre_char **regexes, + sre_int_t nregexes, sre_uint_t *max_ncaps, int *multi_flags, + sre_int_t *err_offset, sre_int_t *err_regex_id) +{ + sre_char *start, *err_pos = NULL; + sre_regex_t *re, *r; + sre_regex_t *parsed = NULL; + sre_uint_t ncaps, saved_ncaps, *multi_ncaps, group; + sre_int_t i; + sre_char *src; + + ncaps = 0; + saved_ncaps = 0; + *max_ncaps = 0; + *err_offset = -1; + *err_regex_id = -1; + + if (nregexes <= 0) { + return NULL; + } + + multi_ncaps = sre_palloc(pool, nregexes * sizeof(sre_uint_t)); + if (multi_ncaps == NULL) { + return NULL; + } + + /* assemble /re1|re2|re3|.../ */ + + r = NULL; + + for (i = 0; i < nregexes; i++) { + src = regexes[i]; + start = src; + *err_regex_id = i; + + group = ncaps; + + if (yyparse(pool, &src, &ncaps, multi_flags ? multi_flags[i] : 0, + &parsed, &err_pos) != SRE_OK) + { + if (err_pos) { + *err_offset = (sre_int_t) (err_pos - start); + } + + return NULL; + } + + if (parsed == NULL) { + *err_regex_id = i; + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_PAREN, parsed, NULL); + /* $0 capture */ + + if (re == NULL) { + return NULL; + } + + re->data.group = group; + + re = sre_regex_create(pool, SRE_REGEX_TYPE_TOPLEVEL, re, NULL); + if (re == NULL) { + return NULL; + } + + re->data.regex_id = i; + + if (r == NULL) { + r = re; + multi_ncaps[i] = ncaps; + *max_ncaps = ncaps; + + } else { + r = sre_regex_create(pool, SRE_REGEX_TYPE_ALT, r, re); + if (r == NULL) { + return NULL; + } + + multi_ncaps[i] = ncaps - saved_ncaps; + if (multi_ncaps[i] > *max_ncaps) { + *max_ncaps = multi_ncaps[i]; + } + } + + dd("%d: ncaps: %d, max_ncaps: %d", (int) i, (int) ncaps, + (int) *max_ncaps); + + ncaps++; + saved_ncaps = ncaps; + } + + /* assemble the regex ".*?(regex)" */ + + re = r; + + r = sre_regex_create(pool, SRE_REGEX_TYPE_DOT, NULL, NULL); + if (r == NULL) { + return NULL; + } + + r = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, r, NULL); + if (r == NULL) { + return NULL; + } + + re = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, r, re); + if (re == NULL) { + return NULL; + } + + re->data.multi_ncaps = multi_ncaps; + re->nregexes = nregexes; + return re; +} + + +static sre_regex_t * +sre_regex_desugar_counted_repetition(sre_pool_t *pool, sre_regex_t *subj, + sre_regex_cquant_t *cquant, unsigned greedy) +{ + int i; + sre_regex_t *concat, *quest, *star; + + if (cquant->from == 1 && cquant->to == 1) { + return subj; + } + + /* generate subj{from} first */ + + if (cquant->from == 0) { + concat = sre_regex_create(pool, SRE_REGEX_TYPE_NIL, NULL, NULL); + if (concat == NULL) { + return NULL; + } + + i = 0; + + } else { + concat = subj; + + for (i = 1; i < cquant->from; i++) { + concat = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, concat, subj); + if (concat == NULL) { + return NULL; + } + } + } + + if (cquant->from == cquant->to) { + return concat; + } + + if (cquant->to == -1) { + /* append subj* to concat */ + + star = sre_regex_create(pool, SRE_REGEX_TYPE_STAR, subj, + NULL); + if (star == NULL) { + return NULL; + } + + star->data.greedy = greedy; + + concat = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, concat, star); + if (concat == NULL) { + return NULL; + } + + return concat; + } + + /* append (?:subj?){to - from} */ + + quest = sre_regex_create(pool, SRE_REGEX_TYPE_QUEST, subj, + NULL); + if (quest == NULL) { + return NULL; + } + + quest->data.greedy = greedy; + + for ( ; i < cquant->to; i++) { + concat = sre_regex_create(pool, SRE_REGEX_TYPE_CAT, concat, quest); + if (concat == NULL) { + return NULL; + } + } + + return concat; +} + diff --git a/lib/sregex/src/sregex/sregex.h b/lib/sregex/src/sregex/sregex.h new file mode 100644 index 0000000..1aafac7 --- /dev/null +++ b/lib/sregex/src/sregex/sregex.h @@ -0,0 +1,173 @@ + +/* + * Copyright 2012 Yichun "agentzh" Zhang + * Use of this source code is governed by a BSD-style + * license that can be found in the LICENSE file. + */ + + +#ifndef _SREGEX_H_INCLUDED_ +#define _SREGEX_H_INCLUDED_ + + +#include +#include + + +/* core constants and types */ + + +#if defined _WIN32 || defined __CYGWIN__ +# ifdef BUILDING_DLL +# ifdef __GNUC__ +# define SRE_API __attribute__ ((dllexport)) +# else +# define SRE_API __declspec(dllexport) +# endif +# else +# ifdef __GNUC__ +# define SRE_API __attribute__ ((dllimport)) +# else +# define SRE_API __declspec(dllimport) +# endif +# endif +# define SRE_NOAPI +#else +# if __GNUC__ >= 4 +# define SRE_API __attribute__ ((visibility ("default"))) +# define SRE_NOAPI __attribute__ ((visibility ("hidden"))) +# else +# define SRE_API +# define SRE_NOAPI +# endif +#endif + + +#ifndef sre_char +#define sre_char sre_char +typedef uint8_t sre_char; +#endif + + +#ifndef sre_int_t +#define sre_int_t sre_int_t +typedef intptr_t sre_int_t; +#endif + + +#ifndef sre_uint_t +#define sre_uint_t sre_uint_t +typedef uintptr_t sre_uint_t; +#endif + + +/* status code */ +enum { + SRE_OK = 0, + SRE_ERROR = -1, + SRE_AGAIN = -2, + SRE_BUSY = -3, + SRE_DONE = -4, + SRE_DECLINED = -5 +}; + + +/* the memory pool API */ + + +struct sre_pool_s; +typedef struct sre_pool_s sre_pool_t; + + +SRE_API sre_pool_t *sre_create_pool(size_t size); +SRE_API void sre_reset_pool(sre_pool_t *pool); +SRE_API void sre_destroy_pool(sre_pool_t *pool); + + +/* the regex parser API */ + + +/* regex flags */ +enum { + SRE_REGEX_CASELESS = 1 +}; + + +struct sre_regex_s; +typedef struct sre_regex_s sre_regex_t; + + +SRE_API sre_regex_t *sre_regex_parse(sre_pool_t *pool, sre_char *src, + sre_uint_t *ncaps, int flags, sre_int_t *err_offset); + +SRE_API void sre_regex_dump(sre_regex_t *re); + +SRE_API sre_regex_t * sre_regex_parse_multi(sre_pool_t *pool, + sre_char **regexes, sre_int_t nregexes, sre_uint_t *max_ncaps, + int *multi_flags, sre_int_t *err_offset, sre_int_t *err_regex_id); + + +/* the regex compiler API */ + + +struct sre_program_s; +typedef struct sre_program_s sre_program_t; + + +SRE_API void sre_program_dump(sre_program_t *prog); + +SRE_API sre_program_t *sre_regex_compile(sre_pool_t *pool, sre_regex_t *re); + + +/* the Pike VM API */ + + +struct sre_vm_pike_ctx_s; +typedef struct sre_vm_pike_ctx_s sre_vm_pike_ctx_t; + + +SRE_API sre_vm_pike_ctx_t *sre_vm_pike_create_ctx(sre_pool_t *pool, + sre_program_t *prog, sre_int_t *ovector, size_t ovecsize); + +SRE_API sre_int_t sre_vm_pike_exec(sre_vm_pike_ctx_t *ctx, sre_char *input, + size_t len, unsigned eof, sre_int_t **pending_matched); + + +/* the Thompson VM API */ + + +struct sre_vm_thompson_ctx_s; +typedef struct sre_vm_thompson_ctx_s sre_vm_thompson_ctx_t; + + +SRE_API sre_vm_thompson_ctx_t *sre_vm_thompson_create_ctx(sre_pool_t *pool, + sre_program_t *prog); + +SRE_API sre_int_t sre_vm_thompson_exec(sre_vm_thompson_ctx_t *ctx, sre_char *input, + size_t len, unsigned eof); + + +/* Thompson VM JIT API */ + + +struct sre_vm_thompson_code_s; +typedef struct sre_vm_thompson_code_s sre_vm_thompson_code_t; + + +typedef sre_int_t (*sre_vm_thompson_exec_pt)(sre_vm_thompson_ctx_t *ctx, + sre_char *input, size_t size, unsigned eof); + + +SRE_API sre_int_t sre_vm_thompson_jit_compile(sre_pool_t *pool, + sre_program_t *prog, sre_vm_thompson_code_t **pcode); + +SRE_API sre_vm_thompson_ctx_t *sre_vm_thompson_jit_create_ctx(sre_pool_t *pool, + sre_program_t *prog); + +SRE_API sre_vm_thompson_exec_pt + sre_vm_thompson_jit_get_handler(sre_vm_thompson_code_t *code); + +SRE_API sre_int_t sre_vm_thompson_jit_free(sre_vm_thompson_code_t *code); + + +#endif /* _SREGEX_H_INCLUDED_ */ diff --git a/lib/sregex/sregex-cli b/lib/sregex/sregex-cli new file mode 100755 index 0000000..a0c6eed Binary files /dev/null and b/lib/sregex/sregex-cli differ diff --git a/lib/sregex/t/01-sanity-01.t b/lib/sregex/t/01-sanity-01.t new file mode 100644 index 0000000..4d736b7 --- /dev/null +++ b/lib/sregex/t/01-sanity-01.t @@ -0,0 +1,316 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: +--- re: a|ab +--- s: bah + + + +=== TEST 2: +--- re: a|(ab) +--- s: bah + + + +=== TEST 3: +--- re: a|(ab) +--- s: a + + + +=== TEST 4: +--- re: a|(ab) +--- s: b + + + +=== TEST 5: +--- re: ab +--- s: abc + + + +=== TEST 6: +--- re: a+ +--- s: bhaaaca + + + +=== TEST 7: +--- re: a* +--- s: bhc + + + +=== TEST 8: +--- re: a* +--- s: bhac + + + +=== TEST 9: +--- re: a? +--- s: bhc + + + +=== TEST 10: +--- re: a? +--- s: bhac + + + +=== TEST 11: .+ +--- re: .+ +--- s: + + + +=== TEST 12: +--- re: b.+?a +--- s: bhaaaca + + + +=== TEST 13: +--- re: bh.+?a +--- s: bhac + + + +=== TEST 14: +--- re: b.*?a +--- s: bhaaaca + + + +=== TEST 15: +--- re: bh.*?a +--- s: bhac + + + +=== TEST 16: non-greedy ? +--- re: a?? +--- s: bhac + + + +=== TEST 17: looping empty pattern (matching none) +re1 and re2 are wrong here +--- re: (a*)* +--- s: bhaac + + + +=== TEST 18: looping empty pattern (matching one char) +perl and pcre are wrong here +--- re: (a*)* +--- s: a +--- cap: (0, 1) (0, 1) + + + +=== TEST 19: looping empty pattern (matching one char, non-greedy) +re1 and re2 are wrong here. +--- re: (a*?)* +--- s: a + + + +=== TEST 20: looping empty pattern +perl and pcre are wrong here. +--- re: (a?)* +--- s: a +--- cap: (0, 1) (0, 1) + + + +=== TEST 21: looping empty pattern +re1 and re2 are wrong here. +--- re: (a??)* +--- s: a + + + +=== TEST 22: looping empty pattern +re1 and re2 are wrong here. +--- re: (a*?)* +--- s: a + + + +=== TEST 23: perl capturing semantics +--- re: (a|bcdef|g|ab|c|d|e|efg|fg)* +--- s: abcdefg + + + +=== TEST 24: +--- re: (a+)(b+) +--- s: aabbbb + + + +=== TEST 25: (?: ... ) +--- re: (?:a+)(?:b+) +--- s: aabbbb + + + +=== TEST 26: many captures exceeding $9 +--- re eval: "(.)" x 12 +--- s eval: "a" x 12 + + + +=== TEST 27: +--- re: (a|) +--- s: aabbbb + + + +=== TEST 28: +--- re: (|a) +--- s: aabbbb + + + +=== TEST 29: empty regex +--- re: +--- s: aabbbb + + + +=== TEST 30: empty group +--- re: () +--- s: aabbbb + + + +=== TEST 31: +--- re: abab|abbb +--- s: abbb + + + +=== TEST 32: +--- re: (a?)(a?)(a?)aaa +--- s: aaa + + + +=== TEST 33: a common pathological regex +--- re: (.*) (.*) (.*) (.*) (.*) +--- s: a c d ee fff + + + +=== TEST 34: submatch semantics (greedy) +--- re: (.+)(.+) +--- s: abcd + + + +=== TEST 35: submatch semantics (non-greedy) +--- re: (.+?)(.+?) +--- s: abcd + + + +=== TEST 36: character class (single char ranges) +--- re: [az]+ +--- s: -(aazbc+d + + + +=== TEST 37: character class (single char ranges) +--- re: [az]+ +--- s: -(bc+d + + + +=== TEST 38: character class (two char ranges) +--- re: [a-z]+ +--- s: -(aazbc+d + + + +=== TEST 39: character class (two char ranges) +--- re: [a-z]+ +--- s: -([*y*+ + + + +=== TEST 40: character class (two char ranges) +--- re: [a-z]+ +--- s: -([*/+ + + + +=== TEST 41: character class (two char ranges) +--- re: [^a-z]+ +--- s: -(aazbc+d + + + +=== TEST 42: character class (special char -) +--- re: [^-a-z]+ +--- s: -aaz-bc+d + + + +=== TEST 43: character class (special char "()") +--- re: [^()a-z]+ +--- s: -a(az)-bc+d + + + +=== TEST 44: character class (special char "()") +--- re: [()a-]+ +--- s: -a(az)-bc+d + + + +=== TEST 45: character class (special char "()") +--- re: [()a-z-A]+ +--- s: -a(az)-bc+d + + + +=== TEST 46: character class (two ranges) +--- re: [0-9A-Za-z]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 47: \d +--- re: \d+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 48: \w +--- re: \w+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 49: \W +--- re: \W+ +--- s: hello_world1234Blah(+- + + + +=== TEST 50: \D +--- re: \D+ +--- s: -+(hello)_world1234Blah(+ + + + diff --git a/lib/sregex/t/01-sanity-02.t b/lib/sregex/t/01-sanity-02.t new file mode 100644 index 0000000..a597b38 --- /dev/null +++ b/lib/sregex/t/01-sanity-02.t @@ -0,0 +1,310 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: \s +--- re: \s+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 2: \S +--- re: \S+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 3: escaped \ and [ +--- re: \\\[\)\(\. +--- s: hello\[)(.a + + + +=== TEST 4: [\d] +--- re: [\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 5: [B\d] +--- re: [B\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 6: [\dB] +--- re: [\dB]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 7: [^\d] +--- re: [^\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 8: [^\d] +--- re: [^\d]+ +--- s: 0159783 + + + +=== TEST 9: [^az\d] +--- re: [^az\d]+ +--- s: 0159a783z + + + +=== TEST 10: [^az\d] +--- re: [^az\d]+ +--- s: 0159a783zd + + + +=== TEST 11: [az\d] +--- re: [az\d]+ +--- s: +-*(byd + + + +=== TEST 12: [az\d] +--- re: [az\d]+ +--- s: +-*(byd9 + + + +=== TEST 13: [az\d] +--- re: [az\d]+ +--- s: +-*(bydz + + + +=== TEST 14: [a-\d] +--- re: [a-\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 15: +--- re: [(\w]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 16: +--- re: [\w(]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 17: +--- re: [\s]+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 18: +--- re: [\S]+ +--- s eval: "a" + + + +=== TEST 19: +--- re: [a-\xfe]+ +--- s eval: "b" + + + +=== TEST 20: +--- re: [\S]+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 21: \W +--- re: [\W]+ +--- s: hello_world1234Blah(+- + + + +=== TEST 22: \D +--- re: [\D]+ +--- s: -+(hello)_world1234Blah(+ + + + +=== TEST 23: +--- re: [^\D]+ +--- s: -+(hello)_world1234Blah(+ + + + +=== TEST 24: escaped metachars +--- re: [\\\[\)\(\.]+ +--- s: hello\[)(.a + + + +=== TEST 25: . in [] +--- re: [.]+ +--- s: hello\[)(.a + + + +=== TEST 26: . in [] +--- re: [\.-9]+ +--- s: -+(hello)_world.1234Blah(+ + + + +=== TEST 27: +-. +--- re: [\+-\.]+ +--- s: -.,+(hello)_world.1234Blah(+ + + + +=== TEST 28: +--- re: x{1,} +--- s: hxxxxxx + + + +=== TEST 29: +--- re: x{0,} +--- s: hxxxxxx + + + +=== TEST 30: +--- re: x{0,} +--- s: hab + + + +=== TEST 31: +--- re: x{1,} +--- s: hab + + + +=== TEST 32: +--- re: x{0,1} +--- s: hab + + + +=== TEST 33: +--- re: x{0,1} +--- s: haxb + + + +=== TEST 34: +--- re: x{0, 1} +--- s: x{0, 1} + + + +=== TEST 35: +--- re: x{0,1 +--- s: x{0,1} + + + +=== TEST 36: +--- re: x{0 ,1} +--- s: x{0 ,1} + + + +=== TEST 37: +--- re: x{,12} +--- s: x{,12} + + + +=== TEST 38: +--- re: x{1,1} +--- s: axxxx + + + +=== TEST 39: +--- re: x{1,1}? +--- s: axxxx + + + +=== TEST 40: +--- re: x{3,3} +--- s: axxxx + + + +=== TEST 41: +--- re: x{1,3} +--- s: axxxx + + + +=== TEST 42: +--- re: x{2,3} +--- s: axxxx + + + +=== TEST 43: +--- re: x{2,3}? +--- s: axxxx + + + +=== TEST 44: +--- re: x{1,3}? +--- s: axxxx + + + +=== TEST 45: +--- re: x{1,}? +--- s: axxxx + + + +=== TEST 46: +--- re: x{1,} +--- s: axxxx + + + +=== TEST 47: +--- re: x{12,15} +--- s eval: 'x' x 16 + + + +=== TEST 48: +--- re: x{12,15} +--- s eval: 'x' x 16 + + + +=== TEST 49: +--- re: x{100,} +--- s eval: 'x' x 16 +--- fatal + + + +=== TEST 50: from exceeding 100 +--- re: x{0,100} +--- s eval: 'x' x 16 +--- fatal + + + diff --git a/lib/sregex/t/01-sanity-03.t b/lib/sregex/t/01-sanity-03.t new file mode 100644 index 0000000..61656a7 --- /dev/null +++ b/lib/sregex/t/01-sanity-03.t @@ -0,0 +1,309 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: to exceeding 100 +--- re: {0,100} +--- s eval: 'x' x 16 +--- fatal + + + +=== TEST 2: +--- re: x{1} +--- s eval: 'x' x 16 + + + +=== TEST 3: +--- re: x{1}? +--- s eval: 'x' x 16 + + + +=== TEST 4: +--- re: x{2} +--- s eval: 'x' x 16 + + + +=== TEST 5: +--- re: x{2}? +--- s eval: 'x' x 16 + + + +=== TEST 6: +--- re: x{11} +--- s eval: 'x' x 16 + + + +=== TEST 7: +--- re: x{0,0} +--- s: hab + + + +=== TEST 8: match a tab +--- re: \t +--- s eval: " \t" + + + +=== TEST 9: match a tab in char class +--- re: [\t] +--- s eval: " \t" + + + +=== TEST 10: match a newline +--- re: \n +--- s eval: " \n" + + + +=== TEST 11: match a newline in char class +--- re: [\n] +--- s eval: " \n" + + + +=== TEST 12: match a return +--- re: \r +--- s eval: " \r" + + + +=== TEST 13: match a return in char class +--- re: [\r] +--- s eval: " \r" + + + +=== TEST 14: match a form feed +--- re: \f +--- s eval: " \f" + + + +=== TEST 15: match a form feed in char class +--- re: [\f] +--- s eval: " \f" + + + +=== TEST 16: match an alarm feed +--- re: \a +--- s eval: " \a" + + + +=== TEST 17: match an alarm in char class +--- re: [\a] +--- s eval: " \a" + + + +=== TEST 18: match an escape feed +--- re: \e +--- s eval: " \e" + + + +=== TEST 19: match an escape in char class +--- re: [\e] +--- s eval: " \e" + + + +=== TEST 20: \A +--- re: \Ahello +--- s eval: "hello" + + + +=== TEST 21: \A +--- re: \Ahello +--- s eval: "ahello" + + + +=== TEST 22: \A +--- re: \Ahello +--- s eval: "blah\nhello" + + + +=== TEST 23: ^ +--- re: ^h +--- s eval: "h" + + + +=== TEST 24: ^^ +--- re: ^^hello +--- s eval: "hello" + + + +=== TEST 25: ^^ +--- re: ^h^ello +--- s eval: "hello" + + + +=== TEST 26: ^^ +--- re: ^\n^ello +--- s eval: "\nello" + + + +=== TEST 27: ^ +--- re: ^hello +--- s eval: "hello" + + + +=== TEST 28: ^ +--- re: ^hello +--- s eval: "blah\nhello" + + + +=== TEST 29: ^ not match +--- re: ^ello +--- s eval: "blah\nhello" + + + +=== TEST 30: ^ +--- re: (a.*(^hello)) +--- s eval: "blah\nhello" + + + +=== TEST 31: ^ +--- re: ^ +--- s: + + + +=== TEST 32: ^ +--- re: (^)+ +--- s: "\n\n\n" + + + +=== TEST 33: \z +--- re: o\z +--- s eval: "o" + + + +=== TEST 34: \z & $ +--- re: $\z\n +--- s eval: "o\n" + + + +=== TEST 35: \z & $ +--- re: \z$\n +--- s eval: "o\n" + + + +=== TEST 36: \z +--- re: l\z +--- s eval: "hello" + + + +=== TEST 37: \z +--- re: hello\z +--- s eval: "blah\nhello" + + + +=== TEST 38: \z +--- re: hello\z +--- s eval: "blah\nhello\n" + + + +=== TEST 39: $ +--- re: hello$ +--- s eval: "blah\nhello" + + + +=== TEST 40: $ +--- re: hello$ +--- s eval: "blah\nhello\n" + + + +=== TEST 41: $ +--- re: hell$ +--- s eval: "blah\nhello\n" + + + +=== TEST 42: $ +--- re: \w+$ +--- s eval: "blah\nhello" + + + +=== TEST 43: $ +--- re: .*(\w+)$ +--- s eval: "blah\nhello" + + + +=== TEST 44: $ +--- re: .*(\w+)$\n +--- s eval: "blah\nhello" + + + +=== TEST 45: $ +--- re: ((\w+)$\n?)+ +--- s eval: "a\nb" + + + +=== TEST 46: $ +--- re: ((\w+)$\n?)+ +--- s eval: "abc\ndef" + + + +=== TEST 47: \b +--- re: a\b +--- s eval: "a\ndef" + + + +=== TEST 48: \b +--- re: ab\b +--- s eval: "ab\ndef" + + + +=== TEST 49: \b +--- re: ab\b +--- s eval: "abdef" + + + +=== TEST 50: \b +--- re: a\bb +--- s eval: "ab" + + + diff --git a/lib/sregex/t/01-sanity-04.t b/lib/sregex/t/01-sanity-04.t new file mode 100644 index 0000000..30a7956 --- /dev/null +++ b/lib/sregex/t/01-sanity-04.t @@ -0,0 +1,312 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: \b +--- re: (a\b|a\b)b +--- s eval: "ab" + + + +=== TEST 2: \b +--- re: ([+a])\b([-b]) +--- s eval: "ab" + + + +=== TEST 3: \b +--- re: ([+a])\b([-b]) +--- s eval: "a-" + + + +=== TEST 4: \b +--- re: ([+a])\b([-b]) +--- s eval: "+-" + + + +=== TEST 5: \b +--- re: ([+a])\b([-b]) +--- s eval: "+b" + + + +=== TEST 6: \b +--- re: ([+a])\b\b([-b]) +--- s eval: "+b" + + + +=== TEST 7: \b +--- re: \bb +--- s eval: "b" + + + +=== TEST 8: \b +--- re: \b([-b]) +--- s eval: "b" + + + +=== TEST 9: \b +--- re: \b([-b]) +--- s eval: "-" + + + +=== TEST 10: \b\z +--- re: a\b\z +--- s eval: "a\n" + + + +=== TEST 11: testinput1:1641 +--- re: .*\b5 +--- s eval: "5" + + + +=== TEST 12: testinput1:1641 +--- re: .*\b5+$ +--- s eval: "55" + + + +=== TEST 13: \B +--- re: ([+a])\B([-b]) +--- s eval: "ab" + + + +=== TEST 14: \B +--- re: ([+a])\B([-b]) +--- s eval: "a-" + + + +=== TEST 15: \B +--- re: ([+a])\B([-b]) +--- s eval: "+-" + + + +=== TEST 16: \B +--- re: ([+a])\B([-b]) +--- s eval: "+b" + + + +=== TEST 17: \B +--- re: ([+a])\B\B([-b]) +--- s eval: "+b" + + + +=== TEST 18: \B +--- re: \B([-b]) +--- s eval: "b" + + + +=== TEST 19: \B +--- re: \B([-b]) +--- s eval: "-" + + + +=== TEST 20: \B\z +--- re: a\B\z +--- s eval: "a\n" + + + +=== TEST 21: \h +--- re: \h+ +--- s eval: "\f\r\t " + + + +=== TEST 22: \H +--- re: \H+ +--- s eval: "\f\r\t " + + + +=== TEST 23: \v +--- re: \v+ +--- s eval: " \t\n\x0b\f\r\x85\x86" + + + +=== TEST 24: \V +--- re: \v+ +--- s eval: "\x86 \t\n\x0b\f\r\x85" + + + +=== TEST 25: \h +--- re: [\h]+ +--- s eval: "\f\r\t " + + + +=== TEST 26: \H +--- re: [\H]+ +--- s eval: "\f\r\t " + + + +=== TEST 27: \v +--- re: [\v]+ +--- s eval: " \t\n\x0b\f\r\x85\x86" +--- cap: (2, 7) + + + +=== TEST 28: \V +--- re: [\V]+ +--- s eval: "\x86 \t\n\x0b\f\r\x85" +--- cap: (0, 3) + + + +=== TEST 29: [\b] +--- re: [\b]+ +--- s eval: "a\b\b" + + + +=== TEST 30: [[]] +--- re: [[]]+ +--- s eval: "a[[[[]]]]" + + + +=== TEST 31: [][] +--- re: [][]+ +--- s eval: "a[[[[]]]]" + + + +=== TEST 32: [][] +--- re: [^][]+ +--- s eval: "ab[[[[]]]]" + + + +=== TEST 33: \N +--- re: \N+ +--- s eval: "hello!\r\t " + + + +=== TEST 34: \x{DD} +--- re: \x{0a} +--- s eval: "a\nb" + + + +=== TEST 35: \x{DD} +--- re: \x{0a}b +--- s eval: "a\nb" + + + +=== TEST 36: \x{DD} +--- re: \x{0a +--- s eval: "a\nb" +--- err +[error] syntax error at pos 0 + + + +=== TEST 37: \x{DD} +--- re: \xa +--- s eval: "a\nb" + + + +=== TEST 38: \xDD +--- re: \x0a +--- s eval: "a\nb" + + + +=== TEST 39: \xDD +--- re: \x0ab +--- s eval: "a\nb" + + + +=== TEST 40: \xDD +--- re: [\x0ab]+ +--- s eval: "a\nb" + + + +=== TEST 41: \xD +--- re: [\xa]+ +--- s eval: "a\nb" + + + +=== TEST 42: \xDD +--- re: \x0a! +--- s eval: "a\n!" + + + +=== TEST 43: \xDD +--- re: \xa! +--- s eval: "a\n!" + + + +=== TEST 44: \x{DD} +--- re: \x{a}b +--- s eval: "a\nb" + + + +=== TEST 45: \x{DD} +--- re: \x{A}b +--- s eval: "a\nb" + + + +=== TEST 46: \x{DD} +--- re: [\x{A}b]+ +--- s eval: "a\nb" + + + +=== TEST 47: \o{dd} +--- re: \o{12} +--- s eval: "a\nb" + + + +=== TEST 48: \o{ddd} +--- re: \o{012}b +--- s eval: "a\nb" + + + +=== TEST 49: \o{ddd} +--- re: [\o{012}b]+ +--- s eval: "a\nb" + + + +=== TEST 50: \o{ddd} +--- re: [\o{12}b]+ +--- s eval: "a\nb" + + + diff --git a/lib/sregex/t/01-sanity-05.t b/lib/sregex/t/01-sanity-05.t new file mode 100644 index 0000000..4e5ed78 --- /dev/null +++ b/lib/sregex/t/01-sanity-05.t @@ -0,0 +1,345 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: \o{ddd} +--- re: [\o{1}b]+ +--- s eval: "a\1b" + + + +=== TEST 2: \o{ddd} +--- re: [\o{1 +--- s eval: "a\1b" +--- err +[error] syntax error at pos 0 + + + +=== TEST 3: \oDD +--- re: \o12 +--- s eval: "a\nb" +--- err +[error] syntax error at pos 0 + + + +=== TEST 4: \oDD +--- re: \o{12 +--- s eval: "a\nb" +--- err +[error] syntax error at pos 0 + + + +=== TEST 5: [\02] +--- re: [\02] +--- s eval: "a\2b" + + + +=== TEST 6: [\12] +--- re: [\12] +--- s eval: "a\nb" + + + +=== TEST 7: +--- re: [\012] +--- s eval: "a\nb" + + + +=== TEST 8: +--- re: [\0123] +--- s eval: "a\n3" + + + +=== TEST 9: +--- re: [\0123]+ +--- s eval: "a\n3" + + + +=== TEST 10: +--- re: [\0123]+ +--- s eval: "a\n23" + + + +=== TEST 11: [\012] +--- re: [\018] +--- s eval: "a\n8" + + + +=== TEST 12: +--- re: \02 +--- s eval: "a\2b" + + + +=== TEST 13: +--- re: \12 +--- s eval: "a\nb" + + + +=== TEST 14: +--- re: \012 +--- s eval: "a\nb" + + + +=== TEST 15: +--- re: \0123 +--- s eval: "a\n3" + + + +=== TEST 16: [\012] +--- re: \018 +--- s eval: "a\n8" + + + +=== TEST 17: \cb +--- re: \cb +--- s eval: "a\0028" + + + +=== TEST 18: \cB +--- re: \cB +--- s eval: "a\0028" + + + +=== TEST 19: \c +--- re: \c +--- s eval: "a\0028" +--- err +[error] syntax error at pos 0 + + + +=== TEST 20: [\cb] +--- re: [\cb]+ +--- s eval: "a\0028" + + + +=== TEST 21: \cB +--- re: [\cB]+ +--- s eval: "a\0028" + + + +=== TEST 22: \c +--- re: [\c] +--- s eval: "a\0028" +--- err +[error] syntax error at pos 0 + + + +=== TEST 23: \cB8 +--- re: [\cB8]+ +--- s eval: "a\0028" + + + +=== TEST 24: literal : +--- re: a:\w+ +--- s eval: "a:hello" + + + +=== TEST 25: from > to and to == 0 +--- re: a{1,0} +--- s: a +--- err +[error] syntax error at pos 1 + + + +=== TEST 26: trailing \ +--- re: \ +--- s: a +--- err +[error] syntax error at pos 0 + + + +=== TEST 27: from > to +--- re: [D-C] +--- s: a +--- err +[error] syntax error at pos 0 + + + +=== TEST 28: the "possessive" quantifier form not supported +--- re: a++ +--- s: a +--- err +[error] syntax error at pos 2 + + + +=== TEST 29: the "possessive" quantifier form not supported +--- re: a*+ +--- s: a +--- err +[error] syntax error at pos 2 + + + +=== TEST 30: the "possessive" quantifier form not supported +--- re: a?+ +--- s: a +--- err +[error] syntax error at pos 2 + + + +=== TEST 31: the "possessive" quantifier form not supported +--- re: a{3}+ +--- s: a +--- err +[error] syntax error at pos 4 + + + +=== TEST 32: unmatched ")" +--- re: \(ab) +--- s: hello(ab) +--- err +[error] syntax error at pos 4 + + + +=== TEST 33: unmatched "]" +--- re: \[ab] +--- s: hello[ab] + + + +=== TEST 34: escaped !, @, \, /, %, and "," +--- re: [\!\,\@\\\/\%]+ +--- s: hello,!@\/% + + + +=== TEST 35: escaped !, @, \, /, %, and , +--- re: \!\,\@\\\/\% +--- s: hello,!@\/% + + + +=== TEST 36: \c\X +--- re: \c\X +--- s eval: "\034X" + + + +=== TEST 37: \c\. +--- re: \c\. +--- s eval: "\034X" + + + +=== TEST 38: \c\ +--- re: \c\ +--- s eval: "\034X" + + + +=== TEST 39: \C +--- re: \C+ +--- s eval: "hello world!\n\r" +--- SKIP + + + +=== TEST 40: a{0,n} +--- re: a{0,3} +--- s: + + + +=== TEST 41: a{0,n} +--- re: a{0,3} +--- s: aaaa + + + +=== TEST 42: \0 in target string +--- re: a +--- s eval: "\0aaaa" + + + +=== TEST 43: temporary captures +--- re: (?:a|(ab))cd +--- s: babcd +--- temp_cap: [(1, -1)] [(1, -1)] [(1, -1)] [(1, -1)] + + + +=== TEST 44: /i - in +--- re: [abd-f]+ +--- s: bFEBADaC +--- flags: i + + + +=== TEST 45: /i - not in +--- re: [^abd-f]+ +--- s: bFEBADaCz- +--- flags: i + + + +=== TEST 46: /i - testinput1:1685 +--- re: word (?:[a-zA-Z0-9]+ ){0,300}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" +--- flags: i + + + +=== TEST 47: /i - char +--- re: hello +--- s: ZAhHElLO +--- flags: i + + + +=== TEST 48: /i - char +--- re: hello +--- s: ZAHhello +--- flags: i + + + +=== TEST 49: match early +--- re: \s+ +--- s eval: "abc \t\n\f\rd" +--- temp_cap chop +[(1, -1)] [(2, -1)] [(3, -1)] [(3, -1)](3, 4) [(3, -1)](3, 5) [(3, -1)](3, 6) [(3, -1)](3, 7) [(3, -1)](3, 8) + + + +=== TEST 50: pending match +--- re: abcde|bc +--- s eval: "abcdf" +--- temp_cap chop +[(0, -1)] [(0, -1)] [(0, -1)](1, 3) [(0, -1)](1, 3) + + + diff --git a/lib/sregex/t/01-sanity-06.t b/lib/sregex/t/01-sanity-06.t new file mode 100644 index 0000000..f7f86c8 --- /dev/null +++ b/lib/sregex/t/01-sanity-06.t @@ -0,0 +1,29 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: \& +--- re: a\&b +--- s eval: 'a&b' + + + +=== TEST 2: [\&] +--- re: a[\&]b +--- s eval: 'a&b' + + + +=== TEST 3: \# \" \' +--- re: a\#\"\'b +--- s eval: 'a#"\'b' + + + +=== TEST 4: [\#\"\'] +--- re: [a\#\"\'b]{4} +--- s eval: 'a#"\'b' diff --git a/lib/sregex/t/01-sanity.t_ b/lib/sregex/t/01-sanity.t_ new file mode 100644 index 0000000..808d7f4 --- /dev/null +++ b/lib/sregex/t/01-sanity.t_ @@ -0,0 +1,1581 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: +--- re: a|ab +--- s: bah + + + +=== TEST 2: +--- re: a|(ab) +--- s: bah + + + +=== TEST 3: +--- re: a|(ab) +--- s: a + + + +=== TEST 4: +--- re: a|(ab) +--- s: b + + + +=== TEST 5: +--- re: ab +--- s: abc + + + +=== TEST 6: +--- re: a+ +--- s: bhaaaca + + + +=== TEST 7: +--- re: a* +--- s: bhc + + + +=== TEST 8: +--- re: a* +--- s: bhac + + + +=== TEST 9: +--- re: a? +--- s: bhc + + + +=== TEST 10: +--- re: a? +--- s: bhac + + + +=== TEST 11: .+ +--- re: .+ +--- s: + + + +=== TEST 12: +--- re: b.+?a +--- s: bhaaaca + + + +=== TEST 13: +--- re: bh.+?a +--- s: bhac + + + +=== TEST 14: +--- re: b.*?a +--- s: bhaaaca + + + +=== TEST 15: +--- re: bh.*?a +--- s: bhac + + + +=== TEST 16: non-greedy ? +--- re: a?? +--- s: bhac + + + +=== TEST 17: looping empty pattern (matching none) +re1 and re2 are wrong here +--- re: (a*)* +--- s: bhaac + + + +=== TEST 18: looping empty pattern (matching one char) +perl and pcre are wrong here +--- re: (a*)* +--- s: a +--- cap: (0, 1) (0, 1) + + + +=== TEST 19: looping empty pattern (matching one char, non-greedy) +re1 and re2 are wrong here. +--- re: (a*?)* +--- s: a + + + +=== TEST 20: looping empty pattern +perl and pcre are wrong here. +--- re: (a?)* +--- s: a +--- cap: (0, 1) (0, 1) + + + +=== TEST 21: looping empty pattern +re1 and re2 are wrong here. +--- re: (a??)* +--- s: a + + + +=== TEST 22: looping empty pattern +re1 and re2 are wrong here. +--- re: (a*?)* +--- s: a + + + +=== TEST 23: perl capturing semantics +--- re: (a|bcdef|g|ab|c|d|e|efg|fg)* +--- s: abcdefg + + + +=== TEST 24: +--- re: (a+)(b+) +--- s: aabbbb + + + +=== TEST 25: (?: ... ) +--- re: (?:a+)(?:b+) +--- s: aabbbb + + + +=== TEST 26: many captures exceeding $9 +--- re eval: "(.)" x 12 +--- s eval: "a" x 12 + + + +=== TEST 27: +--- re: (a|) +--- s: aabbbb + + + +=== TEST 28: +--- re: (|a) +--- s: aabbbb + + + +=== TEST 29: empty regex +--- re: +--- s: aabbbb + + + +=== TEST 30: empty group +--- re: () +--- s: aabbbb + + + +=== TEST 31: +--- re: abab|abbb +--- s: abbb + + + +=== TEST 32: +--- re: (a?)(a?)(a?)aaa +--- s: aaa + + + +=== TEST 33: a common pathological regex +--- re: (.*) (.*) (.*) (.*) (.*) +--- s: a c d ee fff + + + +=== TEST 34: submatch semantics (greedy) +--- re: (.+)(.+) +--- s: abcd + + + +=== TEST 35: submatch semantics (non-greedy) +--- re: (.+?)(.+?) +--- s: abcd + + + +=== TEST 36: character class (single char ranges) +--- re: [az]+ +--- s: -(aazbc+d + + + +=== TEST 37: character class (single char ranges) +--- re: [az]+ +--- s: -(bc+d + + + +=== TEST 38: character class (two char ranges) +--- re: [a-z]+ +--- s: -(aazbc+d + + + +=== TEST 39: character class (two char ranges) +--- re: [a-z]+ +--- s: -([*y*+ + + + +=== TEST 40: character class (two char ranges) +--- re: [a-z]+ +--- s: -([*/+ + + + +=== TEST 41: character class (two char ranges) +--- re: [^a-z]+ +--- s: -(aazbc+d + + + +=== TEST 42: character class (special char -) +--- re: [^-a-z]+ +--- s: -aaz-bc+d + + + +=== TEST 43: character class (special char "()") +--- re: [^()a-z]+ +--- s: -a(az)-bc+d + + + +=== TEST 44: character class (special char "()") +--- re: [()a-]+ +--- s: -a(az)-bc+d + + + +=== TEST 45: character class (special char "()") +--- re: [()a-z-A]+ +--- s: -a(az)-bc+d + + + +=== TEST 46: character class (two ranges) +--- re: [0-9A-Za-z]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 47: \d +--- re: \d+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 48: \w +--- re: \w+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 49: \W +--- re: \W+ +--- s: hello_world1234Blah(+- + + + +=== TEST 50: \D +--- re: \D+ +--- s: -+(hello)_world1234Blah(+ + + + +=== TEST 51: \s +--- re: \s+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 52: \S +--- re: \S+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 53: escaped \ and [ +--- re: \\\[\)\(\. +--- s: hello\[)(.a + + + +=== TEST 54: [\d] +--- re: [\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 55: [B\d] +--- re: [B\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 56: [\dB] +--- re: [\dB]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 57: [^\d] +--- re: [^\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 58: [^\d] +--- re: [^\d]+ +--- s: 0159783 + + + +=== TEST 59: [^az\d] +--- re: [^az\d]+ +--- s: 0159a783z + + + +=== TEST 60: [^az\d] +--- re: [^az\d]+ +--- s: 0159a783zd + + + +=== TEST 61: [az\d] +--- re: [az\d]+ +--- s: +-*(byd + + + +=== TEST 62: [az\d] +--- re: [az\d]+ +--- s: +-*(byd9 + + + +=== TEST 63: [az\d] +--- re: [az\d]+ +--- s: +-*(bydz + + + +=== TEST 64: [a-\d] +--- re: [a-\d]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 65: +--- re: [(\w]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 66: +--- re: [\w(]+ +--- s: -hello_world1234Blah(+ + + + +=== TEST 67: +--- re: [\s]+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 68: +--- re: [\S]+ +--- s eval: "a" + + + +=== TEST 69: +--- re: [a-\xfe]+ +--- s eval: "b" + + + +=== TEST 70: +--- re: [\S]+ +--- s eval: "-+(hello) \t_world1234Blah(+" + + + +=== TEST 71: \W +--- re: [\W]+ +--- s: hello_world1234Blah(+- + + + +=== TEST 72: \D +--- re: [\D]+ +--- s: -+(hello)_world1234Blah(+ + + + +=== TEST 73: +--- re: [^\D]+ +--- s: -+(hello)_world1234Blah(+ + + + +=== TEST 74: escaped metachars +--- re: [\\\[\)\(\.]+ +--- s: hello\[)(.a + + + +=== TEST 75: . in [] +--- re: [.]+ +--- s: hello\[)(.a + + + +=== TEST 76: . in [] +--- re: [\.-9]+ +--- s: -+(hello)_world.1234Blah(+ + + + +=== TEST 77: +-. +--- re: [\+-\.]+ +--- s: -.,+(hello)_world.1234Blah(+ + + + +=== TEST 78: +--- re: x{1,} +--- s: hxxxxxx + + + +=== TEST 79: +--- re: x{0,} +--- s: hxxxxxx + + + +=== TEST 80: +--- re: x{0,} +--- s: hab + + + +=== TEST 81: +--- re: x{1,} +--- s: hab + + + +=== TEST 82: +--- re: x{0,1} +--- s: hab + + + +=== TEST 83: +--- re: x{0,1} +--- s: haxb + + + +=== TEST 84: +--- re: x{0, 1} +--- s: x{0, 1} + + + +=== TEST 85: +--- re: x{0,1 +--- s: x{0,1} + + + +=== TEST 86: +--- re: x{0 ,1} +--- s: x{0 ,1} + + + +=== TEST 87: +--- re: x{,12} +--- s: x{,12} + + + +=== TEST 88: +--- re: x{1,1} +--- s: axxxx + + + +=== TEST 89: +--- re: x{1,1}? +--- s: axxxx + + + +=== TEST 90: +--- re: x{3,3} +--- s: axxxx + + + +=== TEST 91: +--- re: x{1,3} +--- s: axxxx + + + +=== TEST 92: +--- re: x{2,3} +--- s: axxxx + + + +=== TEST 93: +--- re: x{2,3}? +--- s: axxxx + + + +=== TEST 94: +--- re: x{1,3}? +--- s: axxxx + + + +=== TEST 95: +--- re: x{1,}? +--- s: axxxx + + + +=== TEST 96: +--- re: x{1,} +--- s: axxxx + + + +=== TEST 97: +--- re: x{12,15} +--- s eval: 'x' x 16 + + + +=== TEST 98: +--- re: x{12,15} +--- s eval: 'x' x 16 + + + +=== TEST 99: +--- re: x{100,} +--- s eval: 'x' x 16 +--- fatal + + + +=== TEST 100: from exceeding 100 +--- re: x{0,100} +--- s eval: 'x' x 16 +--- fatal + + + +=== TEST 101: to exceeding 100 +--- re: {0,100} +--- s eval: 'x' x 16 +--- fatal + + + +=== TEST 102: +--- re: x{1} +--- s eval: 'x' x 16 + + + +=== TEST 103: +--- re: x{1}? +--- s eval: 'x' x 16 + + + +=== TEST 104: +--- re: x{2} +--- s eval: 'x' x 16 + + + +=== TEST 105: +--- re: x{2}? +--- s eval: 'x' x 16 + + + +=== TEST 106: +--- re: x{11} +--- s eval: 'x' x 16 + + + +=== TEST 107: +--- re: x{0,0} +--- s: hab + + + +=== TEST 108: match a tab +--- re: \t +--- s eval: " \t" + + + +=== TEST 109: match a tab in char class +--- re: [\t] +--- s eval: " \t" + + + +=== TEST 110: match a newline +--- re: \n +--- s eval: " \n" + + + +=== TEST 111: match a newline in char class +--- re: [\n] +--- s eval: " \n" + + + +=== TEST 112: match a return +--- re: \r +--- s eval: " \r" + + + +=== TEST 113: match a return in char class +--- re: [\r] +--- s eval: " \r" + + + +=== TEST 114: match a form feed +--- re: \f +--- s eval: " \f" + + + +=== TEST 115: match a form feed in char class +--- re: [\f] +--- s eval: " \f" + + + +=== TEST 116: match an alarm feed +--- re: \a +--- s eval: " \a" + + + +=== TEST 117: match an alarm in char class +--- re: [\a] +--- s eval: " \a" + + + +=== TEST 118: match an escape feed +--- re: \e +--- s eval: " \e" + + + +=== TEST 119: match an escape in char class +--- re: [\e] +--- s eval: " \e" + + + +=== TEST 120: \A +--- re: \Ahello +--- s eval: "hello" + + + +=== TEST 121: \A +--- re: \Ahello +--- s eval: "ahello" + + + +=== TEST 122: \A +--- re: \Ahello +--- s eval: "blah\nhello" + + + +=== TEST 123: ^ +--- re: ^h +--- s eval: "h" + + + +=== TEST 124: ^^ +--- re: ^^hello +--- s eval: "hello" + + + +=== TEST 125: ^^ +--- re: ^h^ello +--- s eval: "hello" + + + +=== TEST 126: ^^ +--- re: ^\n^ello +--- s eval: "\nello" + + + +=== TEST 127: ^ +--- re: ^hello +--- s eval: "hello" + + + +=== TEST 128: ^ +--- re: ^hello +--- s eval: "blah\nhello" + + + +=== TEST 129: ^ not match +--- re: ^ello +--- s eval: "blah\nhello" + + + +=== TEST 130: ^ +--- re: (a.*(^hello)) +--- s eval: "blah\nhello" + + + +=== TEST 131: ^ +--- re: ^ +--- s: + + + +=== TEST 132: ^ +--- re: (^)+ +--- s: "\n\n\n" + + + +=== TEST 133: \z +--- re: o\z +--- s eval: "o" + + + +=== TEST 134: \z & $ +--- re: $\z\n +--- s eval: "o\n" + + + +=== TEST 135: \z & $ +--- re: \z$\n +--- s eval: "o\n" + + + +=== TEST 136: \z +--- re: l\z +--- s eval: "hello" + + + +=== TEST 137: \z +--- re: hello\z +--- s eval: "blah\nhello" + + + +=== TEST 138: \z +--- re: hello\z +--- s eval: "blah\nhello\n" + + + +=== TEST 139: $ +--- re: hello$ +--- s eval: "blah\nhello" + + + +=== TEST 140: $ +--- re: hello$ +--- s eval: "blah\nhello\n" + + + +=== TEST 141: $ +--- re: hell$ +--- s eval: "blah\nhello\n" + + + +=== TEST 142: $ +--- re: \w+$ +--- s eval: "blah\nhello" + + + +=== TEST 143: $ +--- re: .*(\w+)$ +--- s eval: "blah\nhello" + + + +=== TEST 144: $ +--- re: .*(\w+)$\n +--- s eval: "blah\nhello" + + + +=== TEST 145: $ +--- re: ((\w+)$\n?)+ +--- s eval: "a\nb" + + + +=== TEST 146: $ +--- re: ((\w+)$\n?)+ +--- s eval: "abc\ndef" + + + +=== TEST 147: \b +--- re: a\b +--- s eval: "a\ndef" + + + +=== TEST 148: \b +--- re: ab\b +--- s eval: "ab\ndef" + + + +=== TEST 149: \b +--- re: ab\b +--- s eval: "abdef" + + + +=== TEST 150: \b +--- re: a\bb +--- s eval: "ab" + + + +=== TEST 151: \b +--- re: (a\b|a\b)b +--- s eval: "ab" + + + +=== TEST 152: \b +--- re: ([+a])\b([-b]) +--- s eval: "ab" + + + +=== TEST 153: \b +--- re: ([+a])\b([-b]) +--- s eval: "a-" + + + +=== TEST 154: \b +--- re: ([+a])\b([-b]) +--- s eval: "+-" + + + +=== TEST 155: \b +--- re: ([+a])\b([-b]) +--- s eval: "+b" + + + +=== TEST 156: \b +--- re: ([+a])\b\b([-b]) +--- s eval: "+b" + + + +=== TEST 157: \b +--- re: \bb +--- s eval: "b" + + + +=== TEST 158: \b +--- re: \b([-b]) +--- s eval: "b" + + + +=== TEST 159: \b +--- re: \b([-b]) +--- s eval: "-" + + + +=== TEST 160: \b\z +--- re: a\b\z +--- s eval: "a\n" + + + +=== TEST 161: testinput1:1641 +--- re: .*\b5 +--- s eval: "5" + + + +=== TEST 162: testinput1:1641 +--- re: .*\b5+$ +--- s eval: "55" + + + +=== TEST 163: \B +--- re: ([+a])\B([-b]) +--- s eval: "ab" + + + +=== TEST 164: \B +--- re: ([+a])\B([-b]) +--- s eval: "a-" + + + +=== TEST 165: \B +--- re: ([+a])\B([-b]) +--- s eval: "+-" + + + +=== TEST 166: \B +--- re: ([+a])\B([-b]) +--- s eval: "+b" + + + +=== TEST 167: \B +--- re: ([+a])\B\B([-b]) +--- s eval: "+b" + + + +=== TEST 168: \B +--- re: \B([-b]) +--- s eval: "b" + + + +=== TEST 169: \B +--- re: \B([-b]) +--- s eval: "-" + + + +=== TEST 170: \B\z +--- re: a\B\z +--- s eval: "a\n" + + + +=== TEST 171: \h +--- re: \h+ +--- s eval: "\f\r\t " + + + +=== TEST 172: \H +--- re: \H+ +--- s eval: "\f\r\t " + + + +=== TEST 173: \v +--- re: \v+ +--- s eval: " \t\n\x0b\f\r\x85\x86" + + + +=== TEST 174: \V +--- re: \v+ +--- s eval: "\x86 \t\n\x0b\f\r\x85" + + + +=== TEST 175: \h +--- re: [\h]+ +--- s eval: "\f\r\t " + + + +=== TEST 176: \H +--- re: [\H]+ +--- s eval: "\f\r\t " + + + +=== TEST 177: \v +--- re: [\v]+ +--- s eval: " \t\n\x0b\f\r\x85\x86" +--- cap: (2, 7) + + + +=== TEST 178: \V +--- re: [\V]+ +--- s eval: "\x86 \t\n\x0b\f\r\x85" +--- cap: (0, 3) + + + +=== TEST 179: [\b] +--- re: [\b]+ +--- s eval: "a\b\b" + + + +=== TEST 180: [[]] +--- re: [[]]+ +--- s eval: "a[[[[]]]]" + + + +=== TEST 181: [][] +--- re: [][]+ +--- s eval: "a[[[[]]]]" + + + +=== TEST 182: [][] +--- re: [^][]+ +--- s eval: "ab[[[[]]]]" + + + +=== TEST 183: \N +--- re: \N+ +--- s eval: "hello!\r\t " + + + +=== TEST 184: \x{DD} +--- re: \x{0a} +--- s eval: "a\nb" + + + +=== TEST 185: \x{DD} +--- re: \x{0a}b +--- s eval: "a\nb" + + + +=== TEST 186: \x{DD} +--- re: \x{0a +--- s eval: "a\nb" +--- err +[error] syntax error at pos 0 + + + +=== TEST 187: \x{DD} +--- re: \xa +--- s eval: "a\nb" + + + +=== TEST 188: \xDD +--- re: \x0a +--- s eval: "a\nb" + + + +=== TEST 189: \xDD +--- re: \x0ab +--- s eval: "a\nb" + + + +=== TEST 190: \xDD +--- re: [\x0ab]+ +--- s eval: "a\nb" + + + +=== TEST 191: \xD +--- re: [\xa]+ +--- s eval: "a\nb" + + + +=== TEST 192: \xDD +--- re: \x0a! +--- s eval: "a\n!" + + + +=== TEST 193: \xDD +--- re: \xa! +--- s eval: "a\n!" + + + +=== TEST 194: \x{DD} +--- re: \x{a}b +--- s eval: "a\nb" + + + +=== TEST 195: \x{DD} +--- re: \x{A}b +--- s eval: "a\nb" + + + +=== TEST 196: \x{DD} +--- re: [\x{A}b]+ +--- s eval: "a\nb" + + + +=== TEST 197: \o{dd} +--- re: \o{12} +--- s eval: "a\nb" + + + +=== TEST 198: \o{ddd} +--- re: \o{012}b +--- s eval: "a\nb" + + + +=== TEST 199: \o{ddd} +--- re: [\o{012}b]+ +--- s eval: "a\nb" + + + +=== TEST 200: \o{ddd} +--- re: [\o{12}b]+ +--- s eval: "a\nb" + + + +=== TEST 201: \o{ddd} +--- re: [\o{1}b]+ +--- s eval: "a\1b" + + + +=== TEST 202: \o{ddd} +--- re: [\o{1 +--- s eval: "a\1b" +--- err +[error] syntax error at pos 0 + + + +=== TEST 203: \oDD +--- re: \o12 +--- s eval: "a\nb" +--- err +[error] syntax error at pos 0 + + + +=== TEST 204: \oDD +--- re: \o{12 +--- s eval: "a\nb" +--- err +[error] syntax error at pos 0 + + + +=== TEST 205: [\02] +--- re: [\02] +--- s eval: "a\2b" + + + +=== TEST 206: [\12] +--- re: [\12] +--- s eval: "a\nb" + + + +=== TEST 207: +--- re: [\012] +--- s eval: "a\nb" + + + +=== TEST 208: +--- re: [\0123] +--- s eval: "a\n3" + + + +=== TEST 209: +--- re: [\0123]+ +--- s eval: "a\n3" + + + +=== TEST 210: +--- re: [\0123]+ +--- s eval: "a\n23" + + + +=== TEST 211: [\012] +--- re: [\018] +--- s eval: "a\n8" + + + +=== TEST 212: +--- re: \02 +--- s eval: "a\2b" + + + +=== TEST 213: +--- re: \12 +--- s eval: "a\nb" + + + +=== TEST 214: +--- re: \012 +--- s eval: "a\nb" + + + +=== TEST 215: +--- re: \0123 +--- s eval: "a\n3" + + + +=== TEST 216: [\012] +--- re: \018 +--- s eval: "a\n8" + + + +=== TEST 217: \cb +--- re: \cb +--- s eval: "a\0028" + + + +=== TEST 218: \cB +--- re: \cB +--- s eval: "a\0028" + + + +=== TEST 219: \c +--- re: \c +--- s eval: "a\0028" +--- err +[error] syntax error at pos 0 + + + +=== TEST 220: [\cb] +--- re: [\cb]+ +--- s eval: "a\0028" + + + +=== TEST 221: \cB +--- re: [\cB]+ +--- s eval: "a\0028" + + + +=== TEST 222: \c +--- re: [\c] +--- s eval: "a\0028" +--- err +[error] syntax error at pos 0 + + + +=== TEST 223: \cB8 +--- re: [\cB8]+ +--- s eval: "a\0028" + + + +=== TEST 224: literal : +--- re: a:\w+ +--- s eval: "a:hello" + + + +=== TEST 225: from > to and to == 0 +--- re: a{1,0} +--- s: a +--- err +[error] syntax error at pos 1 + + + +=== TEST 226: trailing \ +--- re: \ +--- s: a +--- err +[error] syntax error at pos 0 + + + +=== TEST 227: from > to +--- re: [D-C] +--- s: a +--- err +[error] syntax error at pos 0 + + + +=== TEST 228: the "possessive" quantifier form not supported +--- re: a++ +--- s: a +--- err +[error] syntax error at pos 2 + + + +=== TEST 229: the "possessive" quantifier form not supported +--- re: a*+ +--- s: a +--- err +[error] syntax error at pos 2 + + + +=== TEST 230: the "possessive" quantifier form not supported +--- re: a?+ +--- s: a +--- err +[error] syntax error at pos 2 + + + +=== TEST 231: the "possessive" quantifier form not supported +--- re: a{3}+ +--- s: a +--- err +[error] syntax error at pos 4 + + + +=== TEST 232: unmatched ")" +--- re: \(ab) +--- s: hello(ab) +--- err +[error] syntax error at pos 4 + + + +=== TEST 233: unmatched "]" +--- re: \[ab] +--- s: hello[ab] + + + +=== TEST 234: escaped !, @, \, /, %, and "," +--- re: [\!\,\@\\\/\%]+ +--- s: hello,!@\/% + + + +=== TEST 235: escaped !, @, \, /, %, and , +--- re: \!\,\@\\\/\% +--- s: hello,!@\/% + + + +=== TEST 236: \c\X +--- re: \c\X +--- s eval: "\034X" + + + +=== TEST 237: \c\. +--- re: \c\. +--- s eval: "\034X" + + + +=== TEST 238: \c\ +--- re: \c\ +--- s eval: "\034X" + + + +=== TEST 239: \C +--- re: \C+ +--- s eval: "hello world!\n\r" +--- SKIP + + + +=== TEST 240: a{0,n} +--- re: a{0,3} +--- s: + + + +=== TEST 241: a{0,n} +--- re: a{0,3} +--- s: aaaa + + + +=== TEST 242: \0 in target string +--- re: a +--- s eval: "\0aaaa" + + + +=== TEST 243: temporary captures +--- re: (?:a|(ab))cd +--- s: babcd +--- temp_cap: [(1, -1)] [(1, -1)] [(1, -1)] [(1, -1)] + + + +=== TEST 244: /i - in +--- re: [abd-f]+ +--- s: bFEBADaC +--- flags: i + + + +=== TEST 245: /i - not in +--- re: [^abd-f]+ +--- s: bFEBADaCz- +--- flags: i + + + +=== TEST 246: /i - testinput1:1685 +--- re: word (?:[a-zA-Z0-9]+ ){0,300}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" +--- flags: i + + + +=== TEST 247: /i - char +--- re: hello +--- s: ZAhHElLO +--- flags: i + + + +=== TEST 248: /i - char +--- re: hello +--- s: ZAHhello +--- flags: i + + + +=== TEST 249: match early +--- re: \s+ +--- s eval: "abc \t\n\f\rd" +--- temp_cap chop +[(1, -1)] [(2, -1)] [(3, -1)] [(3, -1)](3, 4) [(3, -1)](3, 5) [(3, -1)](3, 6) [(3, -1)](3, 7) [(3, -1)](3, 8) + + + +=== TEST 250: pending match +--- re: abcde|bc +--- s eval: "abcdf" +--- temp_cap chop +[(0, -1)] [(0, -1)] [(0, -1)](1, 3) [(0, -1)](1, 3) + + + +=== TEST 251: \& +--- re: a\&b +--- s eval: 'a&b' + + + +=== TEST 252: [\&] +--- re: a[\&]b +--- s eval: 'a&b' + + + +=== TEST 253: \# \" \' +--- re: a\#\"\'b +--- s eval: 'a#"\'b' + + + +=== TEST 254: [\#\"\'] +--- re: [a\#\"\'b]{4} +--- s eval: 'a#"\'b' diff --git a/lib/sregex/t/02-p5-re_tests-01.t b/lib/sregex/t/02-p5-re_tests-01.t new file mode 100644 index 0000000..48cce18 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-01.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:9 +--- re: abc +--- s eval: "abc" + + + +=== TEST 2: re_tests:12 +--- re: abc +--- s eval: "xbc" + + + +=== TEST 3: re_tests:13 +--- re: abc +--- s eval: "axc" + + + +=== TEST 4: re_tests:14 +--- re: abc +--- s eval: "abx" + + + +=== TEST 5: re_tests:15 +--- re: abc +--- s eval: "xabcy" + + + +=== TEST 6: re_tests:18 +--- re: abc +--- s eval: "ababc" + + + +=== TEST 7: re_tests:21 +--- re: ab*c +--- s eval: "abc" + + + +=== TEST 8: re_tests:24 +--- re: ab*bc +--- s eval: "abc" + + + +=== TEST 9: re_tests:27 +--- re: ab*bc +--- s eval: "abbc" + + + +=== TEST 10: re_tests:30 +--- re: ab*bc +--- s eval: "abbbbc" + + + +=== TEST 11: re_tests:33 +--- re: .{1} +--- s eval: "abbbbc" + + + +=== TEST 12: re_tests:36 +--- re: .{3,4} +--- s eval: "abbbbc" + + + +=== TEST 13: re_tests:42 +--- re: \N {1} +--- s eval: "abbbbc" + + + +=== TEST 14: re_tests:48 +--- re: \N {3,4} +--- s eval: "abbbbc" + + + +=== TEST 15: re_tests:51 +--- re: ab{0,}bc +--- s eval: "abbbbc" + + + +=== TEST 16: re_tests:54 +--- re: ab+bc +--- s eval: "abbc" + + + +=== TEST 17: re_tests:57 +--- re: ab+bc +--- s eval: "abc" + + + +=== TEST 18: re_tests:58 +--- re: ab+bc +--- s eval: "abq" + + + +=== TEST 19: re_tests:59 +--- re: ab{1,}bc +--- s eval: "abq" + + + +=== TEST 20: re_tests:60 +--- re: ab+bc +--- s eval: "abbbbc" + + + +=== TEST 21: re_tests:63 +--- re: ab{1,}bc +--- s eval: "abbbbc" + + + +=== TEST 22: re_tests:66 +--- re: ab{1,3}bc +--- s eval: "abbbbc" + + + +=== TEST 23: re_tests:69 +--- re: ab{3,4}bc +--- s eval: "abbbbc" + + + +=== TEST 24: re_tests:72 +--- re: ab{4,5}bc +--- s eval: "abbbbc" + + + +=== TEST 25: re_tests:73 +--- re: ab?bc +--- s eval: "abbc" + + + +=== TEST 26: re_tests:74 +--- re: ab?bc +--- s eval: "abc" + + + +=== TEST 27: re_tests:75 +--- re: ab{0,1}bc +--- s eval: "abc" + + + +=== TEST 28: re_tests:76 +--- re: ab?bc +--- s eval: "abbbbc" + + + +=== TEST 29: re_tests:77 +--- re: ab?c +--- s eval: "abc" + + + +=== TEST 30: re_tests:78 +--- re: ab{0,1}c +--- s eval: "abc" + + + +=== TEST 31: re_tests:79 +--- re: ^abc$ +--- s eval: "abc" + + + +=== TEST 32: re_tests:80 +--- re: ^abc$ +--- s eval: "abcc" + + + +=== TEST 33: re_tests:81 +--- re: ^abc +--- s eval: "abcc" + + + +=== TEST 34: re_tests:82 +--- re: ^abc$ +--- s eval: "aabc" + + + +=== TEST 35: re_tests:83 +--- re: abc$ +--- s eval: "aabc" + + + +=== TEST 36: re_tests:84 +--- re: abc$ +--- s eval: "aabcd" + + + +=== TEST 37: re_tests:85 +--- re: ^ +--- s eval: "abc" + + + +=== TEST 38: re_tests:86 +--- re: $ +--- s eval: "abc" + + + +=== TEST 39: re_tests:87 +--- re: a.c +--- s eval: "abc" + + + +=== TEST 40: re_tests:88 +--- re: a.c +--- s eval: "axc" + + + +=== TEST 41: re_tests:89 +--- re: a\Nc +--- s eval: "abc" + + + +=== TEST 42: re_tests:90 +--- re: a\N c +--- s eval: "abc" + + + +=== TEST 43: re_tests:91 +--- re: a.*c +--- s eval: "axyzc" + + + +=== TEST 44: re_tests:92 +--- re: a\N*c +--- s eval: "axyzc" + + + +=== TEST 45: re_tests:93 +--- re: a\N *c +--- s eval: "axyzc" + + + +=== TEST 46: re_tests:94 +--- re: a.*c +--- s eval: "axyzd" + + + +=== TEST 47: re_tests:95 +--- re: a\N*c +--- s eval: "axyzd" + + + +=== TEST 48: re_tests:96 +--- re: a\N *c +--- s eval: "axyzd" + + + +=== TEST 49: re_tests:97 +--- re: a[bc]d +--- s eval: "abc" + + + +=== TEST 50: re_tests:98 +--- re: a[bc]d +--- s eval: "abd" + + + diff --git a/lib/sregex/t/02-p5-re_tests-02.t b/lib/sregex/t/02-p5-re_tests-02.t new file mode 100644 index 0000000..a156286 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-02.t @@ -0,0 +1,311 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:99 +--- re: a[b]d +--- s eval: "abd" + + + +=== TEST 2: re_tests:100 +--- re: [a][b][d] +--- s eval: "abd" + + + +=== TEST 3: re_tests:101 +--- re: .[b]. +--- s eval: "abd" + + + +=== TEST 4: re_tests:102 +--- re: .[b]. +--- s eval: "aBd" + + + +=== TEST 5: re_tests:105 +--- re: a[b-d]e +--- s eval: "abd" + + + +=== TEST 6: re_tests:106 +--- re: a[b-d]e +--- s eval: "ace" + + + +=== TEST 7: re_tests:107 +--- re: a[b-d] +--- s eval: "aac" + + + +=== TEST 8: re_tests:108 +--- re: a[-b] +--- s eval: "a-" + + + +=== TEST 9: re_tests:109 +--- re: a[b-] +--- s eval: "a-" + + + +=== TEST 10: re_tests:110 +--- re: a[b-a] +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 11: re_tests:111 +--- re: a[]b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 12: re_tests:112 +--- re: a[ +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 13: re_tests:113 +--- re: a] +--- s eval: "a]" + + + +=== TEST 14: re_tests:114 +--- re: a[]]b +--- s eval: "a]b" + + + +=== TEST 15: re_tests:115 +--- re: a[^bc]d +--- s eval: "aed" + + + +=== TEST 16: re_tests:116 +--- re: a[^bc]d +--- s eval: "abd" + + + +=== TEST 17: re_tests:117 +--- re: a[^-b]c +--- s eval: "adc" + + + +=== TEST 18: re_tests:118 +--- re: a[^-b]c +--- s eval: "a-c" + + + +=== TEST 19: re_tests:119 +--- re: a[^]b]c +--- s eval: "a]c" + + + +=== TEST 20: re_tests:120 +--- re: a[^]b]c +--- s eval: "adc" + + + +=== TEST 21: re_tests:121 +--- re: \ba\b +--- s eval: "a-" + + + +=== TEST 22: re_tests:122 +--- re: \ba\b +--- s eval: "-a" + + + +=== TEST 23: re_tests:123 +--- re: \ba\b +--- s eval: "-a-" + + + +=== TEST 24: re_tests:124 +--- re: \by\b +--- s eval: "xy" + + + +=== TEST 25: re_tests:125 +--- re: \by\b +--- s eval: "yz" + + + +=== TEST 26: re_tests:126 +--- re: \by\b +--- s eval: "xyz" + + + +=== TEST 27: re_tests:127 +--- re: \Ba\B +--- s eval: "a-" + + + +=== TEST 28: re_tests:128 +--- re: \Ba\B +--- s eval: "-a" + + + +=== TEST 29: re_tests:129 +--- re: \Ba\B +--- s eval: "-a-" + + + +=== TEST 30: re_tests:130 +--- re: \By\b +--- s eval: "xy" + + + +=== TEST 31: re_tests:134 +--- re: \by\B +--- s eval: "yz" + + + +=== TEST 32: re_tests:135 +--- re: \By\B +--- s eval: "xyz" + + + +=== TEST 33: re_tests:136 +--- re: \w +--- s eval: "a" + + + +=== TEST 34: re_tests:137 +--- re: \w +--- s eval: "-" + + + +=== TEST 35: re_tests:138 +--- re: \W +--- s eval: "a" + + + +=== TEST 36: re_tests:139 +--- re: \W +--- s eval: "-" + + + +=== TEST 37: re_tests:140 +--- re: a\sb +--- s eval: "a b" + + + +=== TEST 38: re_tests:141 +--- re: a\sb +--- s eval: "a-b" + + + +=== TEST 39: re_tests:142 +--- re: a\Sb +--- s eval: "a b" + + + +=== TEST 40: re_tests:143 +--- re: a\Sb +--- s eval: "a-b" + + + +=== TEST 41: re_tests:144 +--- re: \d +--- s eval: "1" + + + +=== TEST 42: re_tests:145 +--- re: \d +--- s eval: "-" + + + +=== TEST 43: re_tests:146 +--- re: \D +--- s eval: "1" + + + +=== TEST 44: re_tests:147 +--- re: \D +--- s eval: "-" + + + +=== TEST 45: re_tests:148 +--- re: [\w] +--- s eval: "a" + + + +=== TEST 46: re_tests:149 +--- re: [\w] +--- s eval: "-" + + + +=== TEST 47: re_tests:150 +--- re: [\W] +--- s eval: "a" + + + +=== TEST 48: re_tests:151 +--- re: [\W] +--- s eval: "-" + + + +=== TEST 49: re_tests:152 +--- re: a[\s]b +--- s eval: "a b" + + + +=== TEST 50: re_tests:153 +--- re: a[\s]b +--- s eval: "a-b" + + + diff --git a/lib/sregex/t/02-p5-re_tests-03.t b/lib/sregex/t/02-p5-re_tests-03.t new file mode 100644 index 0000000..4d9ffe2 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-03.t @@ -0,0 +1,316 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:154 +--- re: a[\S]b +--- s eval: "a b" + + + +=== TEST 2: re_tests:155 +--- re: a[\S]b +--- s eval: "a-b" + + + +=== TEST 3: re_tests:156 +--- re: [\d] +--- s eval: "1" + + + +=== TEST 4: re_tests:157 +--- re: [\d] +--- s eval: "-" + + + +=== TEST 5: re_tests:158 +--- re: [\D] +--- s eval: "1" + + + +=== TEST 6: re_tests:159 +--- re: [\D] +--- s eval: "-" + + + +=== TEST 7: re_tests:160 +--- re: ab|cd +--- s eval: "abc" + + + +=== TEST 8: re_tests:161 +--- re: ab|cd +--- s eval: "abcd" + + + +=== TEST 9: re_tests:162 +--- re: ()ef +--- s eval: "def" + + + +=== TEST 10: re_tests:167 +--- re: *a +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 11: re_tests:168 +--- re: (|*)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 12: re_tests:169 +--- re: (*)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 13: re_tests:170 +--- re: $b +--- s eval: "b" + + + +=== TEST 14: re_tests:171 +--- re: a\ +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 15: re_tests:172 +--- re: a\(b +--- s eval: "a(b" + + + +=== TEST 16: re_tests:173 +--- re: a\(*b +--- s eval: "ab" + + + +=== TEST 17: re_tests:174 +--- re: a\(*b +--- s eval: "a((b" + + + +=== TEST 18: re_tests:175 +--- re: a\\b +--- s eval: "a\\b" + + + +=== TEST 19: re_tests:176 +--- re: abc) +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 20: re_tests:177 +--- re: (abc +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 21: re_tests:178 +--- re: ((a)) +--- s eval: "abc" + + + +=== TEST 22: re_tests:183 +--- re: (a)b(c) +--- s eval: "abc" + + + +=== TEST 23: re_tests:186 +--- re: a+b+c +--- s eval: "aabbabc" + + + +=== TEST 24: re_tests:187 +--- re: a{1,}b{1,}c +--- s eval: "aabbabc" + + + +=== TEST 25: re_tests:188 +--- re: a** +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 26: re_tests:189 +--- re: a.+?c +--- s eval: "abcabc" + + + +=== TEST 27: re_tests:190 +--- re: (a+|b)* +--- s eval: "ab" + + + +=== TEST 28: re_tests:195 +--- re: (a+|b){0,} +--- s eval: "ab" + + + +=== TEST 29: re_tests:196 +--- re: (a+|b)+ +--- s eval: "ab" + + + +=== TEST 30: re_tests:197 +--- re: (a+|b){1,} +--- s eval: "ab" + + + +=== TEST 31: re_tests:198 +--- re: (a+|b)? +--- s eval: "ab" + + + +=== TEST 32: re_tests:199 +--- re: (a+|b){0,1} +--- s eval: "ab" + + + +=== TEST 33: re_tests:200 +--- re: )( +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 34: re_tests:201 +--- re: [^ab]* +--- s eval: "cde" + + + +=== TEST 35: re_tests:202 +--- re: abc +--- s eval: "" + + + +=== TEST 36: re_tests:203 +--- re: a* +--- s eval: "" + + + +=== TEST 37: re_tests:204 +--- re: ([abc])*d +--- s eval: "abbbcd" + + + +=== TEST 38: re_tests:205 +--- re: ([abc])*bcd +--- s eval: "abcd" + + + +=== TEST 39: re_tests:206 +--- re: a|b|c|d|e +--- s eval: "e" + + + +=== TEST 40: re_tests:207 +--- re: (a|b|c|d|e)f +--- s eval: "ef" + + + +=== TEST 41: re_tests:212 +--- re: abcd*efg +--- s eval: "abcdefg" + + + +=== TEST 42: re_tests:213 +--- re: ab* +--- s eval: "xabyabbbz" + + + +=== TEST 43: re_tests:214 +--- re: ab* +--- s eval: "xayabbbz" + + + +=== TEST 44: re_tests:215 +--- re: (ab|cd)e +--- s eval: "abcde" + + + +=== TEST 45: re_tests:216 +--- re: [abhgefdc]ij +--- s eval: "hij" + + + +=== TEST 46: re_tests:217 +--- re: ^(ab|cd)e +--- s eval: "abcde" + + + +=== TEST 47: re_tests:218 +--- re: (abc|)ef +--- s eval: "abcdef" + + + +=== TEST 48: re_tests:219 +--- re: (a|b)c*d +--- s eval: "abcd" + + + +=== TEST 49: re_tests:220 +--- re: (ab|ab*)bc +--- s eval: "abc" + + + +=== TEST 50: re_tests:221 +--- re: a([bc]*)c* +--- s eval: "abc" + + + diff --git a/lib/sregex/t/02-p5-re_tests-04.t b/lib/sregex/t/02-p5-re_tests-04.t new file mode 100644 index 0000000..cb933cd --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-04.t @@ -0,0 +1,331 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:222 +--- re: a([bc]*)(c*d) +--- s eval: "abcd" + + + +=== TEST 2: re_tests:229 +--- re: a([bc]+)(c*d) +--- s eval: "abcd" + + + +=== TEST 3: re_tests:230 +--- re: a([bc]*)(c+d) +--- s eval: "abcd" + + + +=== TEST 4: re_tests:237 +--- re: a[bcd]*dcdcde +--- s eval: "adcdcde" + + + +=== TEST 5: re_tests:238 +--- re: a[bcd]+dcdcde +--- s eval: "adcdcde" + + + +=== TEST 6: re_tests:239 +--- re: (ab|a)b*c +--- s eval: "abc" + + + +=== TEST 7: re_tests:244 +--- re: ((a)(b)c)(d) +--- s eval: "abcd" + + + +=== TEST 8: re_tests:255 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "alpha" + + + +=== TEST 9: re_tests:256 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "abh" + + + +=== TEST 10: re_tests:257 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effgz" + + + +=== TEST 11: re_tests:258 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "ij" + + + +=== TEST 12: re_tests:259 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effg" + + + +=== TEST 13: re_tests:260 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "bcdd" + + + +=== TEST 14: re_tests:261 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "reffgz" + + + +=== TEST 15: re_tests:262 +--- re: ((((((((((a)))))))))) +--- s eval: "a" + + + +=== TEST 16: re_tests:268 +--- re: ((((((((((a))))))))))\041 +--- s eval: "aa" + + + +=== TEST 17: re_tests:269 +--- re: ((((((((((a))))))))))\041 +--- s eval: "a!" + + + +=== TEST 18: re_tests:270 +--- re: (((((((((a))))))))) +--- s eval: "a" + + + +=== TEST 19: re_tests:271 +--- re: multiple words of text +--- s eval: "uh-uh" + + + +=== TEST 20: re_tests:272 +--- re: multiple words +--- s eval: "multiple words, yeah" + + + +=== TEST 21: re_tests:273 +--- re: (.*)c(.*) +--- s eval: "abcde" + + + +=== TEST 22: re_tests:274 +--- re: \((.*), (.*)\) +--- s eval: "(a, b)" + + + +=== TEST 23: re_tests:275 +--- re: [k] +--- s eval: "ab" + + + +=== TEST 24: re_tests:276 +--- re: abcd +--- s eval: "abcd" + + + +=== TEST 25: re_tests:277 +--- re: a(bc)d +--- s eval: "abcd" + + + +=== TEST 26: re_tests:278 +--- re: a[-]?c +--- s eval: "ac" + + + +=== TEST 27: re_tests:285 +--- re: \g{1} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 28: re_tests:287 +--- re: \g0 +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 29: re_tests:289 +--- re: \g{0} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 30: re_tests:302 +--- re: (a)|(b) +--- s eval: "b" + + + +=== TEST 31: re_tests:308 +--- re: abc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 32: re_tests:309 +--- re: abc +--- s eval: "XBC" +--- flags: i + + + +=== TEST 33: re_tests:310 +--- re: abc +--- s eval: "AXC" +--- flags: i + + + +=== TEST 34: re_tests:311 +--- re: abc +--- s eval: "ABX" +--- flags: i + + + +=== TEST 35: re_tests:312 +--- re: abc +--- s eval: "XABCY" +--- flags: i + + + +=== TEST 36: re_tests:313 +--- re: abc +--- s eval: "ABABC" +--- flags: i + + + +=== TEST 37: re_tests:314 +--- re: ab*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 38: re_tests:315 +--- re: ab*bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 39: re_tests:316 +--- re: ab*bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 40: re_tests:317 +--- re: ab*?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 41: re_tests:318 +--- re: ab{0,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 42: re_tests:319 +--- re: ab+?bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 43: re_tests:320 +--- re: ab+bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 44: re_tests:321 +--- re: ab+bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 45: re_tests:322 +--- re: ab{1,}bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 46: re_tests:323 +--- re: ab+bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 47: re_tests:324 +--- re: ab{1,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 48: re_tests:325 +--- re: ab{1,3}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 49: re_tests:326 +--- re: ab{3,4}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 50: re_tests:327 +--- re: ab{4,5}?bc +--- s eval: "ABBBBC" +--- flags: i + + + diff --git a/lib/sregex/t/02-p5-re_tests-05.t b/lib/sregex/t/02-p5-re_tests-05.t new file mode 100644 index 0000000..a6aa3d5 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-05.t @@ -0,0 +1,367 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:328 +--- re: ab??bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 2: re_tests:329 +--- re: ab??bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 3: re_tests:330 +--- re: ab{0,1}?bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 4: re_tests:331 +--- re: ab??bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 5: re_tests:332 +--- re: ab??c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 6: re_tests:333 +--- re: ab{0,1}?c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 7: re_tests:334 +--- re: ^abc$ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 8: re_tests:335 +--- re: ^abc$ +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 9: re_tests:336 +--- re: ^abc +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 10: re_tests:337 +--- re: ^abc$ +--- s eval: "AABC" +--- flags: i + + + +=== TEST 11: re_tests:338 +--- re: abc$ +--- s eval: "AABC" +--- flags: i + + + +=== TEST 12: re_tests:339 +--- re: ^ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 13: re_tests:340 +--- re: $ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 14: re_tests:341 +--- re: a.c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 15: re_tests:342 +--- re: a.c +--- s eval: "AXC" +--- flags: i + + + +=== TEST 16: re_tests:343 +--- re: a\Nc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 17: re_tests:344 +--- re: a.*?c +--- s eval: "AXYZC" +--- flags: i + + + +=== TEST 18: re_tests:345 +--- re: a.*c +--- s eval: "AXYZD" +--- flags: i + + + +=== TEST 19: re_tests:346 +--- re: a[bc]d +--- s eval: "ABC" +--- flags: i + + + +=== TEST 20: re_tests:347 +--- re: a[bc]d +--- s eval: "ABD" +--- flags: i + + + +=== TEST 21: re_tests:348 +--- re: a[b-d]e +--- s eval: "ABD" +--- flags: i + + + +=== TEST 22: re_tests:349 +--- re: a[b-d]e +--- s eval: "ACE" +--- flags: i + + + +=== TEST 23: re_tests:350 +--- re: a[b-d] +--- s eval: "AAC" +--- flags: i + + + +=== TEST 24: re_tests:351 +--- re: a[-b] +--- s eval: "A-" +--- flags: i + + + +=== TEST 25: re_tests:352 +--- re: a[b-] +--- s eval: "A-" +--- flags: i + + + +=== TEST 26: re_tests:353 +--- re: a[b-a] +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 27: re_tests:354 +--- re: a[]b +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 28: re_tests:355 +--- re: a[ +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 29: re_tests:356 +--- re: a] +--- s eval: "A]" +--- flags: i + + + +=== TEST 30: re_tests:357 +--- re: a[]]b +--- s eval: "A]B" +--- flags: i + + + +=== TEST 31: re_tests:358 +--- re: a[^bc]d +--- s eval: "AED" +--- flags: i + + + +=== TEST 32: re_tests:359 +--- re: a[^bc]d +--- s eval: "ABD" +--- flags: i + + + +=== TEST 33: re_tests:360 +--- re: a[^-b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 34: re_tests:361 +--- re: a[^-b]c +--- s eval: "A-C" +--- flags: i + + + +=== TEST 35: re_tests:362 +--- re: a[^]b]c +--- s eval: "A]C" +--- flags: i + + + +=== TEST 36: re_tests:363 +--- re: a[^]b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 37: re_tests:364 +--- re: ab|cd +--- s eval: "ABC" +--- flags: i + + + +=== TEST 38: re_tests:365 +--- re: ab|cd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 39: re_tests:366 +--- re: ()ef +--- s eval: "DEF" +--- flags: i + + + +=== TEST 40: re_tests:367 +--- re: *a +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 41: re_tests:368 +--- re: (|*)b +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 42: re_tests:369 +--- re: (*)b +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 43: re_tests:370 +--- re: $b +--- s eval: "B" +--- flags: i + + + +=== TEST 44: re_tests:371 +--- re: a\ +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 45: re_tests:372 +--- re: a\(b +--- s eval: "A(B" +--- flags: i + + + +=== TEST 46: re_tests:373 +--- re: a\(*b +--- s eval: "AB" +--- flags: i + + + +=== TEST 47: re_tests:374 +--- re: a\(*b +--- s eval: "A((B" +--- flags: i + + + +=== TEST 48: re_tests:375 +--- re: a\\b +--- s eval: "A\\B" +--- flags: i + + + +=== TEST 49: re_tests:376 +--- re: abc) +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 50: re_tests:377 +--- re: (abc +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + diff --git a/lib/sregex/t/02-p5-re_tests-06.t b/lib/sregex/t/02-p5-re_tests-06.t new file mode 100644 index 0000000..265a1bc --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-06.t @@ -0,0 +1,360 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:378 +--- re: ((a)) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 2: re_tests:379 +--- re: (a)b(c) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 3: re_tests:380 +--- re: a+b+c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 4: re_tests:381 +--- re: a{1,}b{1,}c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 5: re_tests:382 +--- re: a** +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 6: re_tests:383 +--- re: a.+?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 7: re_tests:384 +--- re: a.*?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 8: re_tests:385 +--- re: a.{0,5}?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 9: re_tests:386 +--- re: (a+|b)* +--- s eval: "AB" +--- flags: i + + + +=== TEST 10: re_tests:387 +--- re: (a+|b){0,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 11: re_tests:388 +--- re: (a+|b)+ +--- s eval: "AB" +--- flags: i + + + +=== TEST 12: re_tests:389 +--- re: (a+|b){1,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 13: re_tests:390 +--- re: (a+|b)? +--- s eval: "AB" +--- flags: i + + + +=== TEST 14: re_tests:391 +--- re: (a+|b){0,1} +--- s eval: "AB" +--- flags: i + + + +=== TEST 15: re_tests:392 +--- re: (a+|b){0,1}? +--- s eval: "AB" +--- flags: i + + + +=== TEST 16: re_tests:393 +--- re: )( +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 17: re_tests:394 +--- re: [^ab]* +--- s eval: "CDE" +--- flags: i + + + +=== TEST 18: re_tests:395 +--- re: abc +--- s eval: "" +--- flags: i + + + +=== TEST 19: re_tests:396 +--- re: a* +--- s eval: "" +--- flags: i + + + +=== TEST 20: re_tests:397 +--- re: ([abc])*d +--- s eval: "ABBBCD" +--- flags: i + + + +=== TEST 21: re_tests:398 +--- re: ([abc])*bcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 22: re_tests:399 +--- re: a|b|c|d|e +--- s eval: "E" +--- flags: i + + + +=== TEST 23: re_tests:400 +--- re: (a|b|c|d|e)f +--- s eval: "EF" +--- flags: i + + + +=== TEST 24: re_tests:401 +--- re: abcd*efg +--- s eval: "ABCDEFG" +--- flags: i + + + +=== TEST 25: re_tests:402 +--- re: ab* +--- s eval: "XABYABBBZ" +--- flags: i + + + +=== TEST 26: re_tests:403 +--- re: ab* +--- s eval: "XAYABBBZ" +--- flags: i + + + +=== TEST 27: re_tests:404 +--- re: (ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 28: re_tests:405 +--- re: [abhgefdc]ij +--- s eval: "HIJ" +--- flags: i + + + +=== TEST 29: re_tests:406 +--- re: ^(ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 30: re_tests:407 +--- re: (abc|)ef +--- s eval: "ABCDEF" +--- flags: i + + + +=== TEST 31: re_tests:408 +--- re: (a|b)c*d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 32: re_tests:409 +--- re: (ab|ab*)bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 33: re_tests:410 +--- re: a([bc]*)c* +--- s eval: "ABC" +--- flags: i + + + +=== TEST 34: re_tests:411 +--- re: a([bc]*)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 35: re_tests:412 +--- re: a([bc]+)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 36: re_tests:413 +--- re: a([bc]*)(c+d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 37: re_tests:414 +--- re: a[bcd]*dcdcde +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 38: re_tests:415 +--- re: a[bcd]+dcdcde +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 39: re_tests:416 +--- re: (ab|a)b*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 40: re_tests:417 +--- re: ((a)(b)c)(d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 41: re_tests:418 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "ALPHA" +--- flags: i + + + +=== TEST 42: re_tests:419 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "ABH" +--- flags: i + + + +=== TEST 43: re_tests:420 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFGZ" +--- flags: i + + + +=== TEST 44: re_tests:421 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "IJ" +--- flags: i + + + +=== TEST 45: re_tests:422 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFG" +--- flags: i + + + +=== TEST 46: re_tests:423 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "BCDD" +--- flags: i + + + +=== TEST 47: re_tests:424 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "REFFGZ" +--- flags: i + + + +=== TEST 48: re_tests:425 +--- re: ((((((((((a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 49: re_tests:427 +--- re: ((((((((((a))))))))))\041 +--- s eval: "AA" +--- flags: i + + + +=== TEST 50: re_tests:428 +--- re: ((((((((((a))))))))))\041 +--- s eval: "A!" +--- flags: i + + + diff --git a/lib/sregex/t/02-p5-re_tests-07.t b/lib/sregex/t/02-p5-re_tests-07.t new file mode 100644 index 0000000..1839178 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-07.t @@ -0,0 +1,322 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:429 +--- re: (((((((((a))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 2: re_tests:430 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 3: re_tests:431 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c)))))))))) +--- s eval: "C" +--- flags: i + + + +=== TEST 4: re_tests:432 +--- re: multiple words of text +--- s eval: "UH-UH" +--- flags: i + + + +=== TEST 5: re_tests:433 +--- re: multiple words +--- s eval: "MULTIPLE WORDS, YEAH" +--- flags: i + + + +=== TEST 6: re_tests:434 +--- re: (.*)c(.*) +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 7: re_tests:435 +--- re: \((.*), (.*)\) +--- s eval: "(A, B)" +--- flags: i + + + +=== TEST 8: re_tests:436 +--- re: [k] +--- s eval: "AB" +--- flags: i + + + +=== TEST 9: re_tests:437 +--- re: abcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 10: re_tests:438 +--- re: a(bc)d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 11: re_tests:439 +--- re: a[-]?c +--- s eval: "AC" +--- flags: i + + + +=== TEST 12: re_tests:446 +--- re: a(?:b|c|d)(.) +--- s eval: "ace" + + + +=== TEST 13: re_tests:447 +--- re: a(?:b|c|d)*(.) +--- s eval: "ace" + + + +=== TEST 14: re_tests:448 +--- re: a(?:b|c|d)+?(.) +--- s eval: "ace" + + + +=== TEST 15: re_tests:449 +--- re: a(?:b|c|d)+?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 16: re_tests:450 +--- re: a(?:b|c|d)+(.) +--- s eval: "acdbcdbe" + + + +=== TEST 17: re_tests:451 +--- re: a(?:b|c|d){2}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 18: re_tests:452 +--- re: a(?:b|c|d){4,5}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 19: re_tests:453 +--- re: a(?:b|c|d){4,5}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 20: re_tests:454 +--- re: ((foo)|(bar))* +--- s eval: "foobar" + + + +=== TEST 21: re_tests:455 +--- re: (? +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 22: re_tests:456 +--- re: a(?:b|c|d){6,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 23: re_tests:457 +--- re: a(?:b|c|d){6,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 24: re_tests:458 +--- re: a(?:b|c|d){5,6}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 25: re_tests:459 +--- re: a(?:b|c|d){5,6}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 26: re_tests:460 +--- re: a(?:b|c|d){5,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 27: re_tests:461 +--- re: a(?:b|c|d){5,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 28: re_tests:462 +--- re: a(?:b|(c|e){1,2}?|d)+?(.) +--- s eval: "ace" + + + +=== TEST 29: re_tests:463 +--- re: ^(.+)?B +--- s eval: "AB" + + + +=== TEST 30: re_tests:464 +--- re: ^([^a-z])|(\^)$ +--- s eval: "." + + + +=== TEST 31: re_tests:465 +--- re: ^[<>]& +--- s eval: "<&OUT" + + + +=== TEST 32: re_tests:472 +--- re: ((a{4})+) +--- s eval: "aaaaaaaaa" + + + +=== TEST 33: re_tests:473 +--- re: (((aa){2})+) +--- s eval: "aaaaaaaaaa" + + + +=== TEST 34: re_tests:474 +--- re: (((a{2}){2})+) +--- s eval: "aaaaaaaaaa" + + + +=== TEST 35: re_tests:475 +--- re: (?:(f)(o)(o)|(b)(a)(r))* +--- s eval: "foobar" + + + +=== TEST 36: re_tests:483 +--- re: (?<%)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 37: re_tests:484 +--- re: (?:..)*a +--- s eval: "aba" + + + +=== TEST 38: re_tests:485 +--- re: (?:..)*?a +--- s eval: "aba" + + + +=== TEST 39: re_tests:487 +--- re: ^(){3,5} +--- s eval: "abc" + + + +=== TEST 40: re_tests:488 +--- re: ^(a+)*ax +--- s eval: "aax" + + + +=== TEST 41: re_tests:489 +--- re: ^((a|b)+)*ax +--- s eval: "aax" + + + +=== TEST 42: re_tests:490 +--- re: ^((a|bc)+)*ax +--- s eval: "aax" + + + +=== TEST 43: re_tests:491 +--- re: (a|x)*ab +--- s eval: "cab" + + + +=== TEST 44: re_tests:492 +--- re: (a)*ab +--- s eval: "cab" + + + +=== TEST 45: re_tests:531 +--- re: (?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b))) +--- s eval: "cabbbb" + + + +=== TEST 46: re_tests:532 +--- re: (?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb))) +--- s eval: "caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + + + +=== TEST 47: re_tests:535 +--- re: foo\w*\d{4}baz +--- s eval: "foobar1234baz" + + + +=== TEST 48: re_tests:537 +--- re: a(?{)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 49: re_tests:544 +--- re: x(~~)*(?:(?:F)?)? +--- s eval: "x~~" + + + +=== TEST 50: re_tests:552 +--- re: ^(?:a?b?)*$ +--- s eval: "a--" + + + diff --git a/lib/sregex/t/02-p5-re_tests-08.t b/lib/sregex/t/02-p5-re_tests-08.t new file mode 100644 index 0000000..0de9427 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-08.t @@ -0,0 +1,311 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:565 +--- re: ^b +--- s eval: "a\nb\nc\n" + + + +=== TEST 2: re_tests:566 +--- re: ()^b +--- s eval: "a\nb\nc\n" + + + +=== TEST 3: re_tests:595 +--- re: (\w+:)+ +--- s eval: "one:" + + + +=== TEST 4: re_tests:599 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd:" + + + +=== TEST 5: re_tests:600 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd" + + + +=== TEST 6: re_tests:601 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "xy:z:::abcd" + + + +=== TEST 7: re_tests:602 +--- re: ^[^bcd]*(c+) +--- s eval: "aexycd" + + + +=== TEST 8: re_tests:603 +--- re: (a*)b+ +--- s eval: "caab" + + + +=== TEST 9: re_tests:610 +--- re: (>a+)ab +--- s eval: "aaab" + + + +=== TEST 10: re_tests:612 +--- re: ([[:]+) +--- s eval: "a:[b]:" + + + +=== TEST 11: re_tests:613 +--- re: ([[=]+) +--- s eval: "a=[b]=" + + + +=== TEST 12: re_tests:614 +--- re: ([[.]+) +--- s eval: "a.[b]." + + + +=== TEST 13: re_tests:615 +--- re: [a[:xyz: +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 14: re_tests:617 +--- re: [a[:]b[:c] +--- s eval: "abc" + + + +=== TEST 15: re_tests:651 +--- re: a{37,17} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 16: re_tests:652 +--- re: a{37,0} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 17: re_tests:654 +--- re: \z +--- s eval: "a\nb\n" + + + +=== TEST 18: re_tests:655 +--- re: $ +--- s eval: "a\nb\n" + + + +=== TEST 19: re_tests:657 +--- re: \z +--- s eval: "b\na\n" + + + +=== TEST 20: re_tests:658 +--- re: $ +--- s eval: "b\na\n" + + + +=== TEST 21: re_tests:660 +--- re: \z +--- s eval: "b\na" + + + +=== TEST 22: re_tests:661 +--- re: $ +--- s eval: "b\na" + + + +=== TEST 23: re_tests:663 +--- re: \z +--- s eval: "a\nb\n" + + + +=== TEST 24: re_tests:664 +--- re: $ +--- s eval: "a\nb\n" + + + +=== TEST 25: re_tests:666 +--- re: \z +--- s eval: "b\na\n" + + + +=== TEST 26: re_tests:667 +--- re: $ +--- s eval: "b\na\n" + + + +=== TEST 27: re_tests:669 +--- re: \z +--- s eval: "b\na" + + + +=== TEST 28: re_tests:670 +--- re: $ +--- s eval: "b\na" + + + +=== TEST 29: re_tests:672 +--- re: a\z +--- s eval: "a\nb\n" + + + +=== TEST 30: re_tests:673 +--- re: a$ +--- s eval: "a\nb\n" + + + +=== TEST 31: re_tests:675 +--- re: a\z +--- s eval: "b\na\n" + + + +=== TEST 32: re_tests:676 +--- re: a$ +--- s eval: "b\na\n" + + + +=== TEST 33: re_tests:678 +--- re: a\z +--- s eval: "b\na" + + + +=== TEST 34: re_tests:679 +--- re: a$ +--- s eval: "b\na" + + + +=== TEST 35: re_tests:681 +--- re: a\z +--- s eval: "a\nb\n" + + + +=== TEST 36: re_tests:682 +--- re: a$ +--- s eval: "a\nb\n" + + + +=== TEST 37: re_tests:684 +--- re: a\z +--- s eval: "b\na\n" + + + +=== TEST 38: re_tests:685 +--- re: a$ +--- s eval: "b\na\n" + + + +=== TEST 39: re_tests:687 +--- re: a\z +--- s eval: "b\na" + + + +=== TEST 40: re_tests:688 +--- re: a$ +--- s eval: "b\na" + + + +=== TEST 41: re_tests:690 +--- re: aa\z +--- s eval: "aa\nb\n" + + + +=== TEST 42: re_tests:691 +--- re: aa$ +--- s eval: "aa\nb\n" + + + +=== TEST 43: re_tests:693 +--- re: aa\z +--- s eval: "b\naa\n" + + + +=== TEST 44: re_tests:694 +--- re: aa$ +--- s eval: "b\naa\n" + + + +=== TEST 45: re_tests:696 +--- re: aa\z +--- s eval: "b\naa" + + + +=== TEST 46: re_tests:697 +--- re: aa$ +--- s eval: "b\naa" + + + +=== TEST 47: re_tests:699 +--- re: aa\z +--- s eval: "aa\nb\n" + + + +=== TEST 48: re_tests:700 +--- re: aa$ +--- s eval: "aa\nb\n" + + + +=== TEST 49: re_tests:702 +--- re: aa\z +--- s eval: "b\naa\n" + + + +=== TEST 50: re_tests:703 +--- re: aa$ +--- s eval: "b\naa\n" + + + diff --git a/lib/sregex/t/02-p5-re_tests-09.t b/lib/sregex/t/02-p5-re_tests-09.t new file mode 100644 index 0000000..3932261 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-09.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:705 +--- re: aa\z +--- s eval: "b\naa" + + + +=== TEST 2: re_tests:706 +--- re: aa$ +--- s eval: "b\naa" + + + +=== TEST 3: re_tests:708 +--- re: aa\z +--- s eval: "ac\nb\n" + + + +=== TEST 4: re_tests:709 +--- re: aa$ +--- s eval: "ac\nb\n" + + + +=== TEST 5: re_tests:711 +--- re: aa\z +--- s eval: "b\nac\n" + + + +=== TEST 6: re_tests:712 +--- re: aa$ +--- s eval: "b\nac\n" + + + +=== TEST 7: re_tests:714 +--- re: aa\z +--- s eval: "b\nac" + + + +=== TEST 8: re_tests:715 +--- re: aa$ +--- s eval: "b\nac" + + + +=== TEST 9: re_tests:717 +--- re: aa\z +--- s eval: "ac\nb\n" + + + +=== TEST 10: re_tests:718 +--- re: aa$ +--- s eval: "ac\nb\n" + + + +=== TEST 11: re_tests:720 +--- re: aa\z +--- s eval: "b\nac\n" + + + +=== TEST 12: re_tests:721 +--- re: aa$ +--- s eval: "b\nac\n" + + + +=== TEST 13: re_tests:723 +--- re: aa\z +--- s eval: "b\nac" + + + +=== TEST 14: re_tests:724 +--- re: aa$ +--- s eval: "b\nac" + + + +=== TEST 15: re_tests:726 +--- re: aa\z +--- s eval: "ca\nb\n" + + + +=== TEST 16: re_tests:727 +--- re: aa$ +--- s eval: "ca\nb\n" + + + +=== TEST 17: re_tests:729 +--- re: aa\z +--- s eval: "b\nca\n" + + + +=== TEST 18: re_tests:730 +--- re: aa$ +--- s eval: "b\nca\n" + + + +=== TEST 19: re_tests:732 +--- re: aa\z +--- s eval: "b\nca" + + + +=== TEST 20: re_tests:733 +--- re: aa$ +--- s eval: "b\nca" + + + +=== TEST 21: re_tests:735 +--- re: aa\z +--- s eval: "ca\nb\n" + + + +=== TEST 22: re_tests:736 +--- re: aa$ +--- s eval: "ca\nb\n" + + + +=== TEST 23: re_tests:738 +--- re: aa\z +--- s eval: "b\nca\n" + + + +=== TEST 24: re_tests:739 +--- re: aa$ +--- s eval: "b\nca\n" + + + +=== TEST 25: re_tests:741 +--- re: aa\z +--- s eval: "b\nca" + + + +=== TEST 26: re_tests:742 +--- re: aa$ +--- s eval: "b\nca" + + + +=== TEST 27: re_tests:744 +--- re: ab\z +--- s eval: "ab\nb\n" + + + +=== TEST 28: re_tests:745 +--- re: ab$ +--- s eval: "ab\nb\n" + + + +=== TEST 29: re_tests:747 +--- re: ab\z +--- s eval: "b\nab\n" + + + +=== TEST 30: re_tests:748 +--- re: ab$ +--- s eval: "b\nab\n" + + + +=== TEST 31: re_tests:750 +--- re: ab\z +--- s eval: "b\nab" + + + +=== TEST 32: re_tests:751 +--- re: ab$ +--- s eval: "b\nab" + + + +=== TEST 33: re_tests:753 +--- re: ab\z +--- s eval: "ab\nb\n" + + + +=== TEST 34: re_tests:754 +--- re: ab$ +--- s eval: "ab\nb\n" + + + +=== TEST 35: re_tests:756 +--- re: ab\z +--- s eval: "b\nab\n" + + + +=== TEST 36: re_tests:757 +--- re: ab$ +--- s eval: "b\nab\n" + + + +=== TEST 37: re_tests:759 +--- re: ab\z +--- s eval: "b\nab" + + + +=== TEST 38: re_tests:760 +--- re: ab$ +--- s eval: "b\nab" + + + +=== TEST 39: re_tests:762 +--- re: ab\z +--- s eval: "ac\nb\n" + + + +=== TEST 40: re_tests:763 +--- re: ab$ +--- s eval: "ac\nb\n" + + + +=== TEST 41: re_tests:765 +--- re: ab\z +--- s eval: "b\nac\n" + + + +=== TEST 42: re_tests:766 +--- re: ab$ +--- s eval: "b\nac\n" + + + +=== TEST 43: re_tests:768 +--- re: ab\z +--- s eval: "b\nac" + + + +=== TEST 44: re_tests:769 +--- re: ab$ +--- s eval: "b\nac" + + + +=== TEST 45: re_tests:771 +--- re: ab\z +--- s eval: "ac\nb\n" + + + +=== TEST 46: re_tests:772 +--- re: ab$ +--- s eval: "ac\nb\n" + + + +=== TEST 47: re_tests:774 +--- re: ab\z +--- s eval: "b\nac\n" + + + +=== TEST 48: re_tests:775 +--- re: ab$ +--- s eval: "b\nac\n" + + + +=== TEST 49: re_tests:777 +--- re: ab\z +--- s eval: "b\nac" + + + +=== TEST 50: re_tests:778 +--- re: ab$ +--- s eval: "b\nac" + + + diff --git a/lib/sregex/t/02-p5-re_tests-10.t b/lib/sregex/t/02-p5-re_tests-10.t new file mode 100644 index 0000000..e6fde18 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-10.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:780 +--- re: ab\z +--- s eval: "ca\nb\n" + + + +=== TEST 2: re_tests:781 +--- re: ab$ +--- s eval: "ca\nb\n" + + + +=== TEST 3: re_tests:783 +--- re: ab\z +--- s eval: "b\nca\n" + + + +=== TEST 4: re_tests:784 +--- re: ab$ +--- s eval: "b\nca\n" + + + +=== TEST 5: re_tests:786 +--- re: ab\z +--- s eval: "b\nca" + + + +=== TEST 6: re_tests:787 +--- re: ab$ +--- s eval: "b\nca" + + + +=== TEST 7: re_tests:789 +--- re: ab\z +--- s eval: "ca\nb\n" + + + +=== TEST 8: re_tests:790 +--- re: ab$ +--- s eval: "ca\nb\n" + + + +=== TEST 9: re_tests:792 +--- re: ab\z +--- s eval: "b\nca\n" + + + +=== TEST 10: re_tests:793 +--- re: ab$ +--- s eval: "b\nca\n" + + + +=== TEST 11: re_tests:795 +--- re: ab\z +--- s eval: "b\nca" + + + +=== TEST 12: re_tests:796 +--- re: ab$ +--- s eval: "b\nca" + + + +=== TEST 13: re_tests:798 +--- re: abb\z +--- s eval: "abb\nb\n" + + + +=== TEST 14: re_tests:799 +--- re: abb$ +--- s eval: "abb\nb\n" + + + +=== TEST 15: re_tests:801 +--- re: abb\z +--- s eval: "b\nabb\n" + + + +=== TEST 16: re_tests:802 +--- re: abb$ +--- s eval: "b\nabb\n" + + + +=== TEST 17: re_tests:804 +--- re: abb\z +--- s eval: "b\nabb" + + + +=== TEST 18: re_tests:805 +--- re: abb$ +--- s eval: "b\nabb" + + + +=== TEST 19: re_tests:807 +--- re: abb\z +--- s eval: "abb\nb\n" + + + +=== TEST 20: re_tests:808 +--- re: abb$ +--- s eval: "abb\nb\n" + + + +=== TEST 21: re_tests:810 +--- re: abb\z +--- s eval: "b\nabb\n" + + + +=== TEST 22: re_tests:811 +--- re: abb$ +--- s eval: "b\nabb\n" + + + +=== TEST 23: re_tests:813 +--- re: abb\z +--- s eval: "b\nabb" + + + +=== TEST 24: re_tests:814 +--- re: abb$ +--- s eval: "b\nabb" + + + +=== TEST 25: re_tests:816 +--- re: abb\z +--- s eval: "ac\nb\n" + + + +=== TEST 26: re_tests:817 +--- re: abb$ +--- s eval: "ac\nb\n" + + + +=== TEST 27: re_tests:819 +--- re: abb\z +--- s eval: "b\nac\n" + + + +=== TEST 28: re_tests:820 +--- re: abb$ +--- s eval: "b\nac\n" + + + +=== TEST 29: re_tests:822 +--- re: abb\z +--- s eval: "b\nac" + + + +=== TEST 30: re_tests:823 +--- re: abb$ +--- s eval: "b\nac" + + + +=== TEST 31: re_tests:825 +--- re: abb\z +--- s eval: "ac\nb\n" + + + +=== TEST 32: re_tests:826 +--- re: abb$ +--- s eval: "ac\nb\n" + + + +=== TEST 33: re_tests:828 +--- re: abb\z +--- s eval: "b\nac\n" + + + +=== TEST 34: re_tests:829 +--- re: abb$ +--- s eval: "b\nac\n" + + + +=== TEST 35: re_tests:831 +--- re: abb\z +--- s eval: "b\nac" + + + +=== TEST 36: re_tests:832 +--- re: abb$ +--- s eval: "b\nac" + + + +=== TEST 37: re_tests:834 +--- re: abb\z +--- s eval: "ca\nb\n" + + + +=== TEST 38: re_tests:835 +--- re: abb$ +--- s eval: "ca\nb\n" + + + +=== TEST 39: re_tests:837 +--- re: abb\z +--- s eval: "b\nca\n" + + + +=== TEST 40: re_tests:838 +--- re: abb$ +--- s eval: "b\nca\n" + + + +=== TEST 41: re_tests:840 +--- re: abb\z +--- s eval: "b\nca" + + + +=== TEST 42: re_tests:841 +--- re: abb$ +--- s eval: "b\nca" + + + +=== TEST 43: re_tests:843 +--- re: abb\z +--- s eval: "ca\nb\n" + + + +=== TEST 44: re_tests:844 +--- re: abb$ +--- s eval: "ca\nb\n" + + + +=== TEST 45: re_tests:846 +--- re: abb\z +--- s eval: "b\nca\n" + + + +=== TEST 46: re_tests:847 +--- re: abb$ +--- s eval: "b\nca\n" + + + +=== TEST 47: re_tests:849 +--- re: abb\z +--- s eval: "b\nca" + + + +=== TEST 48: re_tests:850 +--- re: abb$ +--- s eval: "b\nca" + + + +=== TEST 49: re_tests:851 +--- re: (^|x)(c) +--- s eval: "ca" + + + +=== TEST 50: re_tests:852 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "x" + + + diff --git a/lib/sregex/t/02-p5-re_tests-11.t b/lib/sregex/t/02-p5-re_tests-11.t new file mode 100644 index 0000000..9171598 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-11.t @@ -0,0 +1,312 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:857 +--- re: foo.bart +--- s eval: "foo.bart" + + + +=== TEST 2: re_tests:858 +--- re: ^d[x][x][x] +--- s eval: "abcd\ndxxx" + + + +=== TEST 3: re_tests:859 +--- re: .X(.+)+X +--- s eval: "bbbbXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 4: re_tests:860 +--- re: .X(.+)+XX +--- s eval: "bbbbXcXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 5: re_tests:861 +--- re: .XX(.+)+X +--- s eval: "bbbbXXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 6: re_tests:862 +--- re: .X(.+)+X +--- s eval: "bbbbXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 7: re_tests:863 +--- re: .X(.+)+XX +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 8: re_tests:864 +--- re: .XX(.+)+X +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 9: re_tests:865 +--- re: .X(.+)+[X] +--- s eval: "bbbbXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 10: re_tests:866 +--- re: .X(.+)+[X][X] +--- s eval: "bbbbXcXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 11: re_tests:867 +--- re: .XX(.+)+[X] +--- s eval: "bbbbXXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 12: re_tests:868 +--- re: .X(.+)+[X] +--- s eval: "bbbbXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 13: re_tests:869 +--- re: .X(.+)+[X][X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 14: re_tests:870 +--- re: .XX(.+)+[X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 15: re_tests:871 +--- re: .[X](.+)+[X] +--- s eval: "bbbbXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 16: re_tests:872 +--- re: .[X](.+)+[X][X] +--- s eval: "bbbbXcXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 17: re_tests:873 +--- re: .[X][X](.+)+[X] +--- s eval: "bbbbXXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 18: re_tests:874 +--- re: .[X](.+)+[X] +--- s eval: "bbbbXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 19: re_tests:875 +--- re: .[X](.+)+[X][X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 20: re_tests:876 +--- re: .[X][X](.+)+[X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 21: re_tests:877 +--- re: tt+$ +--- s eval: "xxxtt" + + + +=== TEST 22: re_tests:878 +--- re: ([a-\d]+) +--- s eval: "za-9z" + + + +=== TEST 23: re_tests:879 +--- re: ([\d-z]+) +--- s eval: "a0-za" + + + +=== TEST 24: re_tests:880 +--- re: ([\d-\s]+) +--- s eval: "a0- z" + + + +=== TEST 25: re_tests:885 +--- re: (\d+\.\d+) +--- s eval: "3.1415926" + + + +=== TEST 26: re_tests:886 +--- re: (\ba.{0,10}br) +--- s eval: "have a web browser" + + + +=== TEST 27: re_tests:887 +--- re: \.c(pp|xx|c)?$ +--- s eval: "Changes" +--- flags: i + + + +=== TEST 28: re_tests:888 +--- re: \.c(pp|xx|c)?$ +--- s eval: "IO.c" +--- flags: i + + + +=== TEST 29: re_tests:889 +--- re: (\.c(pp|xx|c)?$) +--- s eval: "IO.c" +--- flags: i + + + +=== TEST 30: re_tests:890 +--- re: ^([a-z]:) +--- s eval: "C:/" + + + +=== TEST 31: re_tests:891 +--- re: ^\S\s+aa$ +--- s eval: "\nx aa" + + + +=== TEST 32: re_tests:892 +--- re: (^|a)b +--- s eval: "ab" + + + +=== TEST 33: re_tests:893 +--- re: ^([ab]*?)(b)?(c)$ +--- s eval: "abac" + + + +=== TEST 34: re_tests:895 +--- re: ^(?:.,){2}c +--- s eval: "a,b,c" + + + +=== TEST 35: re_tests:896 +--- re: ^(.,){2}c +--- s eval: "a,b,c" + + + +=== TEST 36: re_tests:897 +--- re: ^(?:[^,]*,){2}c +--- s eval: "a,b,c" + + + +=== TEST 37: re_tests:898 +--- re: ^([^,]*,){2}c +--- s eval: "a,b,c" + + + +=== TEST 38: re_tests:899 +--- re: ^([^,]*,){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 39: re_tests:900 +--- re: ^([^,]*,){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 40: re_tests:901 +--- re: ^([^,]*,){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 41: re_tests:902 +--- re: ^([^,]{1,3},){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 42: re_tests:903 +--- re: ^([^,]{1,3},){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 43: re_tests:904 +--- re: ^([^,]{1,3},){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 44: re_tests:905 +--- re: ^([^,]{1,},){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 45: re_tests:906 +--- re: ^([^,]{1,},){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 46: re_tests:907 +--- re: ^([^,]{1,},){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 47: re_tests:908 +--- re: ^([^,]{0,3},){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 48: re_tests:909 +--- re: ^([^,]{0,3},){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 49: re_tests:910 +--- re: ^([^,]{0,3},){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 50: re_tests:914 +--- re: ^(a(b)?)+$ +--- s eval: "aba" +--- cap: (0, 3) (2, 3) (1, 2) + + + diff --git a/lib/sregex/t/02-p5-re_tests-12.t b/lib/sregex/t/02-p5-re_tests-12.t new file mode 100644 index 0000000..244b6ce --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-12.t @@ -0,0 +1,312 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:915 +--- re: ^(aa(bb)?)+$ +--- s eval: "aabbaa" +--- cap: (0, 6) (4, 6) (2, 4) + + + +=== TEST 2: re_tests:916 +--- re: ^.{9}abc.*\n +--- s eval: "123\nabcabcabcabc\n" + + + +=== TEST 3: re_tests:917 +--- re: ^(a)?a$ +--- s eval: "a" + + + +=== TEST 4: re_tests:921 +--- re: ^(0+)?(?:x(1))? +--- s eval: "x1" + + + +=== TEST 5: re_tests:922 +--- re: ^([0-9a-fA-F]+)(?:x([0-9a-fA-F]+)?)(?:x([0-9a-fA-F]+))? +--- s eval: "012cxx0190" + + + +=== TEST 6: re_tests:923 +--- re: ^(b+?|a){1,2}c +--- s eval: "bbbac" + + + +=== TEST 7: re_tests:924 +--- re: ^(b+?|a){1,2}c +--- s eval: "bbbbac" + + + +=== TEST 8: re_tests:925 +--- re: \((\w\. \w+)\) +--- s eval: "cd. (A. Tw)" + + + +=== TEST 9: re_tests:926 +--- re: ((?:aaaa|bbbb)cccc)? +--- s eval: "aaaacccc" + + + +=== TEST 10: re_tests:927 +--- re: ((?:aaaa|bbbb)cccc)? +--- s eval: "bbbbcccc" + + + +=== TEST 11: re_tests:928 +--- re: (a)?(a)+ +--- s eval: "a" + + + +=== TEST 12: re_tests:929 +--- re: (ab)?(ab)+ +--- s eval: "ab" + + + +=== TEST 13: re_tests:930 +--- re: (abc)?(abc)+ +--- s eval: "abc" + + + +=== TEST 14: re_tests:931 +--- re: b\s^ +--- s eval: "a\nb\n" +--- cap: (2, 4) + + + +=== TEST 15: re_tests:932 +--- re: \ba +--- s eval: "a" + + + +=== TEST 16: re_tests:943 +--- re: (.*)c +--- s eval: "abcd" + + + +=== TEST 17: re_tests:960 +--- re: (.*?)c +--- s eval: "abcd" + + + +=== TEST 18: re_tests:979 +--- re: a(b)?? +--- s eval: "abc" + + + +=== TEST 19: re_tests:980 +--- re: (\d{1,3}\.){3,} +--- s eval: "128.134.142.8" + + + +=== TEST 20: re_tests:998 +--- re: x(?# +--- s eval: "x" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 21: re_tests:999 +--- re: x(?# +--- s eval: "x" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 22: re_tests:1000 +--- re: (WORDS|WORD)S +--- s eval: "WORDS" + + + +=== TEST 23: re_tests:1001 +--- re: (X.|WORDS|X.|WORD)S +--- s eval: "WORDS" + + + +=== TEST 24: re_tests:1002 +--- re: (WORDS|WORLD|WORD)S +--- s eval: "WORDS" + + + +=== TEST 25: re_tests:1003 +--- re: (X.|WORDS|WORD|Y.)S +--- s eval: "WORDS" + + + +=== TEST 26: re_tests:1004 +--- re: (foo|fool|x.|money|parted)$ +--- s eval: "fool" + + + +=== TEST 27: re_tests:1005 +--- re: (x.|foo|fool|x.|money|parted|y.)$ +--- s eval: "fool" + + + +=== TEST 28: re_tests:1006 +--- re: (foo|fool|money|parted)$ +--- s eval: "fool" + + + +=== TEST 29: re_tests:1007 +--- re: (foo|fool|x.|money|parted)$ +--- s eval: "fools" + + + +=== TEST 30: re_tests:1008 +--- re: (x.|foo|fool|x.|money|parted|y.)$ +--- s eval: "fools" + + + +=== TEST 31: re_tests:1009 +--- re: (foo|fool|money|parted)$ +--- s eval: "fools" + + + +=== TEST 32: re_tests:1010 +--- re: (a|aa|aaa||aaaa|aaaaa|aaaaaa)(b|c) +--- s eval: "aaaaaaaaaaaaaaab" + + + +=== TEST 33: re_tests:1016 +--- re: (?:r?)*?r|(.{2,4}) +--- s eval: "abcde" + + + +=== TEST 34: re_tests:1020 +--- re: ^((?:aa)*)(?:X+((?:\d+|-)(?:X+(.+))?))?$ +--- s eval: "aaaaX5" + + + +=== TEST 35: re_tests:1021 +--- re: X(A|B||C|D)Y +--- s eval: "XXXYYY" + + + +=== TEST 36: re_tests:1023 +--- re: ^([a]{1})*$ +--- s eval: "aa" + + + +=== TEST 37: re_tests:1028 +--- re: ^(XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 38: re_tests:1029 +--- re: ^(XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 39: re_tests:1030 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 40: re_tests:1031 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 41: re_tests:1032 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 42: re_tests:1033 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQX:" + + + +=== TEST 43: re_tests:1034 +--- re: ^(XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 44: re_tests:1035 +--- re: ^(XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 45: re_tests:1036 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 46: re_tests:1037 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 47: re_tests:1038 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 48: re_tests:1039 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQX:" + + + +=== TEST 49: re_tests:1040 +--- re: X(?:ABCF[cC]x*|ABCD|ABCF):(?:DIT|DID|DIM) +--- s eval: "XABCFCxxxxxxxxxx:DIM" + + + +=== TEST 50: re_tests:1041 +--- re: (((ABCD|ABCE|ABCF)))(A|B|C[xy]*): +--- s eval: "ABCFCxxxxxxxxxx:DIM" + + + diff --git a/lib/sregex/t/02-p5-re_tests-13.t b/lib/sregex/t/02-p5-re_tests-13.t new file mode 100644 index 0000000..b4df0af --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-13.t @@ -0,0 +1,329 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:1084 +--- re: (?P<=n>foo|bar|baz) +--- s eval: "snofooewa" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 2: re_tests:1085 +--- re: (?Pfoo|bar|baz) +--- s eval: "snofooewa" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 3: re_tests:1086 +--- re: (?PXfoo|bar|baz) +--- s eval: "snofooewa" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 4: re_tests:1208 +--- re: (foo[1x]|bar[2x]|baz[3x])+y +--- s eval: "foo1bar2baz3y" + + + +=== TEST 5: re_tests:1210 +--- re: (foo[1x]|bar[2x]|baz[3x])*y +--- s eval: "foo1bar2baz3y" + + + +=== TEST 6: re_tests:1213 +--- re: ([yX].|WORDS|[yX].|WORD)S +--- s eval: "WORDS" + + + +=== TEST 7: re_tests:1215 +--- re: ([yX].|WORDS|WORD|[xY].)S +--- s eval: "WORDS" + + + +=== TEST 8: re_tests:1216 +--- re: (foo|fool|[zx].|money|parted)$ +--- s eval: "fool" + + + +=== TEST 9: re_tests:1217 +--- re: ([zx].|foo|fool|[zq].|money|parted|[yx].)$ +--- s eval: "fool" + + + +=== TEST 10: re_tests:1218 +--- re: (foo|fool|[zx].|money|parted)$ +--- s eval: "fools" + + + +=== TEST 11: re_tests:1219 +--- re: ([zx].|foo|fool|[qx].|money|parted|[py].)$ +--- s eval: "fools" + + + +=== TEST 12: re_tests:1221 +--- re: ([yX].|WORDS|[yX].|WORD)+S +--- s eval: "WORDS" + + + +=== TEST 13: re_tests:1222 +--- re: (WORDS|WORLD|WORD)+S +--- s eval: "WORDS" + + + +=== TEST 14: re_tests:1223 +--- re: ([yX].|WORDS|WORD|[xY].)+S +--- s eval: "WORDS" + + + +=== TEST 15: re_tests:1224 +--- re: (foo|fool|[zx].|money|parted)+$ +--- s eval: "fool" + + + +=== TEST 16: re_tests:1225 +--- re: ([zx].|foo|fool|[zq].|money|parted|[yx].)+$ +--- s eval: "fool" + + + +=== TEST 17: re_tests:1226 +--- re: (foo|fool|[zx].|money|parted)+$ +--- s eval: "fools" + + + +=== TEST 18: re_tests:1227 +--- re: ([zx].|foo|fool|[qx].|money|parted|[py].)+$ +--- s eval: "fools" + + + +=== TEST 19: re_tests:1229 +--- re: (x|y|z[QW])+(longish|loquatious|excessive|overblown[QW])+ +--- s eval: "xyzQzWlongishoverblownW" + + + +=== TEST 20: re_tests:1230 +--- re: (x|y|z[QW])*(longish|loquatious|excessive|overblown[QW])* +--- s eval: "xyzQzWlongishoverblownW" + + + +=== TEST 21: re_tests:1231 +--- re: (x|y|z[QW]){1,5}(longish|loquatious|excessive|overblown[QW]){1,5} +--- s eval: "xyzQzWlongishoverblownW" + + + +=== TEST 22: re_tests:1270 +--- re: (?''foo) bar +--- s eval: "..foo bar.." +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 23: re_tests:1271 +--- re: (?<>foo) bar +--- s eval: "..foo bar.." +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 24: re_tests:1272 +--- re: foo \k'n' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 25: re_tests:1273 +--- re: foo \k +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 26: re_tests:1274 +--- re: foo \k'a1' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 27: re_tests:1275 +--- re: foo \k +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 28: re_tests:1276 +--- re: foo \k'_' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 29: re_tests:1277 +--- re: foo \k<_> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 30: re_tests:1278 +--- re: foo \k'_0_' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 31: re_tests:1279 +--- re: foo \k<_0_> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 32: re_tests:1280 +--- re: foo \k'0' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 33: re_tests:1281 +--- re: foo \k<0> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 34: re_tests:1282 +--- re: foo \k'12' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 35: re_tests:1283 +--- re: foo \k<12> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 36: re_tests:1284 +--- re: foo \k'1a' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 37: re_tests:1285 +--- re: foo \k<1a> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 38: re_tests:1286 +--- re: foo \k'' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 39: re_tests:1287 +--- re: foo \k<> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 40: re_tests:1364 +--- re: foo(\v+)bar +--- s eval: "foo\r\n\x{85}\r\n\nbar" + + + +=== TEST 41: re_tests:1365 +--- re: (\V+)(\v) +--- s eval: "foo\r\n\x{85}\r\n\nbar" + + + +=== TEST 42: re_tests:1366 +--- re: (\v+)(\V) +--- s eval: "foo\r\n\x{85}\r\n\nbar" + + + +=== TEST 43: re_tests:1367 +--- re: foo(\v)bar +--- s eval: "foo\x{85}bar" + + + +=== TEST 44: re_tests:1368 +--- re: (\V)(\v) +--- s eval: "foo\x{85}bar" + + + +=== TEST 45: re_tests:1369 +--- re: (\v)(\V) +--- s eval: "foo\x{85}bar" + + + +=== TEST 46: re_tests:1370 +--- re: foo(\v)bar +--- s eval: "foo\rbar" + + + +=== TEST 47: re_tests:1371 +--- re: (\V)(\v) +--- s eval: "foo\rbar" + + + +=== TEST 48: re_tests:1372 +--- re: (\v)(\V) +--- s eval: "foo\rbar" + + + +=== TEST 49: re_tests:1375 +--- re: foo(\h+)bar +--- s eval: "foo\t\x{A0}bar" + + + +=== TEST 50: re_tests:1376 +--- re: (\H+)(\h) +--- s eval: "foo\t\x{A0}bar" + + + diff --git a/lib/sregex/t/02-p5-re_tests-14.t b/lib/sregex/t/02-p5-re_tests-14.t new file mode 100644 index 0000000..e418736 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-14.t @@ -0,0 +1,320 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:1377 +--- re: (\h+)(\H) +--- s eval: "foo\t\x{A0}bar" + + + +=== TEST 2: re_tests:1378 +--- re: foo(\h)bar +--- s eval: "foo\x{A0}bar" + + + +=== TEST 3: re_tests:1379 +--- re: (\H)(\h) +--- s eval: "foo\x{A0}bar" + + + +=== TEST 4: re_tests:1380 +--- re: (\h)(\H) +--- s eval: "foo\x{A0}bar" + + + +=== TEST 5: re_tests:1381 +--- re: foo(\h)bar +--- s eval: "foo\tbar" + + + +=== TEST 6: re_tests:1382 +--- re: (\H)(\h) +--- s eval: "foo\tbar" + + + +=== TEST 7: re_tests:1383 +--- re: (\h)(\H) +--- s eval: "foo\tbar" + + + +=== TEST 8: re_tests:1385 +--- re: .*\z +--- s eval: "foo\n" + + + +=== TEST 9: re_tests:1386 +--- re: \N*\z +--- s eval: "foo\n" + + + +=== TEST 10: re_tests:1389 +--- re: ^(?:(\d)x)?\d$ +--- s eval: "1" + + + +=== TEST 11: re_tests:1390 +--- re: .*?(?:(\w)|(\w))x +--- s eval: "abx" + + + +=== TEST 12: re_tests:1392 +--- re: 0{50} +--- s eval: "000000000000000000000000000000000000000000000000000" + + + +=== TEST 13: re_tests:1395 +--- re: >\d+$ \n +--- s eval: ">10\n" +--- flags: i + + + +=== TEST 14: re_tests:1396 +--- re: >\d+$ \n +--- s eval: ">1\n" +--- flags: i + + + +=== TEST 15: re_tests:1397 +--- re: \d+$ \n +--- s eval: ">10\n" +--- flags: i + + + +=== TEST 16: re_tests:1398 +--- re: >\d\d$ \n +--- s eval: ">10\n" +--- flags: i + + + +=== TEST 17: re_tests:1399 +--- re: >\d+$ \n +--- s eval: ">10\n" + + + +=== TEST 18: re_tests:1403 +--- re: ^\s*i.*?o\s*$ +--- s eval: "io\n io" + + + +=== TEST 19: re_tests:1416 +--- re: [\s][\S] +--- s eval: "\x{a0}\x{a0}" + + + +=== TEST 20: re_tests:1424 +--- re: abc\N\{U+BEEF} +--- s eval: "abc\n{UBEEF}" + + + +=== TEST 21: re_tests:1425 +--- re: abc\N\{U+BEEF} +--- s eval: "abc.{UBEEF}" + + + +=== TEST 22: re_tests:1426 +--- re: [abc\N\{U+BEEF}] +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 23: re_tests:1429 +--- re: abc\N +--- s eval: "abcd" + + + +=== TEST 24: re_tests:1430 +--- re: abc\N +--- s eval: "abc\n" + + + +=== TEST 25: re_tests:1437 +--- re: abc\N{def +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ +--- SKIP + + + +=== TEST 26: re_tests:1447 +--- re: abc\N{def +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ +--- SKIP + + + +=== TEST 27: re_tests:1450 +--- re: abc\N {U+41} +--- s eval: "-" + + + +=== TEST 28: re_tests:1451 +--- re: abc\N {SPACE} +--- s eval: "-" + + + +=== TEST 29: re_tests:1460 +--- re: \c` +--- s eval: "-" + + + +=== TEST 30: re_tests:1461 +--- re: \c1 +--- s eval: "-" + + + +=== TEST 31: re_tests:1462 +--- re: \cA +--- s eval: "\001" + + + +=== TEST 32: re_tests:1470 +--- re: \o{120} +--- s eval: "\x{50}" + + + +=== TEST 33: re_tests:1473 +--- re: [a\o{120}] +--- s eval: "\x{50}" + + + +=== TEST 34: re_tests:1483 +--- re: [\0] +--- s eval: "\000" + + + +=== TEST 35: re_tests:1484 +--- re: [\07] +--- s eval: "\007" + + + +=== TEST 36: re_tests:1485 +--- re: [\07] +--- s eval: "7\000" + + + +=== TEST 37: re_tests:1486 +--- re: [\006] +--- s eval: "\006" + + + +=== TEST 38: re_tests:1487 +--- re: [\006] +--- s eval: "6\000" + + + +=== TEST 39: re_tests:1488 +--- re: [\0005] +--- s eval: "\0005" + + + +=== TEST 40: re_tests:1489 +--- re: [\0005] +--- s eval: "5\000" + + + +=== TEST 41: re_tests:1490 +--- re: [\_] +--- s eval: "_" + + + +=== TEST 42: re_tests:1493 +--- re: (q1|.)*(q2|.)*(x(a|bc)*y){2,} +--- s eval: "xayxay" + + + +=== TEST 43: re_tests:1494 +--- re: (q1|.)*(q2|.)*(x(a|bc)*y){2,3} +--- s eval: "xayxay" + + + +=== TEST 44: re_tests:1495 +--- re: (q1|z)*(q2|z)*z{15}-.*?(x(a|bc)*y){2,3}Z +--- s eval: "zzzzzzzzzzzzzzzz-xayxayxayxayZ" + + + +=== TEST 45: re_tests:1497 +--- re: (?:(?:)foo|bar|zot|rt78356) +--- s eval: "foo" + + + +=== TEST 46: re_tests:1518 +--- re: s +--- s eval: "\x{17F}" +--- flags: i + + + +=== TEST 47: re_tests:1519 +--- re: s +--- s eval: "\x{17F}" +--- flags: i + + + +=== TEST 48: re_tests:1520 +--- re: s +--- s eval: "S" +--- flags: i + + + +=== TEST 49: re_tests:1530 +--- re: ^.*\d\H +--- s eval: "X1" + + + +=== TEST 50: re_tests:1531 +--- re: ^.*\d\V +--- s eval: "X1" + + + diff --git a/lib/sregex/t/02-p5-re_tests-15.t b/lib/sregex/t/02-p5-re_tests-15.t new file mode 100644 index 0000000..13bc606 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests-15.t @@ -0,0 +1,114 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:1539 +--- re: [s\xDF] +--- s eval: "\xDFs" +--- flags: i + + + +=== TEST 2: re_tests:1544 +--- re: ff +--- s eval: "\x{FB00}\x{FB01}" +--- flags: i + + + +=== TEST 3: re_tests:1545 +--- re: ff +--- s eval: "\x{FB01}\x{FB00}" +--- flags: i + + + +=== TEST 4: re_tests:1546 +--- re: fi +--- s eval: "\x{FB01}\x{FB00}" +--- flags: i + + + +=== TEST 5: re_tests:1547 +--- re: fi +--- s eval: "\x{FB00}\x{FB01}" +--- flags: i + + + +=== TEST 6: re_tests:1551 +--- re: ffiffl +--- s eval: "abcdef\x{FB03}\x{FB04}" +--- flags: i + + + +=== TEST 7: re_tests:1552 +--- re: \xdf\xdf +--- s eval: "abcdefssss" +--- flags: i + + + +=== TEST 8: re_tests:1554 +--- re: st +--- s eval: "\x{DF}\x{FB05}" +--- flags: i + + + +=== TEST 9: re_tests:1555 +--- re: ssst +--- s eval: "\x{DF}\x{FB05}" +--- flags: i + + + +=== TEST 10: re_tests:1563 +--- re: s\xDF +--- s eval: "\xDFs" +--- flags: i + + + +=== TEST 11: re_tests:1564 +--- re: sst +--- s eval: "s\N{LATIN SMALL LIGATURE ST}" +--- flags: i + + + +=== TEST 12: re_tests:1565 +--- re: sst +--- s eval: "s\N{LATIN SMALL LIGATURE LONG S T}" +--- flags: i + + + +=== TEST 13: re_tests:1599 +--- re: [\h] +--- s eval: "\x{A0}" + + + +=== TEST 14: re_tests:1600 +--- re: [\H] +--- s eval: "\x{BF}" + + + +=== TEST 15: re_tests:1601 +--- re: [\H] +--- s eval: "\x{A0}" + + + +=== TEST 16: re_tests:1602 +--- re: [\H] +--- s eval: "\x{A1}" + diff --git a/lib/sregex/t/02-p5-re_tests.t_ b/lib/sregex/t/02-p5-re_tests.t_ new file mode 100644 index 0000000..d80ea85 --- /dev/null +++ b/lib/sregex/t/02-p5-re_tests.t_ @@ -0,0 +1,4517 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: re_tests:9 +--- re: abc +--- s eval: "abc" + + + +=== TEST 2: re_tests:12 +--- re: abc +--- s eval: "xbc" + + + +=== TEST 3: re_tests:13 +--- re: abc +--- s eval: "axc" + + + +=== TEST 4: re_tests:14 +--- re: abc +--- s eval: "abx" + + + +=== TEST 5: re_tests:15 +--- re: abc +--- s eval: "xabcy" + + + +=== TEST 6: re_tests:18 +--- re: abc +--- s eval: "ababc" + + + +=== TEST 7: re_tests:21 +--- re: ab*c +--- s eval: "abc" + + + +=== TEST 8: re_tests:24 +--- re: ab*bc +--- s eval: "abc" + + + +=== TEST 9: re_tests:27 +--- re: ab*bc +--- s eval: "abbc" + + + +=== TEST 10: re_tests:30 +--- re: ab*bc +--- s eval: "abbbbc" + + + +=== TEST 11: re_tests:33 +--- re: .{1} +--- s eval: "abbbbc" + + + +=== TEST 12: re_tests:36 +--- re: .{3,4} +--- s eval: "abbbbc" + + + +=== TEST 13: re_tests:42 +--- re: \N {1} +--- s eval: "abbbbc" + + + +=== TEST 14: re_tests:48 +--- re: \N {3,4} +--- s eval: "abbbbc" + + + +=== TEST 15: re_tests:51 +--- re: ab{0,}bc +--- s eval: "abbbbc" + + + +=== TEST 16: re_tests:54 +--- re: ab+bc +--- s eval: "abbc" + + + +=== TEST 17: re_tests:57 +--- re: ab+bc +--- s eval: "abc" + + + +=== TEST 18: re_tests:58 +--- re: ab+bc +--- s eval: "abq" + + + +=== TEST 19: re_tests:59 +--- re: ab{1,}bc +--- s eval: "abq" + + + +=== TEST 20: re_tests:60 +--- re: ab+bc +--- s eval: "abbbbc" + + + +=== TEST 21: re_tests:63 +--- re: ab{1,}bc +--- s eval: "abbbbc" + + + +=== TEST 22: re_tests:66 +--- re: ab{1,3}bc +--- s eval: "abbbbc" + + + +=== TEST 23: re_tests:69 +--- re: ab{3,4}bc +--- s eval: "abbbbc" + + + +=== TEST 24: re_tests:72 +--- re: ab{4,5}bc +--- s eval: "abbbbc" + + + +=== TEST 25: re_tests:73 +--- re: ab?bc +--- s eval: "abbc" + + + +=== TEST 26: re_tests:74 +--- re: ab?bc +--- s eval: "abc" + + + +=== TEST 27: re_tests:75 +--- re: ab{0,1}bc +--- s eval: "abc" + + + +=== TEST 28: re_tests:76 +--- re: ab?bc +--- s eval: "abbbbc" + + + +=== TEST 29: re_tests:77 +--- re: ab?c +--- s eval: "abc" + + + +=== TEST 30: re_tests:78 +--- re: ab{0,1}c +--- s eval: "abc" + + + +=== TEST 31: re_tests:79 +--- re: ^abc$ +--- s eval: "abc" + + + +=== TEST 32: re_tests:80 +--- re: ^abc$ +--- s eval: "abcc" + + + +=== TEST 33: re_tests:81 +--- re: ^abc +--- s eval: "abcc" + + + +=== TEST 34: re_tests:82 +--- re: ^abc$ +--- s eval: "aabc" + + + +=== TEST 35: re_tests:83 +--- re: abc$ +--- s eval: "aabc" + + + +=== TEST 36: re_tests:84 +--- re: abc$ +--- s eval: "aabcd" + + + +=== TEST 37: re_tests:85 +--- re: ^ +--- s eval: "abc" + + + +=== TEST 38: re_tests:86 +--- re: $ +--- s eval: "abc" + + + +=== TEST 39: re_tests:87 +--- re: a.c +--- s eval: "abc" + + + +=== TEST 40: re_tests:88 +--- re: a.c +--- s eval: "axc" + + + +=== TEST 41: re_tests:89 +--- re: a\Nc +--- s eval: "abc" + + + +=== TEST 42: re_tests:90 +--- re: a\N c +--- s eval: "abc" + + + +=== TEST 43: re_tests:91 +--- re: a.*c +--- s eval: "axyzc" + + + +=== TEST 44: re_tests:92 +--- re: a\N*c +--- s eval: "axyzc" + + + +=== TEST 45: re_tests:93 +--- re: a\N *c +--- s eval: "axyzc" + + + +=== TEST 46: re_tests:94 +--- re: a.*c +--- s eval: "axyzd" + + + +=== TEST 47: re_tests:95 +--- re: a\N*c +--- s eval: "axyzd" + + + +=== TEST 48: re_tests:96 +--- re: a\N *c +--- s eval: "axyzd" + + + +=== TEST 49: re_tests:97 +--- re: a[bc]d +--- s eval: "abc" + + + +=== TEST 50: re_tests:98 +--- re: a[bc]d +--- s eval: "abd" + + + +=== TEST 51: re_tests:99 +--- re: a[b]d +--- s eval: "abd" + + + +=== TEST 52: re_tests:100 +--- re: [a][b][d] +--- s eval: "abd" + + + +=== TEST 53: re_tests:101 +--- re: .[b]. +--- s eval: "abd" + + + +=== TEST 54: re_tests:102 +--- re: .[b]. +--- s eval: "aBd" + + + +=== TEST 55: re_tests:105 +--- re: a[b-d]e +--- s eval: "abd" + + + +=== TEST 56: re_tests:106 +--- re: a[b-d]e +--- s eval: "ace" + + + +=== TEST 57: re_tests:107 +--- re: a[b-d] +--- s eval: "aac" + + + +=== TEST 58: re_tests:108 +--- re: a[-b] +--- s eval: "a-" + + + +=== TEST 59: re_tests:109 +--- re: a[b-] +--- s eval: "a-" + + + +=== TEST 60: re_tests:110 +--- re: a[b-a] +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 61: re_tests:111 +--- re: a[]b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 62: re_tests:112 +--- re: a[ +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 63: re_tests:113 +--- re: a] +--- s eval: "a]" + + + +=== TEST 64: re_tests:114 +--- re: a[]]b +--- s eval: "a]b" + + + +=== TEST 65: re_tests:115 +--- re: a[^bc]d +--- s eval: "aed" + + + +=== TEST 66: re_tests:116 +--- re: a[^bc]d +--- s eval: "abd" + + + +=== TEST 67: re_tests:117 +--- re: a[^-b]c +--- s eval: "adc" + + + +=== TEST 68: re_tests:118 +--- re: a[^-b]c +--- s eval: "a-c" + + + +=== TEST 69: re_tests:119 +--- re: a[^]b]c +--- s eval: "a]c" + + + +=== TEST 70: re_tests:120 +--- re: a[^]b]c +--- s eval: "adc" + + + +=== TEST 71: re_tests:121 +--- re: \ba\b +--- s eval: "a-" + + + +=== TEST 72: re_tests:122 +--- re: \ba\b +--- s eval: "-a" + + + +=== TEST 73: re_tests:123 +--- re: \ba\b +--- s eval: "-a-" + + + +=== TEST 74: re_tests:124 +--- re: \by\b +--- s eval: "xy" + + + +=== TEST 75: re_tests:125 +--- re: \by\b +--- s eval: "yz" + + + +=== TEST 76: re_tests:126 +--- re: \by\b +--- s eval: "xyz" + + + +=== TEST 77: re_tests:127 +--- re: \Ba\B +--- s eval: "a-" + + + +=== TEST 78: re_tests:128 +--- re: \Ba\B +--- s eval: "-a" + + + +=== TEST 79: re_tests:129 +--- re: \Ba\B +--- s eval: "-a-" + + + +=== TEST 80: re_tests:130 +--- re: \By\b +--- s eval: "xy" + + + +=== TEST 81: re_tests:134 +--- re: \by\B +--- s eval: "yz" + + + +=== TEST 82: re_tests:135 +--- re: \By\B +--- s eval: "xyz" + + + +=== TEST 83: re_tests:136 +--- re: \w +--- s eval: "a" + + + +=== TEST 84: re_tests:137 +--- re: \w +--- s eval: "-" + + + +=== TEST 85: re_tests:138 +--- re: \W +--- s eval: "a" + + + +=== TEST 86: re_tests:139 +--- re: \W +--- s eval: "-" + + + +=== TEST 87: re_tests:140 +--- re: a\sb +--- s eval: "a b" + + + +=== TEST 88: re_tests:141 +--- re: a\sb +--- s eval: "a-b" + + + +=== TEST 89: re_tests:142 +--- re: a\Sb +--- s eval: "a b" + + + +=== TEST 90: re_tests:143 +--- re: a\Sb +--- s eval: "a-b" + + + +=== TEST 91: re_tests:144 +--- re: \d +--- s eval: "1" + + + +=== TEST 92: re_tests:145 +--- re: \d +--- s eval: "-" + + + +=== TEST 93: re_tests:146 +--- re: \D +--- s eval: "1" + + + +=== TEST 94: re_tests:147 +--- re: \D +--- s eval: "-" + + + +=== TEST 95: re_tests:148 +--- re: [\w] +--- s eval: "a" + + + +=== TEST 96: re_tests:149 +--- re: [\w] +--- s eval: "-" + + + +=== TEST 97: re_tests:150 +--- re: [\W] +--- s eval: "a" + + + +=== TEST 98: re_tests:151 +--- re: [\W] +--- s eval: "-" + + + +=== TEST 99: re_tests:152 +--- re: a[\s]b +--- s eval: "a b" + + + +=== TEST 100: re_tests:153 +--- re: a[\s]b +--- s eval: "a-b" + + + +=== TEST 101: re_tests:154 +--- re: a[\S]b +--- s eval: "a b" + + + +=== TEST 102: re_tests:155 +--- re: a[\S]b +--- s eval: "a-b" + + + +=== TEST 103: re_tests:156 +--- re: [\d] +--- s eval: "1" + + + +=== TEST 104: re_tests:157 +--- re: [\d] +--- s eval: "-" + + + +=== TEST 105: re_tests:158 +--- re: [\D] +--- s eval: "1" + + + +=== TEST 106: re_tests:159 +--- re: [\D] +--- s eval: "-" + + + +=== TEST 107: re_tests:160 +--- re: ab|cd +--- s eval: "abc" + + + +=== TEST 108: re_tests:161 +--- re: ab|cd +--- s eval: "abcd" + + + +=== TEST 109: re_tests:162 +--- re: ()ef +--- s eval: "def" + + + +=== TEST 110: re_tests:167 +--- re: *a +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 111: re_tests:168 +--- re: (|*)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 112: re_tests:169 +--- re: (*)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 113: re_tests:170 +--- re: $b +--- s eval: "b" + + + +=== TEST 114: re_tests:171 +--- re: a\ +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 115: re_tests:172 +--- re: a\(b +--- s eval: "a(b" + + + +=== TEST 116: re_tests:173 +--- re: a\(*b +--- s eval: "ab" + + + +=== TEST 117: re_tests:174 +--- re: a\(*b +--- s eval: "a((b" + + + +=== TEST 118: re_tests:175 +--- re: a\\b +--- s eval: "a\\b" + + + +=== TEST 119: re_tests:176 +--- re: abc) +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 120: re_tests:177 +--- re: (abc +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 121: re_tests:178 +--- re: ((a)) +--- s eval: "abc" + + + +=== TEST 122: re_tests:183 +--- re: (a)b(c) +--- s eval: "abc" + + + +=== TEST 123: re_tests:186 +--- re: a+b+c +--- s eval: "aabbabc" + + + +=== TEST 124: re_tests:187 +--- re: a{1,}b{1,}c +--- s eval: "aabbabc" + + + +=== TEST 125: re_tests:188 +--- re: a** +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 126: re_tests:189 +--- re: a.+?c +--- s eval: "abcabc" + + + +=== TEST 127: re_tests:190 +--- re: (a+|b)* +--- s eval: "ab" + + + +=== TEST 128: re_tests:195 +--- re: (a+|b){0,} +--- s eval: "ab" + + + +=== TEST 129: re_tests:196 +--- re: (a+|b)+ +--- s eval: "ab" + + + +=== TEST 130: re_tests:197 +--- re: (a+|b){1,} +--- s eval: "ab" + + + +=== TEST 131: re_tests:198 +--- re: (a+|b)? +--- s eval: "ab" + + + +=== TEST 132: re_tests:199 +--- re: (a+|b){0,1} +--- s eval: "ab" + + + +=== TEST 133: re_tests:200 +--- re: )( +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 134: re_tests:201 +--- re: [^ab]* +--- s eval: "cde" + + + +=== TEST 135: re_tests:202 +--- re: abc +--- s eval: "" + + + +=== TEST 136: re_tests:203 +--- re: a* +--- s eval: "" + + + +=== TEST 137: re_tests:204 +--- re: ([abc])*d +--- s eval: "abbbcd" + + + +=== TEST 138: re_tests:205 +--- re: ([abc])*bcd +--- s eval: "abcd" + + + +=== TEST 139: re_tests:206 +--- re: a|b|c|d|e +--- s eval: "e" + + + +=== TEST 140: re_tests:207 +--- re: (a|b|c|d|e)f +--- s eval: "ef" + + + +=== TEST 141: re_tests:212 +--- re: abcd*efg +--- s eval: "abcdefg" + + + +=== TEST 142: re_tests:213 +--- re: ab* +--- s eval: "xabyabbbz" + + + +=== TEST 143: re_tests:214 +--- re: ab* +--- s eval: "xayabbbz" + + + +=== TEST 144: re_tests:215 +--- re: (ab|cd)e +--- s eval: "abcde" + + + +=== TEST 145: re_tests:216 +--- re: [abhgefdc]ij +--- s eval: "hij" + + + +=== TEST 146: re_tests:217 +--- re: ^(ab|cd)e +--- s eval: "abcde" + + + +=== TEST 147: re_tests:218 +--- re: (abc|)ef +--- s eval: "abcdef" + + + +=== TEST 148: re_tests:219 +--- re: (a|b)c*d +--- s eval: "abcd" + + + +=== TEST 149: re_tests:220 +--- re: (ab|ab*)bc +--- s eval: "abc" + + + +=== TEST 150: re_tests:221 +--- re: a([bc]*)c* +--- s eval: "abc" + + + +=== TEST 151: re_tests:222 +--- re: a([bc]*)(c*d) +--- s eval: "abcd" + + + +=== TEST 152: re_tests:229 +--- re: a([bc]+)(c*d) +--- s eval: "abcd" + + + +=== TEST 153: re_tests:230 +--- re: a([bc]*)(c+d) +--- s eval: "abcd" + + + +=== TEST 154: re_tests:237 +--- re: a[bcd]*dcdcde +--- s eval: "adcdcde" + + + +=== TEST 155: re_tests:238 +--- re: a[bcd]+dcdcde +--- s eval: "adcdcde" + + + +=== TEST 156: re_tests:239 +--- re: (ab|a)b*c +--- s eval: "abc" + + + +=== TEST 157: re_tests:244 +--- re: ((a)(b)c)(d) +--- s eval: "abcd" + + + +=== TEST 158: re_tests:255 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "alpha" + + + +=== TEST 159: re_tests:256 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "abh" + + + +=== TEST 160: re_tests:257 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effgz" + + + +=== TEST 161: re_tests:258 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "ij" + + + +=== TEST 162: re_tests:259 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effg" + + + +=== TEST 163: re_tests:260 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "bcdd" + + + +=== TEST 164: re_tests:261 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "reffgz" + + + +=== TEST 165: re_tests:262 +--- re: ((((((((((a)))))))))) +--- s eval: "a" + + + +=== TEST 166: re_tests:268 +--- re: ((((((((((a))))))))))\041 +--- s eval: "aa" + + + +=== TEST 167: re_tests:269 +--- re: ((((((((((a))))))))))\041 +--- s eval: "a!" + + + +=== TEST 168: re_tests:270 +--- re: (((((((((a))))))))) +--- s eval: "a" + + + +=== TEST 169: re_tests:271 +--- re: multiple words of text +--- s eval: "uh-uh" + + + +=== TEST 170: re_tests:272 +--- re: multiple words +--- s eval: "multiple words, yeah" + + + +=== TEST 171: re_tests:273 +--- re: (.*)c(.*) +--- s eval: "abcde" + + + +=== TEST 172: re_tests:274 +--- re: \((.*), (.*)\) +--- s eval: "(a, b)" + + + +=== TEST 173: re_tests:275 +--- re: [k] +--- s eval: "ab" + + + +=== TEST 174: re_tests:276 +--- re: abcd +--- s eval: "abcd" + + + +=== TEST 175: re_tests:277 +--- re: a(bc)d +--- s eval: "abcd" + + + +=== TEST 176: re_tests:278 +--- re: a[-]?c +--- s eval: "ac" + + + +=== TEST 177: re_tests:285 +--- re: \g{1} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 178: re_tests:287 +--- re: \g0 +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 179: re_tests:289 +--- re: \g{0} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 180: re_tests:302 +--- re: (a)|(b) +--- s eval: "b" + + + +=== TEST 181: re_tests:308 +--- re: abc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 182: re_tests:309 +--- re: abc +--- s eval: "XBC" +--- flags: i + + + +=== TEST 183: re_tests:310 +--- re: abc +--- s eval: "AXC" +--- flags: i + + + +=== TEST 184: re_tests:311 +--- re: abc +--- s eval: "ABX" +--- flags: i + + + +=== TEST 185: re_tests:312 +--- re: abc +--- s eval: "XABCY" +--- flags: i + + + +=== TEST 186: re_tests:313 +--- re: abc +--- s eval: "ABABC" +--- flags: i + + + +=== TEST 187: re_tests:314 +--- re: ab*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 188: re_tests:315 +--- re: ab*bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 189: re_tests:316 +--- re: ab*bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 190: re_tests:317 +--- re: ab*?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 191: re_tests:318 +--- re: ab{0,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 192: re_tests:319 +--- re: ab+?bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 193: re_tests:320 +--- re: ab+bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 194: re_tests:321 +--- re: ab+bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 195: re_tests:322 +--- re: ab{1,}bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 196: re_tests:323 +--- re: ab+bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 197: re_tests:324 +--- re: ab{1,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 198: re_tests:325 +--- re: ab{1,3}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 199: re_tests:326 +--- re: ab{3,4}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 200: re_tests:327 +--- re: ab{4,5}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 201: re_tests:328 +--- re: ab??bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 202: re_tests:329 +--- re: ab??bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 203: re_tests:330 +--- re: ab{0,1}?bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 204: re_tests:331 +--- re: ab??bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 205: re_tests:332 +--- re: ab??c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 206: re_tests:333 +--- re: ab{0,1}?c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 207: re_tests:334 +--- re: ^abc$ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 208: re_tests:335 +--- re: ^abc$ +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 209: re_tests:336 +--- re: ^abc +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 210: re_tests:337 +--- re: ^abc$ +--- s eval: "AABC" +--- flags: i + + + +=== TEST 211: re_tests:338 +--- re: abc$ +--- s eval: "AABC" +--- flags: i + + + +=== TEST 212: re_tests:339 +--- re: ^ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 213: re_tests:340 +--- re: $ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 214: re_tests:341 +--- re: a.c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 215: re_tests:342 +--- re: a.c +--- s eval: "AXC" +--- flags: i + + + +=== TEST 216: re_tests:343 +--- re: a\Nc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 217: re_tests:344 +--- re: a.*?c +--- s eval: "AXYZC" +--- flags: i + + + +=== TEST 218: re_tests:345 +--- re: a.*c +--- s eval: "AXYZD" +--- flags: i + + + +=== TEST 219: re_tests:346 +--- re: a[bc]d +--- s eval: "ABC" +--- flags: i + + + +=== TEST 220: re_tests:347 +--- re: a[bc]d +--- s eval: "ABD" +--- flags: i + + + +=== TEST 221: re_tests:348 +--- re: a[b-d]e +--- s eval: "ABD" +--- flags: i + + + +=== TEST 222: re_tests:349 +--- re: a[b-d]e +--- s eval: "ACE" +--- flags: i + + + +=== TEST 223: re_tests:350 +--- re: a[b-d] +--- s eval: "AAC" +--- flags: i + + + +=== TEST 224: re_tests:351 +--- re: a[-b] +--- s eval: "A-" +--- flags: i + + + +=== TEST 225: re_tests:352 +--- re: a[b-] +--- s eval: "A-" +--- flags: i + + + +=== TEST 226: re_tests:353 +--- re: a[b-a] +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 227: re_tests:354 +--- re: a[]b +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 228: re_tests:355 +--- re: a[ +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 229: re_tests:356 +--- re: a] +--- s eval: "A]" +--- flags: i + + + +=== TEST 230: re_tests:357 +--- re: a[]]b +--- s eval: "A]B" +--- flags: i + + + +=== TEST 231: re_tests:358 +--- re: a[^bc]d +--- s eval: "AED" +--- flags: i + + + +=== TEST 232: re_tests:359 +--- re: a[^bc]d +--- s eval: "ABD" +--- flags: i + + + +=== TEST 233: re_tests:360 +--- re: a[^-b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 234: re_tests:361 +--- re: a[^-b]c +--- s eval: "A-C" +--- flags: i + + + +=== TEST 235: re_tests:362 +--- re: a[^]b]c +--- s eval: "A]C" +--- flags: i + + + +=== TEST 236: re_tests:363 +--- re: a[^]b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 237: re_tests:364 +--- re: ab|cd +--- s eval: "ABC" +--- flags: i + + + +=== TEST 238: re_tests:365 +--- re: ab|cd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 239: re_tests:366 +--- re: ()ef +--- s eval: "DEF" +--- flags: i + + + +=== TEST 240: re_tests:367 +--- re: *a +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 241: re_tests:368 +--- re: (|*)b +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 242: re_tests:369 +--- re: (*)b +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 243: re_tests:370 +--- re: $b +--- s eval: "B" +--- flags: i + + + +=== TEST 244: re_tests:371 +--- re: a\ +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 245: re_tests:372 +--- re: a\(b +--- s eval: "A(B" +--- flags: i + + + +=== TEST 246: re_tests:373 +--- re: a\(*b +--- s eval: "AB" +--- flags: i + + + +=== TEST 247: re_tests:374 +--- re: a\(*b +--- s eval: "A((B" +--- flags: i + + + +=== TEST 248: re_tests:375 +--- re: a\\b +--- s eval: "A\\B" +--- flags: i + + + +=== TEST 249: re_tests:376 +--- re: abc) +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 250: re_tests:377 +--- re: (abc +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 251: re_tests:378 +--- re: ((a)) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 252: re_tests:379 +--- re: (a)b(c) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 253: re_tests:380 +--- re: a+b+c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 254: re_tests:381 +--- re: a{1,}b{1,}c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 255: re_tests:382 +--- re: a** +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 256: re_tests:383 +--- re: a.+?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 257: re_tests:384 +--- re: a.*?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 258: re_tests:385 +--- re: a.{0,5}?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 259: re_tests:386 +--- re: (a+|b)* +--- s eval: "AB" +--- flags: i + + + +=== TEST 260: re_tests:387 +--- re: (a+|b){0,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 261: re_tests:388 +--- re: (a+|b)+ +--- s eval: "AB" +--- flags: i + + + +=== TEST 262: re_tests:389 +--- re: (a+|b){1,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 263: re_tests:390 +--- re: (a+|b)? +--- s eval: "AB" +--- flags: i + + + +=== TEST 264: re_tests:391 +--- re: (a+|b){0,1} +--- s eval: "AB" +--- flags: i + + + +=== TEST 265: re_tests:392 +--- re: (a+|b){0,1}? +--- s eval: "AB" +--- flags: i + + + +=== TEST 266: re_tests:393 +--- re: )( +--- s eval: "-" +--- flags: i +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 267: re_tests:394 +--- re: [^ab]* +--- s eval: "CDE" +--- flags: i + + + +=== TEST 268: re_tests:395 +--- re: abc +--- s eval: "" +--- flags: i + + + +=== TEST 269: re_tests:396 +--- re: a* +--- s eval: "" +--- flags: i + + + +=== TEST 270: re_tests:397 +--- re: ([abc])*d +--- s eval: "ABBBCD" +--- flags: i + + + +=== TEST 271: re_tests:398 +--- re: ([abc])*bcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 272: re_tests:399 +--- re: a|b|c|d|e +--- s eval: "E" +--- flags: i + + + +=== TEST 273: re_tests:400 +--- re: (a|b|c|d|e)f +--- s eval: "EF" +--- flags: i + + + +=== TEST 274: re_tests:401 +--- re: abcd*efg +--- s eval: "ABCDEFG" +--- flags: i + + + +=== TEST 275: re_tests:402 +--- re: ab* +--- s eval: "XABYABBBZ" +--- flags: i + + + +=== TEST 276: re_tests:403 +--- re: ab* +--- s eval: "XAYABBBZ" +--- flags: i + + + +=== TEST 277: re_tests:404 +--- re: (ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 278: re_tests:405 +--- re: [abhgefdc]ij +--- s eval: "HIJ" +--- flags: i + + + +=== TEST 279: re_tests:406 +--- re: ^(ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 280: re_tests:407 +--- re: (abc|)ef +--- s eval: "ABCDEF" +--- flags: i + + + +=== TEST 281: re_tests:408 +--- re: (a|b)c*d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 282: re_tests:409 +--- re: (ab|ab*)bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 283: re_tests:410 +--- re: a([bc]*)c* +--- s eval: "ABC" +--- flags: i + + + +=== TEST 284: re_tests:411 +--- re: a([bc]*)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 285: re_tests:412 +--- re: a([bc]+)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 286: re_tests:413 +--- re: a([bc]*)(c+d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 287: re_tests:414 +--- re: a[bcd]*dcdcde +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 288: re_tests:415 +--- re: a[bcd]+dcdcde +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 289: re_tests:416 +--- re: (ab|a)b*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 290: re_tests:417 +--- re: ((a)(b)c)(d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 291: re_tests:418 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "ALPHA" +--- flags: i + + + +=== TEST 292: re_tests:419 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "ABH" +--- flags: i + + + +=== TEST 293: re_tests:420 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFGZ" +--- flags: i + + + +=== TEST 294: re_tests:421 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "IJ" +--- flags: i + + + +=== TEST 295: re_tests:422 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFG" +--- flags: i + + + +=== TEST 296: re_tests:423 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "BCDD" +--- flags: i + + + +=== TEST 297: re_tests:424 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "REFFGZ" +--- flags: i + + + +=== TEST 298: re_tests:425 +--- re: ((((((((((a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 299: re_tests:427 +--- re: ((((((((((a))))))))))\041 +--- s eval: "AA" +--- flags: i + + + +=== TEST 300: re_tests:428 +--- re: ((((((((((a))))))))))\041 +--- s eval: "A!" +--- flags: i + + + +=== TEST 301: re_tests:429 +--- re: (((((((((a))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 302: re_tests:430 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 303: re_tests:431 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c)))))))))) +--- s eval: "C" +--- flags: i + + + +=== TEST 304: re_tests:432 +--- re: multiple words of text +--- s eval: "UH-UH" +--- flags: i + + + +=== TEST 305: re_tests:433 +--- re: multiple words +--- s eval: "MULTIPLE WORDS, YEAH" +--- flags: i + + + +=== TEST 306: re_tests:434 +--- re: (.*)c(.*) +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 307: re_tests:435 +--- re: \((.*), (.*)\) +--- s eval: "(A, B)" +--- flags: i + + + +=== TEST 308: re_tests:436 +--- re: [k] +--- s eval: "AB" +--- flags: i + + + +=== TEST 309: re_tests:437 +--- re: abcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 310: re_tests:438 +--- re: a(bc)d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 311: re_tests:439 +--- re: a[-]?c +--- s eval: "AC" +--- flags: i + + + +=== TEST 312: re_tests:446 +--- re: a(?:b|c|d)(.) +--- s eval: "ace" + + + +=== TEST 313: re_tests:447 +--- re: a(?:b|c|d)*(.) +--- s eval: "ace" + + + +=== TEST 314: re_tests:448 +--- re: a(?:b|c|d)+?(.) +--- s eval: "ace" + + + +=== TEST 315: re_tests:449 +--- re: a(?:b|c|d)+?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 316: re_tests:450 +--- re: a(?:b|c|d)+(.) +--- s eval: "acdbcdbe" + + + +=== TEST 317: re_tests:451 +--- re: a(?:b|c|d){2}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 318: re_tests:452 +--- re: a(?:b|c|d){4,5}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 319: re_tests:453 +--- re: a(?:b|c|d){4,5}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 320: re_tests:454 +--- re: ((foo)|(bar))* +--- s eval: "foobar" + + + +=== TEST 321: re_tests:455 +--- re: (? +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 322: re_tests:456 +--- re: a(?:b|c|d){6,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 323: re_tests:457 +--- re: a(?:b|c|d){6,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 324: re_tests:458 +--- re: a(?:b|c|d){5,6}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 325: re_tests:459 +--- re: a(?:b|c|d){5,6}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 326: re_tests:460 +--- re: a(?:b|c|d){5,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 327: re_tests:461 +--- re: a(?:b|c|d){5,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 328: re_tests:462 +--- re: a(?:b|(c|e){1,2}?|d)+?(.) +--- s eval: "ace" + + + +=== TEST 329: re_tests:463 +--- re: ^(.+)?B +--- s eval: "AB" + + + +=== TEST 330: re_tests:464 +--- re: ^([^a-z])|(\^)$ +--- s eval: "." + + + +=== TEST 331: re_tests:465 +--- re: ^[<>]& +--- s eval: "<&OUT" + + + +=== TEST 332: re_tests:472 +--- re: ((a{4})+) +--- s eval: "aaaaaaaaa" + + + +=== TEST 333: re_tests:473 +--- re: (((aa){2})+) +--- s eval: "aaaaaaaaaa" + + + +=== TEST 334: re_tests:474 +--- re: (((a{2}){2})+) +--- s eval: "aaaaaaaaaa" + + + +=== TEST 335: re_tests:475 +--- re: (?:(f)(o)(o)|(b)(a)(r))* +--- s eval: "foobar" + + + +=== TEST 336: re_tests:483 +--- re: (?<%)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 337: re_tests:484 +--- re: (?:..)*a +--- s eval: "aba" + + + +=== TEST 338: re_tests:485 +--- re: (?:..)*?a +--- s eval: "aba" + + + +=== TEST 339: re_tests:487 +--- re: ^(){3,5} +--- s eval: "abc" + + + +=== TEST 340: re_tests:488 +--- re: ^(a+)*ax +--- s eval: "aax" + + + +=== TEST 341: re_tests:489 +--- re: ^((a|b)+)*ax +--- s eval: "aax" + + + +=== TEST 342: re_tests:490 +--- re: ^((a|bc)+)*ax +--- s eval: "aax" + + + +=== TEST 343: re_tests:491 +--- re: (a|x)*ab +--- s eval: "cab" + + + +=== TEST 344: re_tests:492 +--- re: (a)*ab +--- s eval: "cab" + + + +=== TEST 345: re_tests:531 +--- re: (?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b))) +--- s eval: "cabbbb" + + + +=== TEST 346: re_tests:532 +--- re: (?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb))) +--- s eval: "caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + + + +=== TEST 347: re_tests:535 +--- re: foo\w*\d{4}baz +--- s eval: "foobar1234baz" + + + +=== TEST 348: re_tests:537 +--- re: a(?{)b +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 349: re_tests:544 +--- re: x(~~)*(?:(?:F)?)? +--- s eval: "x~~" + + + +=== TEST 350: re_tests:552 +--- re: ^(?:a?b?)*$ +--- s eval: "a--" + + + +=== TEST 351: re_tests:565 +--- re: ^b +--- s eval: "a\nb\nc\n" + + + +=== TEST 352: re_tests:566 +--- re: ()^b +--- s eval: "a\nb\nc\n" + + + +=== TEST 353: re_tests:595 +--- re: (\w+:)+ +--- s eval: "one:" + + + +=== TEST 354: re_tests:599 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd:" + + + +=== TEST 355: re_tests:600 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd" + + + +=== TEST 356: re_tests:601 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "xy:z:::abcd" + + + +=== TEST 357: re_tests:602 +--- re: ^[^bcd]*(c+) +--- s eval: "aexycd" + + + +=== TEST 358: re_tests:603 +--- re: (a*)b+ +--- s eval: "caab" + + + +=== TEST 359: re_tests:610 +--- re: (>a+)ab +--- s eval: "aaab" + + + +=== TEST 360: re_tests:612 +--- re: ([[:]+) +--- s eval: "a:[b]:" + + + +=== TEST 361: re_tests:613 +--- re: ([[=]+) +--- s eval: "a=[b]=" + + + +=== TEST 362: re_tests:614 +--- re: ([[.]+) +--- s eval: "a.[b]." + + + +=== TEST 363: re_tests:615 +--- re: [a[:xyz: +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 364: re_tests:617 +--- re: [a[:]b[:c] +--- s eval: "abc" + + + +=== TEST 365: re_tests:651 +--- re: a{37,17} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 366: re_tests:652 +--- re: a{37,0} +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 367: re_tests:654 +--- re: \z +--- s eval: "a\nb\n" + + + +=== TEST 368: re_tests:655 +--- re: $ +--- s eval: "a\nb\n" + + + +=== TEST 369: re_tests:657 +--- re: \z +--- s eval: "b\na\n" + + + +=== TEST 370: re_tests:658 +--- re: $ +--- s eval: "b\na\n" + + + +=== TEST 371: re_tests:660 +--- re: \z +--- s eval: "b\na" + + + +=== TEST 372: re_tests:661 +--- re: $ +--- s eval: "b\na" + + + +=== TEST 373: re_tests:663 +--- re: \z +--- s eval: "a\nb\n" + + + +=== TEST 374: re_tests:664 +--- re: $ +--- s eval: "a\nb\n" + + + +=== TEST 375: re_tests:666 +--- re: \z +--- s eval: "b\na\n" + + + +=== TEST 376: re_tests:667 +--- re: $ +--- s eval: "b\na\n" + + + +=== TEST 377: re_tests:669 +--- re: \z +--- s eval: "b\na" + + + +=== TEST 378: re_tests:670 +--- re: $ +--- s eval: "b\na" + + + +=== TEST 379: re_tests:672 +--- re: a\z +--- s eval: "a\nb\n" + + + +=== TEST 380: re_tests:673 +--- re: a$ +--- s eval: "a\nb\n" + + + +=== TEST 381: re_tests:675 +--- re: a\z +--- s eval: "b\na\n" + + + +=== TEST 382: re_tests:676 +--- re: a$ +--- s eval: "b\na\n" + + + +=== TEST 383: re_tests:678 +--- re: a\z +--- s eval: "b\na" + + + +=== TEST 384: re_tests:679 +--- re: a$ +--- s eval: "b\na" + + + +=== TEST 385: re_tests:681 +--- re: a\z +--- s eval: "a\nb\n" + + + +=== TEST 386: re_tests:682 +--- re: a$ +--- s eval: "a\nb\n" + + + +=== TEST 387: re_tests:684 +--- re: a\z +--- s eval: "b\na\n" + + + +=== TEST 388: re_tests:685 +--- re: a$ +--- s eval: "b\na\n" + + + +=== TEST 389: re_tests:687 +--- re: a\z +--- s eval: "b\na" + + + +=== TEST 390: re_tests:688 +--- re: a$ +--- s eval: "b\na" + + + +=== TEST 391: re_tests:690 +--- re: aa\z +--- s eval: "aa\nb\n" + + + +=== TEST 392: re_tests:691 +--- re: aa$ +--- s eval: "aa\nb\n" + + + +=== TEST 393: re_tests:693 +--- re: aa\z +--- s eval: "b\naa\n" + + + +=== TEST 394: re_tests:694 +--- re: aa$ +--- s eval: "b\naa\n" + + + +=== TEST 395: re_tests:696 +--- re: aa\z +--- s eval: "b\naa" + + + +=== TEST 396: re_tests:697 +--- re: aa$ +--- s eval: "b\naa" + + + +=== TEST 397: re_tests:699 +--- re: aa\z +--- s eval: "aa\nb\n" + + + +=== TEST 398: re_tests:700 +--- re: aa$ +--- s eval: "aa\nb\n" + + + +=== TEST 399: re_tests:702 +--- re: aa\z +--- s eval: "b\naa\n" + + + +=== TEST 400: re_tests:703 +--- re: aa$ +--- s eval: "b\naa\n" + + + +=== TEST 401: re_tests:705 +--- re: aa\z +--- s eval: "b\naa" + + + +=== TEST 402: re_tests:706 +--- re: aa$ +--- s eval: "b\naa" + + + +=== TEST 403: re_tests:708 +--- re: aa\z +--- s eval: "ac\nb\n" + + + +=== TEST 404: re_tests:709 +--- re: aa$ +--- s eval: "ac\nb\n" + + + +=== TEST 405: re_tests:711 +--- re: aa\z +--- s eval: "b\nac\n" + + + +=== TEST 406: re_tests:712 +--- re: aa$ +--- s eval: "b\nac\n" + + + +=== TEST 407: re_tests:714 +--- re: aa\z +--- s eval: "b\nac" + + + +=== TEST 408: re_tests:715 +--- re: aa$ +--- s eval: "b\nac" + + + +=== TEST 409: re_tests:717 +--- re: aa\z +--- s eval: "ac\nb\n" + + + +=== TEST 410: re_tests:718 +--- re: aa$ +--- s eval: "ac\nb\n" + + + +=== TEST 411: re_tests:720 +--- re: aa\z +--- s eval: "b\nac\n" + + + +=== TEST 412: re_tests:721 +--- re: aa$ +--- s eval: "b\nac\n" + + + +=== TEST 413: re_tests:723 +--- re: aa\z +--- s eval: "b\nac" + + + +=== TEST 414: re_tests:724 +--- re: aa$ +--- s eval: "b\nac" + + + +=== TEST 415: re_tests:726 +--- re: aa\z +--- s eval: "ca\nb\n" + + + +=== TEST 416: re_tests:727 +--- re: aa$ +--- s eval: "ca\nb\n" + + + +=== TEST 417: re_tests:729 +--- re: aa\z +--- s eval: "b\nca\n" + + + +=== TEST 418: re_tests:730 +--- re: aa$ +--- s eval: "b\nca\n" + + + +=== TEST 419: re_tests:732 +--- re: aa\z +--- s eval: "b\nca" + + + +=== TEST 420: re_tests:733 +--- re: aa$ +--- s eval: "b\nca" + + + +=== TEST 421: re_tests:735 +--- re: aa\z +--- s eval: "ca\nb\n" + + + +=== TEST 422: re_tests:736 +--- re: aa$ +--- s eval: "ca\nb\n" + + + +=== TEST 423: re_tests:738 +--- re: aa\z +--- s eval: "b\nca\n" + + + +=== TEST 424: re_tests:739 +--- re: aa$ +--- s eval: "b\nca\n" + + + +=== TEST 425: re_tests:741 +--- re: aa\z +--- s eval: "b\nca" + + + +=== TEST 426: re_tests:742 +--- re: aa$ +--- s eval: "b\nca" + + + +=== TEST 427: re_tests:744 +--- re: ab\z +--- s eval: "ab\nb\n" + + + +=== TEST 428: re_tests:745 +--- re: ab$ +--- s eval: "ab\nb\n" + + + +=== TEST 429: re_tests:747 +--- re: ab\z +--- s eval: "b\nab\n" + + + +=== TEST 430: re_tests:748 +--- re: ab$ +--- s eval: "b\nab\n" + + + +=== TEST 431: re_tests:750 +--- re: ab\z +--- s eval: "b\nab" + + + +=== TEST 432: re_tests:751 +--- re: ab$ +--- s eval: "b\nab" + + + +=== TEST 433: re_tests:753 +--- re: ab\z +--- s eval: "ab\nb\n" + + + +=== TEST 434: re_tests:754 +--- re: ab$ +--- s eval: "ab\nb\n" + + + +=== TEST 435: re_tests:756 +--- re: ab\z +--- s eval: "b\nab\n" + + + +=== TEST 436: re_tests:757 +--- re: ab$ +--- s eval: "b\nab\n" + + + +=== TEST 437: re_tests:759 +--- re: ab\z +--- s eval: "b\nab" + + + +=== TEST 438: re_tests:760 +--- re: ab$ +--- s eval: "b\nab" + + + +=== TEST 439: re_tests:762 +--- re: ab\z +--- s eval: "ac\nb\n" + + + +=== TEST 440: re_tests:763 +--- re: ab$ +--- s eval: "ac\nb\n" + + + +=== TEST 441: re_tests:765 +--- re: ab\z +--- s eval: "b\nac\n" + + + +=== TEST 442: re_tests:766 +--- re: ab$ +--- s eval: "b\nac\n" + + + +=== TEST 443: re_tests:768 +--- re: ab\z +--- s eval: "b\nac" + + + +=== TEST 444: re_tests:769 +--- re: ab$ +--- s eval: "b\nac" + + + +=== TEST 445: re_tests:771 +--- re: ab\z +--- s eval: "ac\nb\n" + + + +=== TEST 446: re_tests:772 +--- re: ab$ +--- s eval: "ac\nb\n" + + + +=== TEST 447: re_tests:774 +--- re: ab\z +--- s eval: "b\nac\n" + + + +=== TEST 448: re_tests:775 +--- re: ab$ +--- s eval: "b\nac\n" + + + +=== TEST 449: re_tests:777 +--- re: ab\z +--- s eval: "b\nac" + + + +=== TEST 450: re_tests:778 +--- re: ab$ +--- s eval: "b\nac" + + + +=== TEST 451: re_tests:780 +--- re: ab\z +--- s eval: "ca\nb\n" + + + +=== TEST 452: re_tests:781 +--- re: ab$ +--- s eval: "ca\nb\n" + + + +=== TEST 453: re_tests:783 +--- re: ab\z +--- s eval: "b\nca\n" + + + +=== TEST 454: re_tests:784 +--- re: ab$ +--- s eval: "b\nca\n" + + + +=== TEST 455: re_tests:786 +--- re: ab\z +--- s eval: "b\nca" + + + +=== TEST 456: re_tests:787 +--- re: ab$ +--- s eval: "b\nca" + + + +=== TEST 457: re_tests:789 +--- re: ab\z +--- s eval: "ca\nb\n" + + + +=== TEST 458: re_tests:790 +--- re: ab$ +--- s eval: "ca\nb\n" + + + +=== TEST 459: re_tests:792 +--- re: ab\z +--- s eval: "b\nca\n" + + + +=== TEST 460: re_tests:793 +--- re: ab$ +--- s eval: "b\nca\n" + + + +=== TEST 461: re_tests:795 +--- re: ab\z +--- s eval: "b\nca" + + + +=== TEST 462: re_tests:796 +--- re: ab$ +--- s eval: "b\nca" + + + +=== TEST 463: re_tests:798 +--- re: abb\z +--- s eval: "abb\nb\n" + + + +=== TEST 464: re_tests:799 +--- re: abb$ +--- s eval: "abb\nb\n" + + + +=== TEST 465: re_tests:801 +--- re: abb\z +--- s eval: "b\nabb\n" + + + +=== TEST 466: re_tests:802 +--- re: abb$ +--- s eval: "b\nabb\n" + + + +=== TEST 467: re_tests:804 +--- re: abb\z +--- s eval: "b\nabb" + + + +=== TEST 468: re_tests:805 +--- re: abb$ +--- s eval: "b\nabb" + + + +=== TEST 469: re_tests:807 +--- re: abb\z +--- s eval: "abb\nb\n" + + + +=== TEST 470: re_tests:808 +--- re: abb$ +--- s eval: "abb\nb\n" + + + +=== TEST 471: re_tests:810 +--- re: abb\z +--- s eval: "b\nabb\n" + + + +=== TEST 472: re_tests:811 +--- re: abb$ +--- s eval: "b\nabb\n" + + + +=== TEST 473: re_tests:813 +--- re: abb\z +--- s eval: "b\nabb" + + + +=== TEST 474: re_tests:814 +--- re: abb$ +--- s eval: "b\nabb" + + + +=== TEST 475: re_tests:816 +--- re: abb\z +--- s eval: "ac\nb\n" + + + +=== TEST 476: re_tests:817 +--- re: abb$ +--- s eval: "ac\nb\n" + + + +=== TEST 477: re_tests:819 +--- re: abb\z +--- s eval: "b\nac\n" + + + +=== TEST 478: re_tests:820 +--- re: abb$ +--- s eval: "b\nac\n" + + + +=== TEST 479: re_tests:822 +--- re: abb\z +--- s eval: "b\nac" + + + +=== TEST 480: re_tests:823 +--- re: abb$ +--- s eval: "b\nac" + + + +=== TEST 481: re_tests:825 +--- re: abb\z +--- s eval: "ac\nb\n" + + + +=== TEST 482: re_tests:826 +--- re: abb$ +--- s eval: "ac\nb\n" + + + +=== TEST 483: re_tests:828 +--- re: abb\z +--- s eval: "b\nac\n" + + + +=== TEST 484: re_tests:829 +--- re: abb$ +--- s eval: "b\nac\n" + + + +=== TEST 485: re_tests:831 +--- re: abb\z +--- s eval: "b\nac" + + + +=== TEST 486: re_tests:832 +--- re: abb$ +--- s eval: "b\nac" + + + +=== TEST 487: re_tests:834 +--- re: abb\z +--- s eval: "ca\nb\n" + + + +=== TEST 488: re_tests:835 +--- re: abb$ +--- s eval: "ca\nb\n" + + + +=== TEST 489: re_tests:837 +--- re: abb\z +--- s eval: "b\nca\n" + + + +=== TEST 490: re_tests:838 +--- re: abb$ +--- s eval: "b\nca\n" + + + +=== TEST 491: re_tests:840 +--- re: abb\z +--- s eval: "b\nca" + + + +=== TEST 492: re_tests:841 +--- re: abb$ +--- s eval: "b\nca" + + + +=== TEST 493: re_tests:843 +--- re: abb\z +--- s eval: "ca\nb\n" + + + +=== TEST 494: re_tests:844 +--- re: abb$ +--- s eval: "ca\nb\n" + + + +=== TEST 495: re_tests:846 +--- re: abb\z +--- s eval: "b\nca\n" + + + +=== TEST 496: re_tests:847 +--- re: abb$ +--- s eval: "b\nca\n" + + + +=== TEST 497: re_tests:849 +--- re: abb\z +--- s eval: "b\nca" + + + +=== TEST 498: re_tests:850 +--- re: abb$ +--- s eval: "b\nca" + + + +=== TEST 499: re_tests:851 +--- re: (^|x)(c) +--- s eval: "ca" + + + +=== TEST 500: re_tests:852 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "x" + + + +=== TEST 501: re_tests:857 +--- re: foo.bart +--- s eval: "foo.bart" + + + +=== TEST 502: re_tests:858 +--- re: ^d[x][x][x] +--- s eval: "abcd\ndxxx" + + + +=== TEST 503: re_tests:859 +--- re: .X(.+)+X +--- s eval: "bbbbXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 504: re_tests:860 +--- re: .X(.+)+XX +--- s eval: "bbbbXcXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 505: re_tests:861 +--- re: .XX(.+)+X +--- s eval: "bbbbXXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 506: re_tests:862 +--- re: .X(.+)+X +--- s eval: "bbbbXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 507: re_tests:863 +--- re: .X(.+)+XX +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 508: re_tests:864 +--- re: .XX(.+)+X +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 509: re_tests:865 +--- re: .X(.+)+[X] +--- s eval: "bbbbXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 510: re_tests:866 +--- re: .X(.+)+[X][X] +--- s eval: "bbbbXcXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 511: re_tests:867 +--- re: .XX(.+)+[X] +--- s eval: "bbbbXXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 512: re_tests:868 +--- re: .X(.+)+[X] +--- s eval: "bbbbXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 513: re_tests:869 +--- re: .X(.+)+[X][X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 514: re_tests:870 +--- re: .XX(.+)+[X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 515: re_tests:871 +--- re: .[X](.+)+[X] +--- s eval: "bbbbXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 516: re_tests:872 +--- re: .[X](.+)+[X][X] +--- s eval: "bbbbXcXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 517: re_tests:873 +--- re: .[X][X](.+)+[X] +--- s eval: "bbbbXXcXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 518: re_tests:874 +--- re: .[X](.+)+[X] +--- s eval: "bbbbXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 519: re_tests:875 +--- re: .[X](.+)+[X][X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 520: re_tests:876 +--- re: .[X][X](.+)+[X] +--- s eval: "bbbbXXXaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 521: re_tests:877 +--- re: tt+$ +--- s eval: "xxxtt" + + + +=== TEST 522: re_tests:878 +--- re: ([a-\d]+) +--- s eval: "za-9z" + + + +=== TEST 523: re_tests:879 +--- re: ([\d-z]+) +--- s eval: "a0-za" + + + +=== TEST 524: re_tests:880 +--- re: ([\d-\s]+) +--- s eval: "a0- z" + + + +=== TEST 525: re_tests:885 +--- re: (\d+\.\d+) +--- s eval: "3.1415926" + + + +=== TEST 526: re_tests:886 +--- re: (\ba.{0,10}br) +--- s eval: "have a web browser" + + + +=== TEST 527: re_tests:887 +--- re: \.c(pp|xx|c)?$ +--- s eval: "Changes" +--- flags: i + + + +=== TEST 528: re_tests:888 +--- re: \.c(pp|xx|c)?$ +--- s eval: "IO.c" +--- flags: i + + + +=== TEST 529: re_tests:889 +--- re: (\.c(pp|xx|c)?$) +--- s eval: "IO.c" +--- flags: i + + + +=== TEST 530: re_tests:890 +--- re: ^([a-z]:) +--- s eval: "C:/" + + + +=== TEST 531: re_tests:891 +--- re: ^\S\s+aa$ +--- s eval: "\nx aa" + + + +=== TEST 532: re_tests:892 +--- re: (^|a)b +--- s eval: "ab" + + + +=== TEST 533: re_tests:893 +--- re: ^([ab]*?)(b)?(c)$ +--- s eval: "abac" + + + +=== TEST 534: re_tests:895 +--- re: ^(?:.,){2}c +--- s eval: "a,b,c" + + + +=== TEST 535: re_tests:896 +--- re: ^(.,){2}c +--- s eval: "a,b,c" + + + +=== TEST 536: re_tests:897 +--- re: ^(?:[^,]*,){2}c +--- s eval: "a,b,c" + + + +=== TEST 537: re_tests:898 +--- re: ^([^,]*,){2}c +--- s eval: "a,b,c" + + + +=== TEST 538: re_tests:899 +--- re: ^([^,]*,){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 539: re_tests:900 +--- re: ^([^,]*,){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 540: re_tests:901 +--- re: ^([^,]*,){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 541: re_tests:902 +--- re: ^([^,]{1,3},){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 542: re_tests:903 +--- re: ^([^,]{1,3},){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 543: re_tests:904 +--- re: ^([^,]{1,3},){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 544: re_tests:905 +--- re: ^([^,]{1,},){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 545: re_tests:906 +--- re: ^([^,]{1,},){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 546: re_tests:907 +--- re: ^([^,]{1,},){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 547: re_tests:908 +--- re: ^([^,]{0,3},){3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 548: re_tests:909 +--- re: ^([^,]{0,3},){3,}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 549: re_tests:910 +--- re: ^([^,]{0,3},){0,3}d +--- s eval: "aaa,b,c,d" + + + +=== TEST 550: re_tests:914 +--- re: ^(a(b)?)+$ +--- s eval: "aba" +--- cap: (0, 3) (2, 3) (1, 2) + + + +=== TEST 551: re_tests:915 +--- re: ^(aa(bb)?)+$ +--- s eval: "aabbaa" +--- cap: (0, 6) (4, 6) (2, 4) + + + +=== TEST 552: re_tests:916 +--- re: ^.{9}abc.*\n +--- s eval: "123\nabcabcabcabc\n" + + + +=== TEST 553: re_tests:917 +--- re: ^(a)?a$ +--- s eval: "a" + + + +=== TEST 554: re_tests:921 +--- re: ^(0+)?(?:x(1))? +--- s eval: "x1" + + + +=== TEST 555: re_tests:922 +--- re: ^([0-9a-fA-F]+)(?:x([0-9a-fA-F]+)?)(?:x([0-9a-fA-F]+))? +--- s eval: "012cxx0190" + + + +=== TEST 556: re_tests:923 +--- re: ^(b+?|a){1,2}c +--- s eval: "bbbac" + + + +=== TEST 557: re_tests:924 +--- re: ^(b+?|a){1,2}c +--- s eval: "bbbbac" + + + +=== TEST 558: re_tests:925 +--- re: \((\w\. \w+)\) +--- s eval: "cd. (A. Tw)" + + + +=== TEST 559: re_tests:926 +--- re: ((?:aaaa|bbbb)cccc)? +--- s eval: "aaaacccc" + + + +=== TEST 560: re_tests:927 +--- re: ((?:aaaa|bbbb)cccc)? +--- s eval: "bbbbcccc" + + + +=== TEST 561: re_tests:928 +--- re: (a)?(a)+ +--- s eval: "a" + + + +=== TEST 562: re_tests:929 +--- re: (ab)?(ab)+ +--- s eval: "ab" + + + +=== TEST 563: re_tests:930 +--- re: (abc)?(abc)+ +--- s eval: "abc" + + + +=== TEST 564: re_tests:931 +--- re: b\s^ +--- s eval: "a\nb\n" +--- cap: (2, 4) + + + +=== TEST 565: re_tests:932 +--- re: \ba +--- s eval: "a" + + + +=== TEST 566: re_tests:943 +--- re: (.*)c +--- s eval: "abcd" + + + +=== TEST 567: re_tests:960 +--- re: (.*?)c +--- s eval: "abcd" + + + +=== TEST 568: re_tests:979 +--- re: a(b)?? +--- s eval: "abc" + + + +=== TEST 569: re_tests:980 +--- re: (\d{1,3}\.){3,} +--- s eval: "128.134.142.8" + + + +=== TEST 570: re_tests:998 +--- re: x(?# +--- s eval: "x" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 571: re_tests:999 +--- re: x(?# +--- s eval: "x" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 572: re_tests:1000 +--- re: (WORDS|WORD)S +--- s eval: "WORDS" + + + +=== TEST 573: re_tests:1001 +--- re: (X.|WORDS|X.|WORD)S +--- s eval: "WORDS" + + + +=== TEST 574: re_tests:1002 +--- re: (WORDS|WORLD|WORD)S +--- s eval: "WORDS" + + + +=== TEST 575: re_tests:1003 +--- re: (X.|WORDS|WORD|Y.)S +--- s eval: "WORDS" + + + +=== TEST 576: re_tests:1004 +--- re: (foo|fool|x.|money|parted)$ +--- s eval: "fool" + + + +=== TEST 577: re_tests:1005 +--- re: (x.|foo|fool|x.|money|parted|y.)$ +--- s eval: "fool" + + + +=== TEST 578: re_tests:1006 +--- re: (foo|fool|money|parted)$ +--- s eval: "fool" + + + +=== TEST 579: re_tests:1007 +--- re: (foo|fool|x.|money|parted)$ +--- s eval: "fools" + + + +=== TEST 580: re_tests:1008 +--- re: (x.|foo|fool|x.|money|parted|y.)$ +--- s eval: "fools" + + + +=== TEST 581: re_tests:1009 +--- re: (foo|fool|money|parted)$ +--- s eval: "fools" + + + +=== TEST 582: re_tests:1010 +--- re: (a|aa|aaa||aaaa|aaaaa|aaaaaa)(b|c) +--- s eval: "aaaaaaaaaaaaaaab" + + + +=== TEST 583: re_tests:1016 +--- re: (?:r?)*?r|(.{2,4}) +--- s eval: "abcde" + + + +=== TEST 584: re_tests:1020 +--- re: ^((?:aa)*)(?:X+((?:\d+|-)(?:X+(.+))?))?$ +--- s eval: "aaaaX5" + + + +=== TEST 585: re_tests:1021 +--- re: X(A|B||C|D)Y +--- s eval: "XXXYYY" + + + +=== TEST 586: re_tests:1023 +--- re: ^([a]{1})*$ +--- s eval: "aa" + + + +=== TEST 587: re_tests:1028 +--- re: ^(XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 588: re_tests:1029 +--- re: ^(XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 589: re_tests:1030 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 590: re_tests:1031 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 591: re_tests:1032 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 592: re_tests:1033 +--- re: ^([TUV]+|XXXXXXXXXX|YYYYYYYYYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQX:" + + + +=== TEST 593: re_tests:1034 +--- re: ^(XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 594: re_tests:1035 +--- re: ^(XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 595: re_tests:1036 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 596: re_tests:1037 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P): +--- s eval: "ZEQQQX:" + + + +=== TEST 597: re_tests:1038 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQQQQQQQQQQQQQQQQP:" + + + +=== TEST 598: re_tests:1039 +--- re: ^([TUV]+|XXX|YYY|Z.Q*X|Z[TE]Q*P|[MKJ]): +--- s eval: "ZEQQQX:" + + + +=== TEST 599: re_tests:1040 +--- re: X(?:ABCF[cC]x*|ABCD|ABCF):(?:DIT|DID|DIM) +--- s eval: "XABCFCxxxxxxxxxx:DIM" + + + +=== TEST 600: re_tests:1041 +--- re: (((ABCD|ABCE|ABCF)))(A|B|C[xy]*): +--- s eval: "ABCFCxxxxxxxxxx:DIM" + + + +=== TEST 601: re_tests:1084 +--- re: (?P<=n>foo|bar|baz) +--- s eval: "snofooewa" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 602: re_tests:1085 +--- re: (?Pfoo|bar|baz) +--- s eval: "snofooewa" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 603: re_tests:1086 +--- re: (?PXfoo|bar|baz) +--- s eval: "snofooewa" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 604: re_tests:1208 +--- re: (foo[1x]|bar[2x]|baz[3x])+y +--- s eval: "foo1bar2baz3y" + + + +=== TEST 605: re_tests:1210 +--- re: (foo[1x]|bar[2x]|baz[3x])*y +--- s eval: "foo1bar2baz3y" + + + +=== TEST 606: re_tests:1213 +--- re: ([yX].|WORDS|[yX].|WORD)S +--- s eval: "WORDS" + + + +=== TEST 607: re_tests:1215 +--- re: ([yX].|WORDS|WORD|[xY].)S +--- s eval: "WORDS" + + + +=== TEST 608: re_tests:1216 +--- re: (foo|fool|[zx].|money|parted)$ +--- s eval: "fool" + + + +=== TEST 609: re_tests:1217 +--- re: ([zx].|foo|fool|[zq].|money|parted|[yx].)$ +--- s eval: "fool" + + + +=== TEST 610: re_tests:1218 +--- re: (foo|fool|[zx].|money|parted)$ +--- s eval: "fools" + + + +=== TEST 611: re_tests:1219 +--- re: ([zx].|foo|fool|[qx].|money|parted|[py].)$ +--- s eval: "fools" + + + +=== TEST 612: re_tests:1221 +--- re: ([yX].|WORDS|[yX].|WORD)+S +--- s eval: "WORDS" + + + +=== TEST 613: re_tests:1222 +--- re: (WORDS|WORLD|WORD)+S +--- s eval: "WORDS" + + + +=== TEST 614: re_tests:1223 +--- re: ([yX].|WORDS|WORD|[xY].)+S +--- s eval: "WORDS" + + + +=== TEST 615: re_tests:1224 +--- re: (foo|fool|[zx].|money|parted)+$ +--- s eval: "fool" + + + +=== TEST 616: re_tests:1225 +--- re: ([zx].|foo|fool|[zq].|money|parted|[yx].)+$ +--- s eval: "fool" + + + +=== TEST 617: re_tests:1226 +--- re: (foo|fool|[zx].|money|parted)+$ +--- s eval: "fools" + + + +=== TEST 618: re_tests:1227 +--- re: ([zx].|foo|fool|[qx].|money|parted|[py].)+$ +--- s eval: "fools" + + + +=== TEST 619: re_tests:1229 +--- re: (x|y|z[QW])+(longish|loquatious|excessive|overblown[QW])+ +--- s eval: "xyzQzWlongishoverblownW" + + + +=== TEST 620: re_tests:1230 +--- re: (x|y|z[QW])*(longish|loquatious|excessive|overblown[QW])* +--- s eval: "xyzQzWlongishoverblownW" + + + +=== TEST 621: re_tests:1231 +--- re: (x|y|z[QW]){1,5}(longish|loquatious|excessive|overblown[QW]){1,5} +--- s eval: "xyzQzWlongishoverblownW" + + + +=== TEST 622: re_tests:1270 +--- re: (?''foo) bar +--- s eval: "..foo bar.." +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 623: re_tests:1271 +--- re: (?<>foo) bar +--- s eval: "..foo bar.." +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 624: re_tests:1272 +--- re: foo \k'n' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 625: re_tests:1273 +--- re: foo \k +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 626: re_tests:1274 +--- re: foo \k'a1' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 627: re_tests:1275 +--- re: foo \k +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 628: re_tests:1276 +--- re: foo \k'_' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 629: re_tests:1277 +--- re: foo \k<_> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 630: re_tests:1278 +--- re: foo \k'_0_' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 631: re_tests:1279 +--- re: foo \k<_0_> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 632: re_tests:1280 +--- re: foo \k'0' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 633: re_tests:1281 +--- re: foo \k<0> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 634: re_tests:1282 +--- re: foo \k'12' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 635: re_tests:1283 +--- re: foo \k<12> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 636: re_tests:1284 +--- re: foo \k'1a' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 637: re_tests:1285 +--- re: foo \k<1a> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 638: re_tests:1286 +--- re: foo \k'' +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 639: re_tests:1287 +--- re: foo \k<> +--- s eval: "foo foo" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 640: re_tests:1364 +--- re: foo(\v+)bar +--- s eval: "foo\r\n\x{85}\r\n\nbar" + + + +=== TEST 641: re_tests:1365 +--- re: (\V+)(\v) +--- s eval: "foo\r\n\x{85}\r\n\nbar" + + + +=== TEST 642: re_tests:1366 +--- re: (\v+)(\V) +--- s eval: "foo\r\n\x{85}\r\n\nbar" + + + +=== TEST 643: re_tests:1367 +--- re: foo(\v)bar +--- s eval: "foo\x{85}bar" + + + +=== TEST 644: re_tests:1368 +--- re: (\V)(\v) +--- s eval: "foo\x{85}bar" + + + +=== TEST 645: re_tests:1369 +--- re: (\v)(\V) +--- s eval: "foo\x{85}bar" + + + +=== TEST 646: re_tests:1370 +--- re: foo(\v)bar +--- s eval: "foo\rbar" + + + +=== TEST 647: re_tests:1371 +--- re: (\V)(\v) +--- s eval: "foo\rbar" + + + +=== TEST 648: re_tests:1372 +--- re: (\v)(\V) +--- s eval: "foo\rbar" + + + +=== TEST 649: re_tests:1375 +--- re: foo(\h+)bar +--- s eval: "foo\t\x{A0}bar" + + + +=== TEST 650: re_tests:1376 +--- re: (\H+)(\h) +--- s eval: "foo\t\x{A0}bar" + + + +=== TEST 651: re_tests:1377 +--- re: (\h+)(\H) +--- s eval: "foo\t\x{A0}bar" + + + +=== TEST 652: re_tests:1378 +--- re: foo(\h)bar +--- s eval: "foo\x{A0}bar" + + + +=== TEST 653: re_tests:1379 +--- re: (\H)(\h) +--- s eval: "foo\x{A0}bar" + + + +=== TEST 654: re_tests:1380 +--- re: (\h)(\H) +--- s eval: "foo\x{A0}bar" + + + +=== TEST 655: re_tests:1381 +--- re: foo(\h)bar +--- s eval: "foo\tbar" + + + +=== TEST 656: re_tests:1382 +--- re: (\H)(\h) +--- s eval: "foo\tbar" + + + +=== TEST 657: re_tests:1383 +--- re: (\h)(\H) +--- s eval: "foo\tbar" + + + +=== TEST 658: re_tests:1385 +--- re: .*\z +--- s eval: "foo\n" + + + +=== TEST 659: re_tests:1386 +--- re: \N*\z +--- s eval: "foo\n" + + + +=== TEST 660: re_tests:1389 +--- re: ^(?:(\d)x)?\d$ +--- s eval: "1" + + + +=== TEST 661: re_tests:1390 +--- re: .*?(?:(\w)|(\w))x +--- s eval: "abx" + + + +=== TEST 662: re_tests:1392 +--- re: 0{50} +--- s eval: "000000000000000000000000000000000000000000000000000" + + + +=== TEST 663: re_tests:1395 +--- re: >\d+$ \n +--- s eval: ">10\n" +--- flags: i + + + +=== TEST 664: re_tests:1396 +--- re: >\d+$ \n +--- s eval: ">1\n" +--- flags: i + + + +=== TEST 665: re_tests:1397 +--- re: \d+$ \n +--- s eval: ">10\n" +--- flags: i + + + +=== TEST 666: re_tests:1398 +--- re: >\d\d$ \n +--- s eval: ">10\n" +--- flags: i + + + +=== TEST 667: re_tests:1399 +--- re: >\d+$ \n +--- s eval: ">10\n" + + + +=== TEST 668: re_tests:1403 +--- re: ^\s*i.*?o\s*$ +--- s eval: "io\n io" + + + +=== TEST 669: re_tests:1416 +--- re: [\s][\S] +--- s eval: "\x{a0}\x{a0}" + + + +=== TEST 670: re_tests:1424 +--- re: abc\N\{U+BEEF} +--- s eval: "abc\n{UBEEF}" + + + +=== TEST 671: re_tests:1425 +--- re: abc\N\{U+BEEF} +--- s eval: "abc.{UBEEF}" + + + +=== TEST 672: re_tests:1426 +--- re: [abc\N\{U+BEEF}] +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ + + + +=== TEST 673: re_tests:1429 +--- re: abc\N +--- s eval: "abcd" + + + +=== TEST 674: re_tests:1430 +--- re: abc\N +--- s eval: "abc\n" + + + +=== TEST 675: re_tests:1437 +--- re: abc\N{def +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ +--- SKIP + + + +=== TEST 676: re_tests:1447 +--- re: abc\N{def +--- s eval: "-" +--- err_like: ^\[error\] syntax error at pos \d+$ +--- SKIP + + + +=== TEST 677: re_tests:1450 +--- re: abc\N {U+41} +--- s eval: "-" + + + +=== TEST 678: re_tests:1451 +--- re: abc\N {SPACE} +--- s eval: "-" + + + +=== TEST 679: re_tests:1460 +--- re: \c` +--- s eval: "-" + + + +=== TEST 680: re_tests:1461 +--- re: \c1 +--- s eval: "-" + + + +=== TEST 681: re_tests:1462 +--- re: \cA +--- s eval: "\001" + + + +=== TEST 682: re_tests:1470 +--- re: \o{120} +--- s eval: "\x{50}" + + + +=== TEST 683: re_tests:1473 +--- re: [a\o{120}] +--- s eval: "\x{50}" + + + +=== TEST 684: re_tests:1483 +--- re: [\0] +--- s eval: "\000" + + + +=== TEST 685: re_tests:1484 +--- re: [\07] +--- s eval: "\007" + + + +=== TEST 686: re_tests:1485 +--- re: [\07] +--- s eval: "7\000" + + + +=== TEST 687: re_tests:1486 +--- re: [\006] +--- s eval: "\006" + + + +=== TEST 688: re_tests:1487 +--- re: [\006] +--- s eval: "6\000" + + + +=== TEST 689: re_tests:1488 +--- re: [\0005] +--- s eval: "\0005" + + + +=== TEST 690: re_tests:1489 +--- re: [\0005] +--- s eval: "5\000" + + + +=== TEST 691: re_tests:1490 +--- re: [\_] +--- s eval: "_" + + + +=== TEST 692: re_tests:1493 +--- re: (q1|.)*(q2|.)*(x(a|bc)*y){2,} +--- s eval: "xayxay" + + + +=== TEST 693: re_tests:1494 +--- re: (q1|.)*(q2|.)*(x(a|bc)*y){2,3} +--- s eval: "xayxay" + + + +=== TEST 694: re_tests:1495 +--- re: (q1|z)*(q2|z)*z{15}-.*?(x(a|bc)*y){2,3}Z +--- s eval: "zzzzzzzzzzzzzzzz-xayxayxayxayZ" + + + +=== TEST 695: re_tests:1497 +--- re: (?:(?:)foo|bar|zot|rt78356) +--- s eval: "foo" + + + +=== TEST 696: re_tests:1518 +--- re: s +--- s eval: "\x{17F}" +--- flags: i + + + +=== TEST 697: re_tests:1519 +--- re: s +--- s eval: "\x{17F}" +--- flags: i + + + +=== TEST 698: re_tests:1520 +--- re: s +--- s eval: "S" +--- flags: i + + + +=== TEST 699: re_tests:1530 +--- re: ^.*\d\H +--- s eval: "X1" + + + +=== TEST 700: re_tests:1531 +--- re: ^.*\d\V +--- s eval: "X1" + + + +=== TEST 701: re_tests:1539 +--- re: [s\xDF] +--- s eval: "\xDFs" +--- flags: i + + + +=== TEST 702: re_tests:1544 +--- re: ff +--- s eval: "\x{FB00}\x{FB01}" +--- flags: i + + + +=== TEST 703: re_tests:1545 +--- re: ff +--- s eval: "\x{FB01}\x{FB00}" +--- flags: i + + + +=== TEST 704: re_tests:1546 +--- re: fi +--- s eval: "\x{FB01}\x{FB00}" +--- flags: i + + + +=== TEST 705: re_tests:1547 +--- re: fi +--- s eval: "\x{FB00}\x{FB01}" +--- flags: i + + + +=== TEST 706: re_tests:1551 +--- re: ffiffl +--- s eval: "abcdef\x{FB03}\x{FB04}" +--- flags: i + + + +=== TEST 707: re_tests:1552 +--- re: \xdf\xdf +--- s eval: "abcdefssss" +--- flags: i + + + +=== TEST 708: re_tests:1554 +--- re: st +--- s eval: "\x{DF}\x{FB05}" +--- flags: i + + + +=== TEST 709: re_tests:1555 +--- re: ssst +--- s eval: "\x{DF}\x{FB05}" +--- flags: i + + + +=== TEST 710: re_tests:1563 +--- re: s\xDF +--- s eval: "\xDFs" +--- flags: i + + + +=== TEST 711: re_tests:1564 +--- re: sst +--- s eval: "s\N{LATIN SMALL LIGATURE ST}" +--- flags: i + + + +=== TEST 712: re_tests:1565 +--- re: sst +--- s eval: "s\N{LATIN SMALL LIGATURE LONG S T}" +--- flags: i + + + +=== TEST 713: re_tests:1599 +--- re: [\h] +--- s eval: "\x{A0}" + + + +=== TEST 714: re_tests:1600 +--- re: [\H] +--- s eval: "\x{BF}" + + + +=== TEST 715: re_tests:1601 +--- re: [\H] +--- s eval: "\x{A0}" + + + +=== TEST 716: re_tests:1602 +--- re: [\H] +--- s eval: "\x{A1}" + diff --git a/lib/sregex/t/03-pcre-testinput1-01.t b/lib/sregex/t/03-pcre-testinput1-01.t new file mode 100644 index 0000000..045af25 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-01.t @@ -0,0 +1,312 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:6 +--- re: the quick brown fox +--- s eval: "the quick brown fox" + + + +=== TEST 2: testinput1:7 +--- re: the quick brown fox +--- s eval: "The quick brown FOX" + + + +=== TEST 3: testinput1:8 +--- re: the quick brown fox +--- s eval: "What do you know about the quick brown fox?" + + + +=== TEST 4: testinput1:9 +--- re: the quick brown fox +--- s eval: "What do you know about THE QUICK BROWN FOX?" + + + +=== TEST 5: testinput1:12 +--- re: The quick brown fox +--- s eval: "the quick brown fox" +--- flags: i + + + +=== TEST 6: testinput1:13 +--- re: The quick brown fox +--- s eval: "The quick brown FOX" +--- flags: i + + + +=== TEST 7: testinput1:14 +--- re: The quick brown fox +--- s eval: "What do you know about the quick brown fox?" +--- flags: i + + + +=== TEST 8: testinput1:15 +--- re: The quick brown fox +--- s eval: "What do you know about THE QUICK BROWN FOX?" +--- flags: i + + + +=== TEST 9: testinput1:18 +--- re: abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz +--- s eval: "abcd\t\n\r\f\a\e9;\$\\?caxyz" + + + +=== TEST 10: testinput1:21 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 11: testinput1:23 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 12: testinput1:24 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 13: testinput1:25 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 14: testinput1:26 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 15: testinput1:27 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 16: testinput1:28 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypAzz" + + + +=== TEST 17: testinput1:29 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 18: testinput1:30 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqAzz" + + + +=== TEST 19: testinput1:31 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqAzz" + + + +=== TEST 20: testinput1:32 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqAzz" + + + +=== TEST 21: testinput1:33 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqqAzz" + + + +=== TEST 22: testinput1:34 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqqqAzz" + + + +=== TEST 23: testinput1:35 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 24: testinput1:36 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzzpqrrrabbxyyyypqAzz" + + + +=== TEST 25: testinput1:37 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabxyzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 26: testinput1:38 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 27: testinput1:39 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 28: testinput1:40 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abcxyzzpqrrrabbxyyyypqAzz" + + + +=== TEST 29: testinput1:41 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabcxyzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 30: testinput1:42 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 31: testinput1:43 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 32: testinput1:44 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyyypqAzz" + + + +=== TEST 33: testinput1:45 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyyyypqAzz" + + + +=== TEST 34: testinput1:46 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypABzz" + + + +=== TEST 35: testinput1:47 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypABBzz" + + + +=== TEST 36: testinput1:48 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: ">>>aaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 37: testinput1:49 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: ">aaaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 38: testinput1:50 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: ">>>>abcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 39: testinput1:51 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "*** Failers" + + + +=== TEST 40: testinput1:52 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrabbxyyyypqAzz" + + + +=== TEST 41: testinput1:53 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrrrabbxyyyypqAzz" + + + +=== TEST 42: testinput1:54 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrrabxyyyypqAzz" + + + +=== TEST 43: testinput1:55 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz" + + + +=== TEST 44: testinput1:56 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyypqAzz" + + + +=== TEST 45: testinput1:57 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqqqqAzz" + + + +=== TEST 46: testinput1:60 +--- re: ^(abc){1,2}zz +--- s eval: "abczz" + + + +=== TEST 47: testinput1:61 +--- re: ^(abc){1,2}zz +--- s eval: "abcabczz" + + + +=== TEST 48: testinput1:62 +--- re: ^(abc){1,2}zz +--- s eval: "*** Failers" + + + +=== TEST 49: testinput1:63 +--- re: ^(abc){1,2}zz +--- s eval: "zz" + + + +=== TEST 50: testinput1:64 +--- re: ^(abc){1,2}zz +--- s eval: "abcabcabczz" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-02.t b/lib/sregex/t/03-pcre-testinput1-02.t new file mode 100644 index 0000000..2eef5f5 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-02.t @@ -0,0 +1,311 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:65 +--- re: ^(abc){1,2}zz +--- s eval: ">>abczz" + + + +=== TEST 2: testinput1:68 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bc" + + + +=== TEST 3: testinput1:69 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbc" + + + +=== TEST 4: testinput1:70 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbc" + + + +=== TEST 5: testinput1:71 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bac" + + + +=== TEST 6: testinput1:72 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbac" + + + +=== TEST 7: testinput1:73 +--- re: ^(b+?|a){1,2}?c +--- s eval: "aac" + + + +=== TEST 8: testinput1:74 +--- re: ^(b+?|a){1,2}?c +--- s eval: "abbbbbbbbbbbc" + + + +=== TEST 9: testinput1:75 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbbbbbbbbbac" + + + +=== TEST 10: testinput1:76 +--- re: ^(b+?|a){1,2}?c +--- s eval: "*** Failers" + + + +=== TEST 11: testinput1:77 +--- re: ^(b+?|a){1,2}?c +--- s eval: "aaac" + + + +=== TEST 12: testinput1:78 +--- re: ^(b+?|a){1,2}?c +--- s eval: "abbbbbbbbbbbac" + + + +=== TEST 13: testinput1:81 +--- re: ^(b+|a){1,2}c +--- s eval: "bc" + + + +=== TEST 14: testinput1:82 +--- re: ^(b+|a){1,2}c +--- s eval: "bbc" + + + +=== TEST 15: testinput1:83 +--- re: ^(b+|a){1,2}c +--- s eval: "bbbc" + + + +=== TEST 16: testinput1:84 +--- re: ^(b+|a){1,2}c +--- s eval: "bac" + + + +=== TEST 17: testinput1:85 +--- re: ^(b+|a){1,2}c +--- s eval: "bbac" + + + +=== TEST 18: testinput1:86 +--- re: ^(b+|a){1,2}c +--- s eval: "aac" + + + +=== TEST 19: testinput1:87 +--- re: ^(b+|a){1,2}c +--- s eval: "abbbbbbbbbbbc" + + + +=== TEST 20: testinput1:88 +--- re: ^(b+|a){1,2}c +--- s eval: "bbbbbbbbbbbac" + + + +=== TEST 21: testinput1:89 +--- re: ^(b+|a){1,2}c +--- s eval: "*** Failers" + + + +=== TEST 22: testinput1:90 +--- re: ^(b+|a){1,2}c +--- s eval: "aaac" + + + +=== TEST 23: testinput1:91 +--- re: ^(b+|a){1,2}c +--- s eval: "abbbbbbbbbbbac" + + + +=== TEST 24: testinput1:94 +--- re: ^(b+|a){1,2}?bc +--- s eval: "bbc" + + + +=== TEST 25: testinput1:97 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "babc" + + + +=== TEST 26: testinput1:98 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "bbabc" + + + +=== TEST 27: testinput1:99 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "bababc" + + + +=== TEST 28: testinput1:100 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "*** Failers" + + + +=== TEST 29: testinput1:101 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "bababbc" + + + +=== TEST 30: testinput1:102 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "babababc" + + + +=== TEST 31: testinput1:105 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "babc" + + + +=== TEST 32: testinput1:106 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "bbabc" + + + +=== TEST 33: testinput1:107 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "bababc" + + + +=== TEST 34: testinput1:108 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "*** Failers" + + + +=== TEST 35: testinput1:109 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "bababbc" + + + +=== TEST 36: testinput1:110 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "babababc" + + + +=== TEST 37: testinput1:113 +--- re: ^\ca\cA\c[\c{\c: +--- s eval: "\x01\x01\e;z" +--- err +[error] syntax error +--- SKIP + + + +=== TEST 38: testinput1:116 +--- re: ^[ab\]cde] +--- s eval: "athing" + + + +=== TEST 39: testinput1:117 +--- re: ^[ab\]cde] +--- s eval: "bthing" + + + +=== TEST 40: testinput1:118 +--- re: ^[ab\]cde] +--- s eval: "]thing" + + + +=== TEST 41: testinput1:119 +--- re: ^[ab\]cde] +--- s eval: "cthing" + + + +=== TEST 42: testinput1:120 +--- re: ^[ab\]cde] +--- s eval: "dthing" + + + +=== TEST 43: testinput1:121 +--- re: ^[ab\]cde] +--- s eval: "ething" + + + +=== TEST 44: testinput1:122 +--- re: ^[ab\]cde] +--- s eval: "*** Failers" + + + +=== TEST 45: testinput1:123 +--- re: ^[ab\]cde] +--- s eval: "fthing" + + + +=== TEST 46: testinput1:124 +--- re: ^[ab\]cde] +--- s eval: "[thing" + + + +=== TEST 47: testinput1:125 +--- re: ^[ab\]cde] +--- s eval: "\\thing" + + + +=== TEST 48: testinput1:128 +--- re: ^[]cde] +--- s eval: "]thing" + + + +=== TEST 49: testinput1:129 +--- re: ^[]cde] +--- s eval: "cthing" + + + +=== TEST 50: testinput1:130 +--- re: ^[]cde] +--- s eval: "dthing" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-03.t b/lib/sregex/t/03-pcre-testinput1-03.t new file mode 100644 index 0000000..22ea7d4 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-03.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:131 +--- re: ^[]cde] +--- s eval: "ething" + + + +=== TEST 2: testinput1:132 +--- re: ^[]cde] +--- s eval: "*** Failers" + + + +=== TEST 3: testinput1:133 +--- re: ^[]cde] +--- s eval: "athing" + + + +=== TEST 4: testinput1:134 +--- re: ^[]cde] +--- s eval: "fthing" + + + +=== TEST 5: testinput1:137 +--- re: ^[^ab\]cde] +--- s eval: "fthing" + + + +=== TEST 6: testinput1:138 +--- re: ^[^ab\]cde] +--- s eval: "[thing" + + + +=== TEST 7: testinput1:139 +--- re: ^[^ab\]cde] +--- s eval: "\\thing" + + + +=== TEST 8: testinput1:140 +--- re: ^[^ab\]cde] +--- s eval: "*** Failers" + + + +=== TEST 9: testinput1:141 +--- re: ^[^ab\]cde] +--- s eval: "athing" + + + +=== TEST 10: testinput1:142 +--- re: ^[^ab\]cde] +--- s eval: "bthing" + + + +=== TEST 11: testinput1:143 +--- re: ^[^ab\]cde] +--- s eval: "]thing" + + + +=== TEST 12: testinput1:144 +--- re: ^[^ab\]cde] +--- s eval: "cthing" + + + +=== TEST 13: testinput1:145 +--- re: ^[^ab\]cde] +--- s eval: "dthing" + + + +=== TEST 14: testinput1:146 +--- re: ^[^ab\]cde] +--- s eval: "ething" + + + +=== TEST 15: testinput1:149 +--- re: ^[^]cde] +--- s eval: "athing" + + + +=== TEST 16: testinput1:150 +--- re: ^[^]cde] +--- s eval: "fthing" + + + +=== TEST 17: testinput1:151 +--- re: ^[^]cde] +--- s eval: "*** Failers" + + + +=== TEST 18: testinput1:152 +--- re: ^[^]cde] +--- s eval: "]thing" + + + +=== TEST 19: testinput1:153 +--- re: ^[^]cde] +--- s eval: "cthing" + + + +=== TEST 20: testinput1:154 +--- re: ^[^]cde] +--- s eval: "dthing" + + + +=== TEST 21: testinput1:155 +--- re: ^[^]cde] +--- s eval: "ething" + + + +=== TEST 22: testinput1:158 +--- re: ^\ +--- s eval: "" + + + +=== TEST 23: testinput1:161 +--- re: ^ +--- s eval: "" + + + +=== TEST 24: testinput1:164 +--- re: ^[0-9]+$ +--- s eval: "0" + + + +=== TEST 25: testinput1:165 +--- re: ^[0-9]+$ +--- s eval: "1" + + + +=== TEST 26: testinput1:166 +--- re: ^[0-9]+$ +--- s eval: "2" + + + +=== TEST 27: testinput1:167 +--- re: ^[0-9]+$ +--- s eval: "3" + + + +=== TEST 28: testinput1:168 +--- re: ^[0-9]+$ +--- s eval: "4" + + + +=== TEST 29: testinput1:169 +--- re: ^[0-9]+$ +--- s eval: "5" + + + +=== TEST 30: testinput1:170 +--- re: ^[0-9]+$ +--- s eval: "6" + + + +=== TEST 31: testinput1:171 +--- re: ^[0-9]+$ +--- s eval: "7" + + + +=== TEST 32: testinput1:172 +--- re: ^[0-9]+$ +--- s eval: "8" + + + +=== TEST 33: testinput1:173 +--- re: ^[0-9]+$ +--- s eval: "9" + + + +=== TEST 34: testinput1:174 +--- re: ^[0-9]+$ +--- s eval: "10" + + + +=== TEST 35: testinput1:175 +--- re: ^[0-9]+$ +--- s eval: "100" + + + +=== TEST 36: testinput1:176 +--- re: ^[0-9]+$ +--- s eval: "*** Failers" + + + +=== TEST 37: testinput1:177 +--- re: ^[0-9]+$ +--- s eval: "abc" + + + +=== TEST 38: testinput1:180 +--- re: ^.*nter +--- s eval: "enter" + + + +=== TEST 39: testinput1:181 +--- re: ^.*nter +--- s eval: "inter" + + + +=== TEST 40: testinput1:182 +--- re: ^.*nter +--- s eval: "uponter" + + + +=== TEST 41: testinput1:185 +--- re: ^xxx[0-9]+$ +--- s eval: "xxx0" + + + +=== TEST 42: testinput1:186 +--- re: ^xxx[0-9]+$ +--- s eval: "xxx1234" + + + +=== TEST 43: testinput1:187 +--- re: ^xxx[0-9]+$ +--- s eval: "*** Failers" + + + +=== TEST 44: testinput1:188 +--- re: ^xxx[0-9]+$ +--- s eval: "xxx" + + + +=== TEST 45: testinput1:191 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "x123" + + + +=== TEST 46: testinput1:192 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "xx123" + + + +=== TEST 47: testinput1:193 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "123456" + + + +=== TEST 48: testinput1:194 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "*** Failers" + + + +=== TEST 49: testinput1:195 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "123" + + + +=== TEST 50: testinput1:196 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "x1234" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-04.t b/lib/sregex/t/03-pcre-testinput1-04.t new file mode 100644 index 0000000..9c30fb7 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-04.t @@ -0,0 +1,321 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:199 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "x123" + + + +=== TEST 2: testinput1:200 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "xx123" + + + +=== TEST 3: testinput1:201 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "123456" + + + +=== TEST 4: testinput1:202 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "*** Failers" + + + +=== TEST 5: testinput1:203 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "123" + + + +=== TEST 6: testinput1:204 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "x1234" + + + +=== TEST 7: testinput1:207 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!pqr=apquxz.ixr.zzz.ac.uk" + + + +=== TEST 8: testinput1:208 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "*** Failers" + + + +=== TEST 9: testinput1:209 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "!pqr=apquxz.ixr.zzz.ac.uk" + + + +=== TEST 10: testinput1:210 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!=apquxz.ixr.zzz.ac.uk" + + + +=== TEST 11: testinput1:211 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!pqr=apquxz:ixr.zzz.ac.uk" + + + +=== TEST 12: testinput1:212 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!pqr=apquxz.ixr.zzz.ac.ukk" + + + +=== TEST 13: testinput1:215 +--- re: : +--- s eval: "Well, we need a colon: somewhere" + + + +=== TEST 14: testinput1:216 +--- re: : +--- s eval: "*** Fail if we don't" + + + +=== TEST 15: testinput1:219 +--- re: ([\da-f:]+)$ +--- s eval: "0abc" +--- flags: i + + + +=== TEST 16: testinput1:220 +--- re: ([\da-f:]+)$ +--- s eval: "abc" +--- flags: i + + + +=== TEST 17: testinput1:221 +--- re: ([\da-f:]+)$ +--- s eval: "fed" +--- flags: i + + + +=== TEST 18: testinput1:222 +--- re: ([\da-f:]+)$ +--- s eval: "E" +--- flags: i + + + +=== TEST 19: testinput1:223 +--- re: ([\da-f:]+)$ +--- s eval: "::" +--- flags: i + + + +=== TEST 20: testinput1:224 +--- re: ([\da-f:]+)$ +--- s eval: "5f03:12C0::932e" +--- flags: i + + + +=== TEST 21: testinput1:225 +--- re: ([\da-f:]+)$ +--- s eval: "fed def" +--- flags: i + + + +=== TEST 22: testinput1:226 +--- re: ([\da-f:]+)$ +--- s eval: "Any old stuff" +--- flags: i + + + +=== TEST 23: testinput1:227 +--- re: ([\da-f:]+)$ +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 24: testinput1:228 +--- re: ([\da-f:]+)$ +--- s eval: "0zzz" +--- flags: i + + + +=== TEST 25: testinput1:229 +--- re: ([\da-f:]+)$ +--- s eval: "gzzz" +--- flags: i + + + +=== TEST 26: testinput1:230 +--- re: ([\da-f:]+)$ +--- s eval: "fed\x20" +--- flags: i + + + +=== TEST 27: testinput1:231 +--- re: ([\da-f:]+)$ +--- s eval: "Any old rubbish" +--- flags: i + + + +=== TEST 28: testinput1:234 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: ".1.2.3" + + + +=== TEST 29: testinput1:235 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "A.12.123.0" + + + +=== TEST 30: testinput1:236 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "*** Failers" + + + +=== TEST 31: testinput1:237 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: ".1.2.3333" + + + +=== TEST 32: testinput1:238 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "1.2.3" + + + +=== TEST 33: testinput1:239 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "1234.2.3" + + + +=== TEST 34: testinput1:242 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "1 IN SOA non-sp1 non-sp2(" + + + +=== TEST 35: testinput1:243 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "1 IN SOA non-sp1 non-sp2 (" + + + +=== TEST 36: testinput1:244 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "*** Failers" + + + +=== TEST 37: testinput1:245 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "1IN SOA non-sp1 non-sp2(" + + + +=== TEST 38: testinput1:248 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "a." + + + +=== TEST 39: testinput1:249 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "Z." + + + +=== TEST 40: testinput1:250 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "2." + + + +=== TEST 41: testinput1:251 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "ab-c.pq-r." + + + +=== TEST 42: testinput1:252 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "sxk.zzz.ac.uk." + + + +=== TEST 43: testinput1:253 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "x-.y-." + + + +=== TEST 44: testinput1:254 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "*** Failers" + + + +=== TEST 45: testinput1:255 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "-abc.peq." + + + +=== TEST 46: testinput1:258 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.a" + + + +=== TEST 47: testinput1:259 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.b0-a" + + + +=== TEST 48: testinput1:260 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.c3-b.c" + + + +=== TEST 49: testinput1:261 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.c-a.b-c" + + + +=== TEST 50: testinput1:262 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*** Failers" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-05.t b/lib/sregex/t/03-pcre-testinput1-05.t new file mode 100644 index 0000000..24331f4 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-05.t @@ -0,0 +1,311 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:263 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.0" + + + +=== TEST 2: testinput1:264 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.a-" + + + +=== TEST 3: testinput1:265 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.a-b.c-" + + + +=== TEST 4: testinput1:266 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.c-a.0-c" + + + +=== TEST 5: testinput1:278 +--- re: ^[\da-f](\.[\da-f])*$ +--- s eval: "a.b.c.d" +--- flags: i + + + +=== TEST 6: testinput1:279 +--- re: ^[\da-f](\.[\da-f])*$ +--- s eval: "A.B.C.D" +--- flags: i + + + +=== TEST 7: testinput1:280 +--- re: ^[\da-f](\.[\da-f])*$ +--- s eval: "a.b.c.1.2.3.C" +--- flags: i + + + +=== TEST 8: testinput1:283 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"1234\"" + + + +=== TEST 9: testinput1:284 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"abcd\" ;" + + + +=== TEST 10: testinput1:285 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"\" ; rhubarb" + + + +=== TEST 11: testinput1:286 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "*** Failers" + + + +=== TEST 12: testinput1:287 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"1234\" : things" + + + +=== TEST 13: testinput1:290 +--- re: ^$ +--- s eval: "" + + + +=== TEST 14: testinput1:291 +--- re: ^$ +--- s eval: "*** Failers" + + + +=== TEST 15: testinput1:306 +--- re: ^ a\ b[c ]d $ +--- s eval: "a bcd" + + + +=== TEST 16: testinput1:307 +--- re: ^ a\ b[c ]d $ +--- s eval: "a b d" + + + +=== TEST 17: testinput1:308 +--- re: ^ a\ b[c ]d $ +--- s eval: "*** Failers" + + + +=== TEST 18: testinput1:309 +--- re: ^ a\ b[c ]d $ +--- s eval: "abcd" + + + +=== TEST 19: testinput1:310 +--- re: ^ a\ b[c ]d $ +--- s eval: "ab d" + + + +=== TEST 20: testinput1:313 +--- re: ^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$ +--- s eval: "abcdefhijklm" + + + +=== TEST 21: testinput1:316 +--- re: ^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$ +--- s eval: "abcdefhijklm" + + + +=== TEST 22: testinput1:319 +--- re: ^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022] +--- s eval: "a+ Z0+\x08\n\x1d\x12" + + + +=== TEST 23: testinput1:325 +--- re: ^a*\w +--- s eval: "z" + + + +=== TEST 24: testinput1:326 +--- re: ^a*\w +--- s eval: "az" + + + +=== TEST 25: testinput1:327 +--- re: ^a*\w +--- s eval: "aaaz" + + + +=== TEST 26: testinput1:328 +--- re: ^a*\w +--- s eval: "a" + + + +=== TEST 27: testinput1:329 +--- re: ^a*\w +--- s eval: "aa" + + + +=== TEST 28: testinput1:330 +--- re: ^a*\w +--- s eval: "aaaa" + + + +=== TEST 29: testinput1:331 +--- re: ^a*\w +--- s eval: "a+" + + + +=== TEST 30: testinput1:332 +--- re: ^a*\w +--- s eval: "aa+" + + + +=== TEST 31: testinput1:335 +--- re: ^a*?\w +--- s eval: "z" + + + +=== TEST 32: testinput1:336 +--- re: ^a*?\w +--- s eval: "az" + + + +=== TEST 33: testinput1:337 +--- re: ^a*?\w +--- s eval: "aaaz" + + + +=== TEST 34: testinput1:338 +--- re: ^a*?\w +--- s eval: "a" + + + +=== TEST 35: testinput1:339 +--- re: ^a*?\w +--- s eval: "aa" + + + +=== TEST 36: testinput1:340 +--- re: ^a*?\w +--- s eval: "aaaa" + + + +=== TEST 37: testinput1:341 +--- re: ^a*?\w +--- s eval: "a+" + + + +=== TEST 38: testinput1:342 +--- re: ^a*?\w +--- s eval: "aa+" + + + +=== TEST 39: testinput1:345 +--- re: ^a+\w +--- s eval: "az" + + + +=== TEST 40: testinput1:346 +--- re: ^a+\w +--- s eval: "aaaz" + + + +=== TEST 41: testinput1:347 +--- re: ^a+\w +--- s eval: "aa" + + + +=== TEST 42: testinput1:348 +--- re: ^a+\w +--- s eval: "aaaa" + + + +=== TEST 43: testinput1:349 +--- re: ^a+\w +--- s eval: "aa+" + + + +=== TEST 44: testinput1:352 +--- re: ^a+?\w +--- s eval: "az" + + + +=== TEST 45: testinput1:353 +--- re: ^a+?\w +--- s eval: "aaaz" + + + +=== TEST 46: testinput1:354 +--- re: ^a+?\w +--- s eval: "aa" + + + +=== TEST 47: testinput1:355 +--- re: ^a+?\w +--- s eval: "aaaa" + + + +=== TEST 48: testinput1:356 +--- re: ^a+?\w +--- s eval: "aa+" + + + +=== TEST 49: testinput1:359 +--- re: ^\d{8}\w{2,} +--- s eval: "1234567890" + + + +=== TEST 50: testinput1:360 +--- re: ^\d{8}\w{2,} +--- s eval: "12345678ab" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-06.t b/lib/sregex/t/03-pcre-testinput1-06.t new file mode 100644 index 0000000..30ea789 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-06.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:361 +--- re: ^\d{8}\w{2,} +--- s eval: "12345678__" + + + +=== TEST 2: testinput1:362 +--- re: ^\d{8}\w{2,} +--- s eval: "*** Failers" + + + +=== TEST 3: testinput1:363 +--- re: ^\d{8}\w{2,} +--- s eval: "1234567" + + + +=== TEST 4: testinput1:366 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "uoie" + + + +=== TEST 5: testinput1:367 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "1234" + + + +=== TEST 6: testinput1:368 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "12345" + + + +=== TEST 7: testinput1:369 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "aaaaa" + + + +=== TEST 8: testinput1:370 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "*** Failers" + + + +=== TEST 9: testinput1:371 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "123456" + + + +=== TEST 10: testinput1:374 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "uoie" + + + +=== TEST 11: testinput1:375 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "1234" + + + +=== TEST 12: testinput1:376 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "12345" + + + +=== TEST 13: testinput1:377 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "aaaaa" + + + +=== TEST 14: testinput1:378 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "123456" + + + +=== TEST 15: testinput1:397 +--- re: ^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9] +--- s eval: "From abcd Mon Sep 01 12:33:02 1997" + + + +=== TEST 16: testinput1:400 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "From abcd Mon Sep 01 12:33:02 1997" + + + +=== TEST 17: testinput1:401 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "From abcd Mon Sep 1 12:33:02 1997" + + + +=== TEST 18: testinput1:402 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "*** Failers" + + + +=== TEST 19: testinput1:403 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "From abcd Sep 01 12:33:02 1997" + + + +=== TEST 20: testinput1:406 +--- re: ^12.34 +--- s eval: "12\n34" + + + +=== TEST 21: testinput1:407 +--- re: ^12.34 +--- s eval: "12\r34" + + + +=== TEST 22: testinput1:439 +--- re: ^abcd#rhubarb +--- s eval: "abcd" + + + +=== TEST 23: testinput1:458 +--- re: ^[ab]{1,3}(ab*|b) +--- s eval: "aabbbbb" + + + +=== TEST 24: testinput1:461 +--- re: ^[ab]{1,3}?(ab*|b) +--- s eval: "aabbbbb" + + + +=== TEST 25: testinput1:464 +--- re: ^[ab]{1,3}?(ab*?|b) +--- s eval: "aabbbbb" + + + +=== TEST 26: testinput1:467 +--- re: ^[ab]{1,3}(ab*?|b) +--- s eval: "aabbbbb" + + + +=== TEST 27: testinput1:1266 +--- re: abc\0def\00pqr\000xyz\0000AB +--- s eval: "abc\0def\00pqr\000xyz\0000AB" + + + +=== TEST 28: testinput1:1267 +--- re: abc\0def\00pqr\000xyz\0000AB +--- s eval: "abc456 abc\0def\00pqr\000xyz\0000ABCDE" + + + +=== TEST 29: testinput1:1270 +--- re: abc\x0def\x00pqr\x000xyz\x0000AB +--- s eval: "abc\x0def\x00pqr\x000xyz\x0000AB" + + + +=== TEST 30: testinput1:1271 +--- re: abc\x0def\x00pqr\x000xyz\x0000AB +--- s eval: "abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE" + + + +=== TEST 31: testinput1:1274 +--- re: ^[\000-\037] +--- s eval: "\0A" + + + +=== TEST 32: testinput1:1275 +--- re: ^[\000-\037] +--- s eval: "\01B" + + + +=== TEST 33: testinput1:1276 +--- re: ^[\000-\037] +--- s eval: "\037C" + + + +=== TEST 34: testinput1:1279 +--- re: \0* +--- s eval: "\0\0\0\0" + + + +=== TEST 35: testinput1:1282 +--- re: A\x0{2,3}Z +--- s eval: "The A\x{0}\x{0}Z" + + + +=== TEST 36: testinput1:1283 +--- re: A\x0{2,3}Z +--- s eval: "An A\0\x{0}\0Z" + + + +=== TEST 37: testinput1:1284 +--- re: A\x0{2,3}Z +--- s eval: "*** Failers" + + + +=== TEST 38: testinput1:1285 +--- re: A\x0{2,3}Z +--- s eval: "A\0Z" + + + +=== TEST 39: testinput1:1286 +--- re: A\x0{2,3}Z +--- s eval: "A\0\x{0}\0\x{0}Z" + + + +=== TEST 40: testinput1:1295 +--- re: ^\s +--- s eval: "\040abc" + + + +=== TEST 41: testinput1:1296 +--- re: ^\s +--- s eval: "\x0cabc" + + + +=== TEST 42: testinput1:1297 +--- re: ^\s +--- s eval: "\nabc" + + + +=== TEST 43: testinput1:1298 +--- re: ^\s +--- s eval: "\rabc" + + + +=== TEST 44: testinput1:1299 +--- re: ^\s +--- s eval: "\tabc" + + + +=== TEST 45: testinput1:1300 +--- re: ^\s +--- s eval: "*** Failers" + + + +=== TEST 46: testinput1:1301 +--- re: ^\s +--- s eval: "abc" + + + +=== TEST 47: testinput1:1346 +--- re: ab{1,3}bc +--- s eval: "abbbbc" + + + +=== TEST 48: testinput1:1347 +--- re: ab{1,3}bc +--- s eval: "abbbc" + + + +=== TEST 49: testinput1:1348 +--- re: ab{1,3}bc +--- s eval: "abbc" + + + +=== TEST 50: testinput1:1349 +--- re: ab{1,3}bc +--- s eval: "*** Failers" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-07.t b/lib/sregex/t/03-pcre-testinput1-07.t new file mode 100644 index 0000000..8d1eef0 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-07.t @@ -0,0 +1,315 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:1350 +--- re: ab{1,3}bc +--- s eval: "abc" + + + +=== TEST 2: testinput1:1351 +--- re: ab{1,3}bc +--- s eval: "abbbbbc" + + + +=== TEST 3: testinput1:1354 +--- re: ([^.]*)\.([^:]*):[T ]+(.*) +--- s eval: "track1.title:TBlah blah blah" + + + +=== TEST 4: testinput1:1357 +--- re: ([^.]*)\.([^:]*):[T ]+(.*) +--- s eval: "track1.title:TBlah blah blah" +--- flags: i + + + +=== TEST 5: testinput1:1360 +--- re: ([^.]*)\.([^:]*):[t ]+(.*) +--- s eval: "track1.title:TBlah blah blah" +--- flags: i + + + +=== TEST 6: testinput1:1363 +--- re: ^[W-c]+$ +--- s eval: "WXY_^abc" + + + +=== TEST 7: testinput1:1364 +--- re: ^[W-c]+$ +--- s eval: "*** Failers" + + + +=== TEST 8: testinput1:1365 +--- re: ^[W-c]+$ +--- s eval: "wxy" + + + +=== TEST 9: testinput1:1368 +--- re: ^[W-c]+$ +--- s eval: "WXY_^abc" +--- flags: i + + + +=== TEST 10: testinput1:1369 +--- re: ^[W-c]+$ +--- s eval: "wxy_^ABC" +--- flags: i + + + +=== TEST 11: testinput1:1372 +--- re: ^[\x3f-\x5F]+$ +--- s eval: "WXY_^abc" +--- flags: i + + + +=== TEST 12: testinput1:1373 +--- re: ^[\x3f-\x5F]+$ +--- s eval: "wxy_^ABC" +--- flags: i + + + +=== TEST 13: testinput1:1376 +--- re: ^abc$ +--- s eval: "abc" + + + +=== TEST 14: testinput1:1377 +--- re: ^abc$ +--- s eval: "qqq\nabc" + + + +=== TEST 15: testinput1:1378 +--- re: ^abc$ +--- s eval: "abc\nzzz" + + + +=== TEST 16: testinput1:1379 +--- re: ^abc$ +--- s eval: "qqq\nabc\nzzz" + + + +=== TEST 17: testinput1:1383 +--- re: ^abc$ +--- s eval: "*** Failers" + + + +=== TEST 18: testinput1:1404 +--- re: (?:b)|(?::+) +--- s eval: "b::c" + + + +=== TEST 19: testinput1:1405 +--- re: (?:b)|(?::+) +--- s eval: "c::b" + + + +=== TEST 20: testinput1:1408 +--- re: [-az]+ +--- s eval: "az-" + + + +=== TEST 21: testinput1:1409 +--- re: [-az]+ +--- s eval: "*** Failers" + + + +=== TEST 22: testinput1:1410 +--- re: [-az]+ +--- s eval: "b" + + + +=== TEST 23: testinput1:1413 +--- re: [az-]+ +--- s eval: "za-" + + + +=== TEST 24: testinput1:1414 +--- re: [az-]+ +--- s eval: "*** Failers" + + + +=== TEST 25: testinput1:1415 +--- re: [az-]+ +--- s eval: "b" + + + +=== TEST 26: testinput1:1418 +--- re: [a\-z]+ +--- s eval: "a-z" + + + +=== TEST 27: testinput1:1419 +--- re: [a\-z]+ +--- s eval: "*** Failers" + + + +=== TEST 28: testinput1:1420 +--- re: [a\-z]+ +--- s eval: "b" + + + +=== TEST 29: testinput1:1423 +--- re: [a-z]+ +--- s eval: "abcdxyz" + + + +=== TEST 30: testinput1:1426 +--- re: [\d-]+ +--- s eval: "12-34" + + + +=== TEST 31: testinput1:1427 +--- re: [\d-]+ +--- s eval: "*** Failers" + + + +=== TEST 32: testinput1:1428 +--- re: [\d-]+ +--- s eval: "aaa" + + + +=== TEST 33: testinput1:1431 +--- re: [\d-z]+ +--- s eval: "12-34z" + + + +=== TEST 34: testinput1:1432 +--- re: [\d-z]+ +--- s eval: "*** Failers" + + + +=== TEST 35: testinput1:1433 +--- re: [\d-z]+ +--- s eval: "aaa" + + + +=== TEST 36: testinput1:1436 +--- re: \x5c +--- s eval: "\\" + + + +=== TEST 37: testinput1:1439 +--- re: \x20Z +--- s eval: "the Zoo" + + + +=== TEST 38: testinput1:1440 +--- re: \x20Z +--- s eval: "*** Failers" + + + +=== TEST 39: testinput1:1441 +--- re: \x20Z +--- s eval: "Zulu" + + + +=== TEST 40: testinput1:1449 +--- re: ab{3cd +--- s eval: "ab{3cd" + + + +=== TEST 41: testinput1:1452 +--- re: ab{3,cd +--- s eval: "ab{3,cd" + + + +=== TEST 42: testinput1:1455 +--- re: ab{3,4a}cd +--- s eval: "ab{3,4a}cd" + + + +=== TEST 43: testinput1:1458 +--- re: {4,5a}bc +--- s eval: "{4,5a}bc" + + + +=== TEST 44: testinput1:1461 +--- re: abc$ +--- s eval: "abc" + + + +=== TEST 45: testinput1:1462 +--- re: abc$ +--- s eval: "abc\n" + + + +=== TEST 46: testinput1:1463 +--- re: abc$ +--- s eval: "*** Failers" + + + +=== TEST 47: testinput1:1464 +--- re: abc$ +--- s eval: "abc\ndef" + + + +=== TEST 48: testinput1:1502 +--- re: ab\idef +--- s eval: "abidef" + + + +=== TEST 49: testinput1:1505 +--- re: a{0}bc +--- s eval: "bc" + + + +=== TEST 50: testinput1:1508 +--- re: (a|(bc)){0,0}?xyz +--- s eval: "xyz" +--- cap: (0, 3) + + + diff --git a/lib/sregex/t/03-pcre-testinput1-08.t b/lib/sregex/t/03-pcre-testinput1-08.t new file mode 100644 index 0000000..ed522f6 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-08.t @@ -0,0 +1,315 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:1523 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baNOTccccd" + + + +=== TEST 2: testinput1:1524 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baNOTcccd" + + + +=== TEST 3: testinput1:1525 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baNOTccd" + + + +=== TEST 4: testinput1:1526 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "bacccd" + + + +=== TEST 5: testinput1:1527 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "*** Failers" + + + +=== TEST 6: testinput1:1528 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "anything" + + + +=== TEST 7: testinput1:1529 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "b\bc " + + + +=== TEST 8: testinput1:1530 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baccd" + + + +=== TEST 9: testinput1:1533 +--- re: [^a] +--- s eval: "Abc" + + + +=== TEST 10: testinput1:1536 +--- re: [^a] +--- s eval: "Abc " +--- flags: i + + + +=== TEST 11: testinput1:1539 +--- re: [^a]+ +--- s eval: "AAAaAbc" + + + +=== TEST 12: testinput1:1542 +--- re: [^a]+ +--- s eval: "AAAaAbc " +--- flags: i + + + +=== TEST 13: testinput1:1545 +--- re: [^a]+ +--- s eval: "bbb\nccc" + + + +=== TEST 14: testinput1:1548 +--- re: [^k]$ +--- s eval: "abc" + + + +=== TEST 15: testinput1:1549 +--- re: [^k]$ +--- s eval: "*** Failers" + + + +=== TEST 16: testinput1:1550 +--- re: [^k]$ +--- s eval: "abk " + + + +=== TEST 17: testinput1:1553 +--- re: [^k]{2,3}$ +--- s eval: "abc" + + + +=== TEST 18: testinput1:1554 +--- re: [^k]{2,3}$ +--- s eval: "kbc" + + + +=== TEST 19: testinput1:1555 +--- re: [^k]{2,3}$ +--- s eval: "kabc " + + + +=== TEST 20: testinput1:1556 +--- re: [^k]{2,3}$ +--- s eval: "*** Failers" + + + +=== TEST 21: testinput1:1557 +--- re: [^k]{2,3}$ +--- s eval: "abk" + + + +=== TEST 22: testinput1:1558 +--- re: [^k]{2,3}$ +--- s eval: "akb" + + + +=== TEST 23: testinput1:1559 +--- re: [^k]{2,3}$ +--- s eval: "akk " + + + +=== TEST 24: testinput1:1562 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "12345678\@a.b.c.d" + + + +=== TEST 25: testinput1:1563 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "123456789\@x.y.z" + + + +=== TEST 26: testinput1:1564 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "*** Failers" + + + +=== TEST 27: testinput1:1565 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "12345678\@x.y.uk" + + + +=== TEST 28: testinput1:1566 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "1234567\@a.b.c.d " + + + +=== TEST 29: testinput1:1575 +--- re: [^a] +--- s eval: "aaaabcd" + + + +=== TEST 30: testinput1:1576 +--- re: [^a] +--- s eval: "aaAabcd " + + + +=== TEST 31: testinput1:1579 +--- re: [^a] +--- s eval: "aaaabcd" +--- flags: i + + + +=== TEST 32: testinput1:1580 +--- re: [^a] +--- s eval: "aaAabcd " +--- flags: i + + + +=== TEST 33: testinput1:1583 +--- re: [^az] +--- s eval: "aaaabcd" + + + +=== TEST 34: testinput1:1584 +--- re: [^az] +--- s eval: "aaAabcd " + + + +=== TEST 35: testinput1:1587 +--- re: [^az] +--- s eval: "aaaabcd" +--- flags: i + + + +=== TEST 36: testinput1:1588 +--- re: [^az] +--- s eval: "aaAabcd " +--- flags: i + + + +=== TEST 37: testinput1:1594 +--- re: P[^*]TAIRE[^*]{1,6}?LL +--- s eval: "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" + + + +=== TEST 38: testinput1:1597 +--- re: P[^*]TAIRE[^*]{1,}?LL +--- s eval: "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" + + + +=== TEST 39: testinput1:1600 +--- re: (\.\d\d[1-9]?)\d+ +--- s eval: "1.230003938" + + + +=== TEST 40: testinput1:1601 +--- re: (\.\d\d[1-9]?)\d+ +--- s eval: "1.875000282 " + + + +=== TEST 41: testinput1:1602 +--- re: (\.\d\d[1-9]?)\d+ +--- s eval: "1.235 " + + + +=== TEST 42: testinput1:1614 +--- re: \b(foo)\s+(\w+) +--- s eval: "Food is on the foo table" +--- flags: i + + + +=== TEST 43: testinput1:1617 +--- re: foo(.*)bar +--- s eval: "The food is under the bar in the barn." + + + +=== TEST 44: testinput1:1620 +--- re: foo(.*?)bar +--- s eval: "The food is under the bar in the barn." + + + +=== TEST 45: testinput1:1623 +--- re: (.*)(\d*) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 46: testinput1:1626 +--- re: (.*)(\d+) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 47: testinput1:1629 +--- re: (.*?)(\d*) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 48: testinput1:1632 +--- re: (.*?)(\d+) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 49: testinput1:1635 +--- re: (.*)(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 50: testinput1:1638 +--- re: (.*?)(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-09.t b/lib/sregex/t/03-pcre-testinput1-09.t new file mode 100644 index 0000000..292fe86 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-09.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:1641 +--- re: (.*)\b(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 2: testinput1:1644 +--- re: (.*\D)(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 3: testinput1:1655 +--- re: ^[W-]46] +--- s eval: "W46]789 " + + + +=== TEST 4: testinput1:1656 +--- re: ^[W-]46] +--- s eval: "-46]789" + + + +=== TEST 5: testinput1:1657 +--- re: ^[W-]46] +--- s eval: "*** Failers" + + + +=== TEST 6: testinput1:1658 +--- re: ^[W-]46] +--- s eval: "Wall" + + + +=== TEST 7: testinput1:1659 +--- re: ^[W-]46] +--- s eval: "Zebra" + + + +=== TEST 8: testinput1:1660 +--- re: ^[W-]46] +--- s eval: "42" + + + +=== TEST 9: testinput1:1661 +--- re: ^[W-]46] +--- s eval: "[abcd] " + + + +=== TEST 10: testinput1:1662 +--- re: ^[W-]46] +--- s eval: "]abcd[" + + + +=== TEST 11: testinput1:1665 +--- re: ^[W-\]46] +--- s eval: "W46]789 " + + + +=== TEST 12: testinput1:1666 +--- re: ^[W-\]46] +--- s eval: "Wall" + + + +=== TEST 13: testinput1:1667 +--- re: ^[W-\]46] +--- s eval: "Zebra" + + + +=== TEST 14: testinput1:1668 +--- re: ^[W-\]46] +--- s eval: "Xylophone " + + + +=== TEST 15: testinput1:1669 +--- re: ^[W-\]46] +--- s eval: "42" + + + +=== TEST 16: testinput1:1670 +--- re: ^[W-\]46] +--- s eval: "[abcd] " + + + +=== TEST 17: testinput1:1671 +--- re: ^[W-\]46] +--- s eval: "]abcd[" + + + +=== TEST 18: testinput1:1672 +--- re: ^[W-\]46] +--- s eval: "\\backslash " + + + +=== TEST 19: testinput1:1673 +--- re: ^[W-\]46] +--- s eval: "*** Failers" + + + +=== TEST 20: testinput1:1674 +--- re: ^[W-\]46] +--- s eval: "-46]789" + + + +=== TEST 21: testinput1:1675 +--- re: ^[W-\]46] +--- s eval: "well" + + + +=== TEST 22: testinput1:1678 +--- re: \d\d\/\d\d\/\d\d\d\d +--- s eval: "01/01/2000" + + + +=== TEST 23: testinput1:1681 +--- re: word (?:[a-zA-Z0-9]+ ){0,10}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark otherword" + + + +=== TEST 24: testinput1:1682 +--- re: word (?:[a-zA-Z0-9]+ ){0,10}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark" + + + +=== TEST 25: testinput1:1685 +--- re: word (?:[a-zA-Z0-9]+ ){0,300}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" + + + +=== TEST 26: testinput1:1688 +--- re: ^(a){0,0} +--- s eval: "bcd" + + + +=== TEST 27: testinput1:1689 +--- re: ^(a){0,0} +--- s eval: "abc" + + + +=== TEST 28: testinput1:1690 +--- re: ^(a){0,0} +--- s eval: "aab " + + + +=== TEST 29: testinput1:1693 +--- re: ^(a){0,1} +--- s eval: "bcd" + + + +=== TEST 30: testinput1:1694 +--- re: ^(a){0,1} +--- s eval: "abc" + + + +=== TEST 31: testinput1:1695 +--- re: ^(a){0,1} +--- s eval: "aab " + + + +=== TEST 32: testinput1:1698 +--- re: ^(a){0,2} +--- s eval: "bcd" + + + +=== TEST 33: testinput1:1699 +--- re: ^(a){0,2} +--- s eval: "abc" + + + +=== TEST 34: testinput1:1700 +--- re: ^(a){0,2} +--- s eval: "aab " + + + +=== TEST 35: testinput1:1703 +--- re: ^(a){0,3} +--- s eval: "bcd" + + + +=== TEST 36: testinput1:1704 +--- re: ^(a){0,3} +--- s eval: "abc" + + + +=== TEST 37: testinput1:1705 +--- re: ^(a){0,3} +--- s eval: "aab" + + + +=== TEST 38: testinput1:1706 +--- re: ^(a){0,3} +--- s eval: "aaa " + + + +=== TEST 39: testinput1:1709 +--- re: ^(a){0,} +--- s eval: "bcd" + + + +=== TEST 40: testinput1:1710 +--- re: ^(a){0,} +--- s eval: "abc" + + + +=== TEST 41: testinput1:1711 +--- re: ^(a){0,} +--- s eval: "aab" + + + +=== TEST 42: testinput1:1712 +--- re: ^(a){0,} +--- s eval: "aaa" + + + +=== TEST 43: testinput1:1713 +--- re: ^(a){0,} +--- s eval: "aaaaaaaa " + + + +=== TEST 44: testinput1:1716 +--- re: ^(a){1,1} +--- s eval: "bcd" + + + +=== TEST 45: testinput1:1717 +--- re: ^(a){1,1} +--- s eval: "abc" + + + +=== TEST 46: testinput1:1718 +--- re: ^(a){1,1} +--- s eval: "aab " + + + +=== TEST 47: testinput1:1721 +--- re: ^(a){1,2} +--- s eval: "bcd" + + + +=== TEST 48: testinput1:1722 +--- re: ^(a){1,2} +--- s eval: "abc" + + + +=== TEST 49: testinput1:1723 +--- re: ^(a){1,2} +--- s eval: "aab " + + + +=== TEST 50: testinput1:1726 +--- re: ^(a){1,3} +--- s eval: "bcd" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-10.t b/lib/sregex/t/03-pcre-testinput1-10.t new file mode 100644 index 0000000..a71b195 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-10.t @@ -0,0 +1,309 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:1727 +--- re: ^(a){1,3} +--- s eval: "abc" + + + +=== TEST 2: testinput1:1728 +--- re: ^(a){1,3} +--- s eval: "aab" + + + +=== TEST 3: testinput1:1729 +--- re: ^(a){1,3} +--- s eval: "aaa " + + + +=== TEST 4: testinput1:1732 +--- re: ^(a){1,} +--- s eval: "bcd" + + + +=== TEST 5: testinput1:1733 +--- re: ^(a){1,} +--- s eval: "abc" + + + +=== TEST 6: testinput1:1734 +--- re: ^(a){1,} +--- s eval: "aab" + + + +=== TEST 7: testinput1:1735 +--- re: ^(a){1,} +--- s eval: "aaa" + + + +=== TEST 8: testinput1:1736 +--- re: ^(a){1,} +--- s eval: "aaaaaaaa " + + + +=== TEST 9: testinput1:1739 +--- re: .*\.gif +--- s eval: "borfle\nbib.gif\nno" + + + +=== TEST 10: testinput1:1742 +--- re: .{0,}\.gif +--- s eval: "borfle\nbib.gif\nno" + + + +=== TEST 11: testinput1:1754 +--- re: .*$ +--- s eval: "borfle\nbib.gif\nno" + + + +=== TEST 12: testinput1:1766 +--- re: .*$ +--- s eval: "borfle\nbib.gif\nno\n" + + + +=== TEST 13: testinput1:1778 +--- re: (.*X|^B) +--- s eval: "abcde\n1234Xyz" + + + +=== TEST 14: testinput1:1779 +--- re: (.*X|^B) +--- s eval: "BarFoo " + + + +=== TEST 15: testinput1:1780 +--- re: (.*X|^B) +--- s eval: "*** Failers" + + + +=== TEST 16: testinput1:1781 +--- re: (.*X|^B) +--- s eval: "abcde\nBar " + + + +=== TEST 17: testinput1:1812 +--- re: ^.*B +--- s eval: "**** Failers" + + + +=== TEST 18: testinput1:1813 +--- re: ^.*B +--- s eval: "abc\nB" + + + +=== TEST 19: testinput1:1831 +--- re: ^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] +--- s eval: "123456654321" + + + +=== TEST 20: testinput1:1834 +--- re: ^\d\d\d\d\d\d\d\d\d\d\d\d +--- s eval: "123456654321 " + + + +=== TEST 21: testinput1:1837 +--- re: ^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d] +--- s eval: "123456654321" + + + +=== TEST 22: testinput1:1840 +--- re: ^[abc]{12} +--- s eval: "abcabcabcabc" + + + +=== TEST 23: testinput1:1843 +--- re: ^[a-c]{12} +--- s eval: "abcabcabcabc" + + + +=== TEST 24: testinput1:1846 +--- re: ^(a|b|c){12} +--- s eval: "abcabcabcabc " + + + +=== TEST 25: testinput1:1849 +--- re: ^[abcdefghijklmnopqrstuvwxy0123456789] +--- s eval: "n" + + + +=== TEST 26: testinput1:1850 +--- re: ^[abcdefghijklmnopqrstuvwxy0123456789] +--- s eval: "*** Failers " + + + +=== TEST 27: testinput1:1851 +--- re: ^[abcdefghijklmnopqrstuvwxy0123456789] +--- s eval: "z " + + + +=== TEST 28: testinput1:1854 +--- re: abcde{0,0} +--- s eval: "abcd" + + + +=== TEST 29: testinput1:1855 +--- re: abcde{0,0} +--- s eval: "*** Failers" + + + +=== TEST 30: testinput1:1856 +--- re: abcde{0,0} +--- s eval: "abce " + + + +=== TEST 31: testinput1:1859 +--- re: ab[cd]{0,0}e +--- s eval: "abe" + + + +=== TEST 32: testinput1:1860 +--- re: ab[cd]{0,0}e +--- s eval: "*** Failers" + + + +=== TEST 33: testinput1:1861 +--- re: ab[cd]{0,0}e +--- s eval: "abcde " + + + +=== TEST 34: testinput1:1864 +--- re: ab(c){0,0}d +--- s eval: "abd" + + + +=== TEST 35: testinput1:1865 +--- re: ab(c){0,0}d +--- s eval: "*** Failers" + + + +=== TEST 36: testinput1:1866 +--- re: ab(c){0,0}d +--- s eval: "abcd " + + + +=== TEST 37: testinput1:1869 +--- re: a(b*) +--- s eval: "a" + + + +=== TEST 38: testinput1:1870 +--- re: a(b*) +--- s eval: "ab" + + + +=== TEST 39: testinput1:1871 +--- re: a(b*) +--- s eval: "abbbb" + + + +=== TEST 40: testinput1:1872 +--- re: a(b*) +--- s eval: "*** Failers" + + + +=== TEST 41: testinput1:1873 +--- re: a(b*) +--- s eval: "bbbbb " + + + +=== TEST 42: testinput1:1876 +--- re: ab\d{0}e +--- s eval: "abe" + + + +=== TEST 43: testinput1:1877 +--- re: ab\d{0}e +--- s eval: "*** Failers" + + + +=== TEST 44: testinput1:1878 +--- re: ab\d{0}e +--- s eval: "ab1e " + + + +=== TEST 45: testinput1:1881 +--- re: "([^\\"]+|\\.)*" +--- s eval: "the \"quick\" brown fox" + + + +=== TEST 46: testinput1:1882 +--- re: "([^\\"]+|\\.)*" +--- s eval: "\"the \\\"quick\\\" brown fox\" " + + + +=== TEST 47: testinput1:1885 +--- re: .*? +--- s eval: "abc" + + + +=== TEST 48: testinput1:1888 +--- re: \b +--- s eval: "abc " + + + +=== TEST 49: testinput1:1894 +--- re: +--- s eval: "abc" + + + +=== TEST 50: testinput1:1897 +--- re: ]{0,})>]{0,})>([\d]{0,}\.)(.*)((
([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR> +--- s eval: "43.Word Processor
(N-1286)
Lega lstaff.comCA - Statewide" +--- flags: i + + + diff --git a/lib/sregex/t/03-pcre-testinput1-11.t b/lib/sregex/t/03-pcre-testinput1-11.t new file mode 100644 index 0000000..f55bd8b --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-11.t @@ -0,0 +1,321 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:1900 +--- re: a[^a]b +--- s eval: "acb" + + + +=== TEST 2: testinput1:1901 +--- re: a[^a]b +--- s eval: "a\nb" + + + +=== TEST 3: testinput1:1904 +--- re: a.b +--- s eval: "acb" + + + +=== TEST 4: testinput1:1905 +--- re: a.b +--- s eval: "*** Failers " + + + +=== TEST 5: testinput1:1906 +--- re: a.b +--- s eval: "a\nb " + + + +=== TEST 6: testinput1:1910 +--- re: a[^a]b +--- s eval: "a\nb " + + + +=== TEST 7: testinput1:1914 +--- re: a.b +--- s eval: "a\nb " + + + +=== TEST 8: testinput1:1919 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbac" + + + +=== TEST 9: testinput1:1920 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbbac" + + + +=== TEST 10: testinput1:1921 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbbbac " + + + +=== TEST 11: testinput1:1924 +--- re: ^(b+|a){1,2}?c +--- s eval: "bac" + + + +=== TEST 12: testinput1:1925 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbac" + + + +=== TEST 13: testinput1:1926 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbbac" + + + +=== TEST 14: testinput1:1927 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbbbac" + + + +=== TEST 15: testinput1:1928 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbbbbac " + + + +=== TEST 16: testinput1:1935 +--- re: \x0{ab} +--- s eval: "\0{ab} " + + + +=== TEST 17: testinput1:1938 +--- re: (A|B)*?CD +--- s eval: "CD " + + + +=== TEST 18: testinput1:1941 +--- re: (A|B)*CD +--- s eval: "CD " + + + +=== TEST 19: testinput1:1972 +--- re: \Aabc\z +--- s eval: "abc" + + + +=== TEST 20: testinput1:1973 +--- re: \Aabc\z +--- s eval: "*** Failers" + + + +=== TEST 21: testinput1:1974 +--- re: \Aabc\z +--- s eval: "abc\n " + + + +=== TEST 22: testinput1:1975 +--- re: \Aabc\z +--- s eval: "qqq\nabc" + + + +=== TEST 23: testinput1:1976 +--- re: \Aabc\z +--- s eval: "abc\nzzz" + + + +=== TEST 24: testinput1:1977 +--- re: \Aabc\z +--- s eval: "qqq\nabc\nzzz" + + + +=== TEST 25: testinput1:1980 +--- re: \Aabc\z +--- s eval: "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/" + + + +=== TEST 26: testinput1:1983 +--- re: \Aabc\z +--- s eval: "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo" + + + +=== TEST 27: testinput1:1997 +--- re: (\d+)(\w) +--- s eval: "12345a" + + + +=== TEST 28: testinput1:1998 +--- re: (\d+)(\w) +--- s eval: "12345+ " + + + +=== TEST 29: testinput1:2210 +--- re: (abc|)+ +--- s eval: "abc" +--- cap: (0, 3) (0, 3) + + + +=== TEST 30: testinput1:2211 +--- re: (abc|)+ +--- s eval: "abcabc" +--- cap: (0, 6) (3, 6) + + + +=== TEST 31: testinput1:2212 +--- re: (abc|)+ +--- s eval: "abcabcabc" +--- cap: (0, 9) (6, 9) + + + +=== TEST 32: testinput1:2213 +--- re: (abc|)+ +--- s eval: "xyz " + + + +=== TEST 33: testinput1:2216 +--- re: ([a]*)* +--- s eval: "a" +--- cap: (0, 1) (0, 1) + + + +=== TEST 34: testinput1:2217 +--- re: ([a]*)* +--- s eval: "aaaaa " +--- cap: (0, 5) (0, 5) + + + +=== TEST 35: testinput1:2220 +--- re: ([ab]*)* +--- s eval: "a" +--- cap: (0, 1) (0, 1) + + + +=== TEST 36: testinput1:2221 +--- re: ([ab]*)* +--- s eval: "b" +--- cap: (0, 1) (0, 1) + + + +=== TEST 37: testinput1:2222 +--- re: ([ab]*)* +--- s eval: "ababab" +--- cap: (0, 6) (0, 6) + + + +=== TEST 38: testinput1:2223 +--- re: ([ab]*)* +--- s eval: "aaaabcde" +--- cap: (0, 5) (0, 5) + + + +=== TEST 39: testinput1:2224 +--- re: ([ab]*)* +--- s eval: "bbbb " +--- cap: (0, 4) (0, 4) + + + +=== TEST 40: testinput1:2227 +--- re: ([^a]*)* +--- s eval: "b" +--- cap: (0, 1) (0, 1) + + + +=== TEST 41: testinput1:2228 +--- re: ([^a]*)* +--- s eval: "bbbb" +--- cap: (0, 4) (0, 4) + + + +=== TEST 42: testinput1:2229 +--- re: ([^a]*)* +--- s eval: "aaa " + + + +=== TEST 43: testinput1:2232 +--- re: ([^ab]*)* +--- s eval: "cccc" +--- cap: (0, 4) (0, 4) + + + +=== TEST 44: testinput1:2233 +--- re: ([^ab]*)* +--- s eval: "abab " + + + +=== TEST 45: testinput1:2236 +--- re: ([a]*?)* +--- s eval: "a" + + + +=== TEST 46: testinput1:2237 +--- re: ([a]*?)* +--- s eval: "aaaa " + + + +=== TEST 47: testinput1:2240 +--- re: ([ab]*?)* +--- s eval: "a" + + + +=== TEST 48: testinput1:2241 +--- re: ([ab]*?)* +--- s eval: "b" + + + +=== TEST 49: testinput1:2242 +--- re: ([ab]*?)* +--- s eval: "abab" + + + +=== TEST 50: testinput1:2243 +--- re: ([ab]*?)* +--- s eval: "baba " + + + diff --git a/lib/sregex/t/03-pcre-testinput1-12.t b/lib/sregex/t/03-pcre-testinput1-12.t new file mode 100644 index 0000000..c7a4965 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-12.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:2246 +--- re: ([^a]*?)* +--- s eval: "b" + + + +=== TEST 2: testinput1:2247 +--- re: ([^a]*?)* +--- s eval: "bbbb" + + + +=== TEST 3: testinput1:2248 +--- re: ([^a]*?)* +--- s eval: "aaa " + + + +=== TEST 4: testinput1:2251 +--- re: ([^ab]*?)* +--- s eval: "c" + + + +=== TEST 5: testinput1:2252 +--- re: ([^ab]*?)* +--- s eval: "cccc" + + + +=== TEST 6: testinput1:2253 +--- re: ([^ab]*?)* +--- s eval: "baba " + + + +=== TEST 7: testinput1:2378 +--- re: abc +--- s eval: "abc" + + + +=== TEST 8: testinput1:2379 +--- re: abc +--- s eval: "xabcy" + + + +=== TEST 9: testinput1:2380 +--- re: abc +--- s eval: "ababc" + + + +=== TEST 10: testinput1:2381 +--- re: abc +--- s eval: "*** Failers" + + + +=== TEST 11: testinput1:2382 +--- re: abc +--- s eval: "xbc" + + + +=== TEST 12: testinput1:2383 +--- re: abc +--- s eval: "axc" + + + +=== TEST 13: testinput1:2384 +--- re: abc +--- s eval: "abx" + + + +=== TEST 14: testinput1:2387 +--- re: ab*c +--- s eval: "abc" + + + +=== TEST 15: testinput1:2390 +--- re: ab*bc +--- s eval: "abc" + + + +=== TEST 16: testinput1:2391 +--- re: ab*bc +--- s eval: "abbc" + + + +=== TEST 17: testinput1:2392 +--- re: ab*bc +--- s eval: "abbbbc" + + + +=== TEST 18: testinput1:2395 +--- re: .{1} +--- s eval: "abbbbc" + + + +=== TEST 19: testinput1:2398 +--- re: .{3,4} +--- s eval: "abbbbc" + + + +=== TEST 20: testinput1:2401 +--- re: ab{0,}bc +--- s eval: "abbbbc" + + + +=== TEST 21: testinput1:2404 +--- re: ab+bc +--- s eval: "abbc" + + + +=== TEST 22: testinput1:2405 +--- re: ab+bc +--- s eval: "*** Failers" + + + +=== TEST 23: testinput1:2406 +--- re: ab+bc +--- s eval: "abc" + + + +=== TEST 24: testinput1:2407 +--- re: ab+bc +--- s eval: "abq" + + + +=== TEST 25: testinput1:2412 +--- re: ab+bc +--- s eval: "abbbbc" + + + +=== TEST 26: testinput1:2415 +--- re: ab{1,}bc +--- s eval: "abbbbc" + + + +=== TEST 27: testinput1:2421 +--- re: ab{3,4}bc +--- s eval: "abbbbc" + + + +=== TEST 28: testinput1:2424 +--- re: ab{4,5}bc +--- s eval: "*** Failers" + + + +=== TEST 29: testinput1:2425 +--- re: ab{4,5}bc +--- s eval: "abq" + + + +=== TEST 30: testinput1:2426 +--- re: ab{4,5}bc +--- s eval: "abbbbc" + + + +=== TEST 31: testinput1:2429 +--- re: ab?bc +--- s eval: "abbc" + + + +=== TEST 32: testinput1:2430 +--- re: ab?bc +--- s eval: "abc" + + + +=== TEST 33: testinput1:2433 +--- re: ab{0,1}bc +--- s eval: "abc" + + + +=== TEST 34: testinput1:2438 +--- re: ab?c +--- s eval: "abc" + + + +=== TEST 35: testinput1:2441 +--- re: ab{0,1}c +--- s eval: "abc" + + + +=== TEST 36: testinput1:2446 +--- re: ^abc$ +--- s eval: "abbbbc" + + + +=== TEST 37: testinput1:2447 +--- re: ^abc$ +--- s eval: "abcc" + + + +=== TEST 38: testinput1:2450 +--- re: ^abc +--- s eval: "abcc" + + + +=== TEST 39: testinput1:2455 +--- re: abc$ +--- s eval: "aabc" + + + +=== TEST 40: testinput1:2458 +--- re: abc$ +--- s eval: "aabcd" + + + +=== TEST 41: testinput1:2461 +--- re: ^ +--- s eval: "abc" + + + +=== TEST 42: testinput1:2464 +--- re: $ +--- s eval: "abc" + + + +=== TEST 43: testinput1:2467 +--- re: a.c +--- s eval: "abc" + + + +=== TEST 44: testinput1:2468 +--- re: a.c +--- s eval: "axc" + + + +=== TEST 45: testinput1:2471 +--- re: a.*c +--- s eval: "axyzc" + + + +=== TEST 46: testinput1:2474 +--- re: a[bc]d +--- s eval: "abd" + + + +=== TEST 47: testinput1:2475 +--- re: a[bc]d +--- s eval: "*** Failers" + + + +=== TEST 48: testinput1:2476 +--- re: a[bc]d +--- s eval: "axyzd" + + + +=== TEST 49: testinput1:2477 +--- re: a[bc]d +--- s eval: "abc" + + + +=== TEST 50: testinput1:2480 +--- re: a[b-d]e +--- s eval: "ace" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-13.t b/lib/sregex/t/03-pcre-testinput1-13.t new file mode 100644 index 0000000..990b047 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-13.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:2483 +--- re: a[b-d] +--- s eval: "aac" + + + +=== TEST 2: testinput1:2486 +--- re: a[-b] +--- s eval: "a-" + + + +=== TEST 3: testinput1:2489 +--- re: a[b-] +--- s eval: "a-" + + + +=== TEST 4: testinput1:2492 +--- re: a] +--- s eval: "a]" + + + +=== TEST 5: testinput1:2495 +--- re: a[]]b +--- s eval: "a]b" + + + +=== TEST 6: testinput1:2498 +--- re: a[^bc]d +--- s eval: "aed" + + + +=== TEST 7: testinput1:2499 +--- re: a[^bc]d +--- s eval: "*** Failers" + + + +=== TEST 8: testinput1:2500 +--- re: a[^bc]d +--- s eval: "abd" + + + +=== TEST 9: testinput1:2504 +--- re: a[^-b]c +--- s eval: "adc" + + + +=== TEST 10: testinput1:2507 +--- re: a[^]b]c +--- s eval: "adc" + + + +=== TEST 11: testinput1:2508 +--- re: a[^]b]c +--- s eval: "*** Failers" + + + +=== TEST 12: testinput1:2509 +--- re: a[^]b]c +--- s eval: "a-c" + + + +=== TEST 13: testinput1:2510 +--- re: a[^]b]c +--- s eval: "a]c" + + + +=== TEST 14: testinput1:2513 +--- re: \ba\b +--- s eval: "a-" + + + +=== TEST 15: testinput1:2514 +--- re: \ba\b +--- s eval: "-a" + + + +=== TEST 16: testinput1:2515 +--- re: \ba\b +--- s eval: "-a-" + + + +=== TEST 17: testinput1:2518 +--- re: \by\b +--- s eval: "*** Failers" + + + +=== TEST 18: testinput1:2519 +--- re: \by\b +--- s eval: "xy" + + + +=== TEST 19: testinput1:2520 +--- re: \by\b +--- s eval: "yz" + + + +=== TEST 20: testinput1:2521 +--- re: \by\b +--- s eval: "xyz" + + + +=== TEST 21: testinput1:2524 +--- re: \Ba\B +--- s eval: "*** Failers" + + + +=== TEST 22: testinput1:2525 +--- re: \Ba\B +--- s eval: "a-" + + + +=== TEST 23: testinput1:2526 +--- re: \Ba\B +--- s eval: "-a" + + + +=== TEST 24: testinput1:2527 +--- re: \Ba\B +--- s eval: "-a-" + + + +=== TEST 25: testinput1:2530 +--- re: \By\b +--- s eval: "xy" + + + +=== TEST 26: testinput1:2533 +--- re: \by\B +--- s eval: "yz" + + + +=== TEST 27: testinput1:2536 +--- re: \By\B +--- s eval: "xyz" + + + +=== TEST 28: testinput1:2539 +--- re: \w +--- s eval: "a" + + + +=== TEST 29: testinput1:2542 +--- re: \W +--- s eval: "-" + + + +=== TEST 30: testinput1:2543 +--- re: \W +--- s eval: "*** Failers" + + + +=== TEST 31: testinput1:2545 +--- re: \W +--- s eval: "a" + + + +=== TEST 32: testinput1:2548 +--- re: a\sb +--- s eval: "a b" + + + +=== TEST 33: testinput1:2551 +--- re: a\Sb +--- s eval: "a-b" + + + +=== TEST 34: testinput1:2552 +--- re: a\Sb +--- s eval: "*** Failers" + + + +=== TEST 35: testinput1:2554 +--- re: a\Sb +--- s eval: "a b" + + + +=== TEST 36: testinput1:2557 +--- re: \d +--- s eval: "1" + + + +=== TEST 37: testinput1:2560 +--- re: \D +--- s eval: "-" + + + +=== TEST 38: testinput1:2561 +--- re: \D +--- s eval: "*** Failers" + + + +=== TEST 39: testinput1:2563 +--- re: \D +--- s eval: "1" + + + +=== TEST 40: testinput1:2566 +--- re: [\w] +--- s eval: "a" + + + +=== TEST 41: testinput1:2569 +--- re: [\W] +--- s eval: "-" + + + +=== TEST 42: testinput1:2570 +--- re: [\W] +--- s eval: "*** Failers" + + + +=== TEST 43: testinput1:2572 +--- re: [\W] +--- s eval: "a" + + + +=== TEST 44: testinput1:2575 +--- re: a[\s]b +--- s eval: "a b" + + + +=== TEST 45: testinput1:2578 +--- re: a[\S]b +--- s eval: "a-b" + + + +=== TEST 46: testinput1:2579 +--- re: a[\S]b +--- s eval: "*** Failers" + + + +=== TEST 47: testinput1:2581 +--- re: a[\S]b +--- s eval: "a b" + + + +=== TEST 48: testinput1:2584 +--- re: [\d] +--- s eval: "1" + + + +=== TEST 49: testinput1:2587 +--- re: [\D] +--- s eval: "-" + + + +=== TEST 50: testinput1:2588 +--- re: [\D] +--- s eval: "*** Failers" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-14.t b/lib/sregex/t/03-pcre-testinput1-14.t new file mode 100644 index 0000000..f1a5376 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-14.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:2590 +--- re: [\D] +--- s eval: "1" + + + +=== TEST 2: testinput1:2593 +--- re: ab|cd +--- s eval: "abc" + + + +=== TEST 3: testinput1:2594 +--- re: ab|cd +--- s eval: "abcd" + + + +=== TEST 4: testinput1:2597 +--- re: ()ef +--- s eval: "def" + + + +=== TEST 5: testinput1:2602 +--- re: a\(b +--- s eval: "a(b" + + + +=== TEST 6: testinput1:2605 +--- re: a\(*b +--- s eval: "ab" + + + +=== TEST 7: testinput1:2606 +--- re: a\(*b +--- s eval: "a((b" + + + +=== TEST 8: testinput1:2609 +--- re: a\\b +--- s eval: "a\b" + + + +=== TEST 9: testinput1:2612 +--- re: ((a)) +--- s eval: "abc" + + + +=== TEST 10: testinput1:2615 +--- re: (a)b(c) +--- s eval: "abc" + + + +=== TEST 11: testinput1:2618 +--- re: a+b+c +--- s eval: "aabbabc" + + + +=== TEST 12: testinput1:2621 +--- re: a{1,}b{1,}c +--- s eval: "aabbabc" + + + +=== TEST 13: testinput1:2624 +--- re: a.+?c +--- s eval: "abcabc" + + + +=== TEST 14: testinput1:2627 +--- re: (a+|b)* +--- s eval: "ab" + + + +=== TEST 15: testinput1:2630 +--- re: (a+|b){0,} +--- s eval: "ab" + + + +=== TEST 16: testinput1:2633 +--- re: (a+|b)+ +--- s eval: "ab" + + + +=== TEST 17: testinput1:2636 +--- re: (a+|b){1,} +--- s eval: "ab" + + + +=== TEST 18: testinput1:2639 +--- re: (a+|b)? +--- s eval: "ab" + + + +=== TEST 19: testinput1:2642 +--- re: (a+|b){0,1} +--- s eval: "ab" + + + +=== TEST 20: testinput1:2645 +--- re: [^ab]* +--- s eval: "cde" + + + +=== TEST 21: testinput1:2649 +--- re: abc +--- s eval: "b" + + + +=== TEST 22: testinput1:2656 +--- re: ([abc])*d +--- s eval: "abbbcd" + + + +=== TEST 23: testinput1:2659 +--- re: ([abc])*bcd +--- s eval: "abcd" + + + +=== TEST 24: testinput1:2662 +--- re: a|b|c|d|e +--- s eval: "e" + + + +=== TEST 25: testinput1:2665 +--- re: (a|b|c|d|e)f +--- s eval: "ef" + + + +=== TEST 26: testinput1:2668 +--- re: abcd*efg +--- s eval: "abcdefg" + + + +=== TEST 27: testinput1:2671 +--- re: ab* +--- s eval: "xabyabbbz" + + + +=== TEST 28: testinput1:2672 +--- re: ab* +--- s eval: "xayabbbz" + + + +=== TEST 29: testinput1:2675 +--- re: (ab|cd)e +--- s eval: "abcde" + + + +=== TEST 30: testinput1:2678 +--- re: [abhgefdc]ij +--- s eval: "hij" + + + +=== TEST 31: testinput1:2683 +--- re: (abc|)ef +--- s eval: "abcdef" + + + +=== TEST 32: testinput1:2686 +--- re: (a|b)c*d +--- s eval: "abcd" + + + +=== TEST 33: testinput1:2689 +--- re: (ab|ab*)bc +--- s eval: "abc" + + + +=== TEST 34: testinput1:2692 +--- re: a([bc]*)c* +--- s eval: "abc" + + + +=== TEST 35: testinput1:2695 +--- re: a([bc]*)(c*d) +--- s eval: "abcd" + + + +=== TEST 36: testinput1:2698 +--- re: a([bc]+)(c*d) +--- s eval: "abcd" + + + +=== TEST 37: testinput1:2701 +--- re: a([bc]*)(c+d) +--- s eval: "abcd" + + + +=== TEST 38: testinput1:2704 +--- re: a[bcd]*dcdcde +--- s eval: "adcdcde" + + + +=== TEST 39: testinput1:2707 +--- re: a[bcd]+dcdcde +--- s eval: "*** Failers" + + + +=== TEST 40: testinput1:2708 +--- re: a[bcd]+dcdcde +--- s eval: "abcde" + + + +=== TEST 41: testinput1:2709 +--- re: a[bcd]+dcdcde +--- s eval: "adcdcde" + + + +=== TEST 42: testinput1:2712 +--- re: (ab|a)b*c +--- s eval: "abc" + + + +=== TEST 43: testinput1:2715 +--- re: ((a)(b)c)(d) +--- s eval: "abcd" + + + +=== TEST 44: testinput1:2718 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "alpha" + + + +=== TEST 45: testinput1:2721 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "abh" + + + +=== TEST 46: testinput1:2724 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effgz" + + + +=== TEST 47: testinput1:2725 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "ij" + + + +=== TEST 48: testinput1:2726 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "reffgz" + + + +=== TEST 49: testinput1:2727 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "*** Failers" + + + +=== TEST 50: testinput1:2728 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effg" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-15.t b/lib/sregex/t/03-pcre-testinput1-15.t new file mode 100644 index 0000000..c684682 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-15.t @@ -0,0 +1,346 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:2729 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "bcdd" + + + +=== TEST 2: testinput1:2732 +--- re: ((((((((((a)))))))))) +--- s eval: "a" + + + +=== TEST 3: testinput1:2738 +--- re: (((((((((a))))))))) +--- s eval: "a" + + + +=== TEST 4: testinput1:2741 +--- re: multiple words of text +--- s eval: "*** Failers" + + + +=== TEST 5: testinput1:2742 +--- re: multiple words of text +--- s eval: "aa" + + + +=== TEST 6: testinput1:2743 +--- re: multiple words of text +--- s eval: "uh-uh" + + + +=== TEST 7: testinput1:2746 +--- re: multiple words +--- s eval: "multiple words, yeah" + + + +=== TEST 8: testinput1:2749 +--- re: (.*)c(.*) +--- s eval: "abcde" + + + +=== TEST 9: testinput1:2752 +--- re: \((.*), (.*)\) +--- s eval: "(a, b)" + + + +=== TEST 10: testinput1:2757 +--- re: abcd +--- s eval: "abcd" + + + +=== TEST 11: testinput1:2760 +--- re: a(bc)d +--- s eval: "abcd" + + + +=== TEST 12: testinput1:2763 +--- re: a[-]?c +--- s eval: "ac" + + + +=== TEST 13: testinput1:2790 +--- re: abc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 14: testinput1:2791 +--- re: abc +--- s eval: "XABCY" +--- flags: i + + + +=== TEST 15: testinput1:2792 +--- re: abc +--- s eval: "ABABC" +--- flags: i + + + +=== TEST 16: testinput1:2793 +--- re: abc +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 17: testinput1:2794 +--- re: abc +--- s eval: "aaxabxbaxbbx" +--- flags: i + + + +=== TEST 18: testinput1:2795 +--- re: abc +--- s eval: "XBC" +--- flags: i + + + +=== TEST 19: testinput1:2796 +--- re: abc +--- s eval: "AXC" +--- flags: i + + + +=== TEST 20: testinput1:2797 +--- re: abc +--- s eval: "ABX" +--- flags: i + + + +=== TEST 21: testinput1:2800 +--- re: ab*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 22: testinput1:2803 +--- re: ab*bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 23: testinput1:2804 +--- re: ab*bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 24: testinput1:2807 +--- re: ab*?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 25: testinput1:2810 +--- re: ab{0,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 26: testinput1:2813 +--- re: ab+?bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 27: testinput1:2816 +--- re: ab+bc +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 28: testinput1:2817 +--- re: ab+bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 29: testinput1:2818 +--- re: ab+bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 30: testinput1:2823 +--- re: ab+bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 31: testinput1:2826 +--- re: ab{1,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 32: testinput1:2829 +--- re: ab{1,3}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 33: testinput1:2832 +--- re: ab{3,4}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 34: testinput1:2835 +--- re: ab{4,5}?bc +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 35: testinput1:2836 +--- re: ab{4,5}?bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 36: testinput1:2837 +--- re: ab{4,5}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 37: testinput1:2840 +--- re: ab??bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 38: testinput1:2841 +--- re: ab??bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 39: testinput1:2844 +--- re: ab{0,1}?bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 40: testinput1:2849 +--- re: ab??c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 41: testinput1:2852 +--- re: ab{0,1}?c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 42: testinput1:2855 +--- re: ^abc$ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 43: testinput1:2856 +--- re: ^abc$ +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 44: testinput1:2857 +--- re: ^abc$ +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 45: testinput1:2858 +--- re: ^abc$ +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 46: testinput1:2861 +--- re: ^abc +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 47: testinput1:2866 +--- re: abc$ +--- s eval: "AABC" +--- flags: i + + + +=== TEST 48: testinput1:2869 +--- re: ^ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 49: testinput1:2872 +--- re: $ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 50: testinput1:2875 +--- re: a.c +--- s eval: "ABC" +--- flags: i + + + diff --git a/lib/sregex/t/03-pcre-testinput1-16.t b/lib/sregex/t/03-pcre-testinput1-16.t new file mode 100644 index 0000000..787849f --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-16.t @@ -0,0 +1,358 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:2876 +--- re: a.c +--- s eval: "AXC" +--- flags: i + + + +=== TEST 2: testinput1:2879 +--- re: a.*?c +--- s eval: "AXYZC" +--- flags: i + + + +=== TEST 3: testinput1:2882 +--- re: a.*c +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 4: testinput1:2883 +--- re: a.*c +--- s eval: "AABC" +--- flags: i + + + +=== TEST 5: testinput1:2884 +--- re: a.*c +--- s eval: "AXYZD" +--- flags: i + + + +=== TEST 6: testinput1:2887 +--- re: a[bc]d +--- s eval: "ABD" +--- flags: i + + + +=== TEST 7: testinput1:2890 +--- re: a[b-d]e +--- s eval: "ACE" +--- flags: i + + + +=== TEST 8: testinput1:2891 +--- re: a[b-d]e +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 9: testinput1:2892 +--- re: a[b-d]e +--- s eval: "ABC" +--- flags: i + + + +=== TEST 10: testinput1:2893 +--- re: a[b-d]e +--- s eval: "ABD" +--- flags: i + + + +=== TEST 11: testinput1:2896 +--- re: a[b-d] +--- s eval: "AAC" +--- flags: i + + + +=== TEST 12: testinput1:2899 +--- re: a[-b] +--- s eval: "A-" +--- flags: i + + + +=== TEST 13: testinput1:2902 +--- re: a[b-] +--- s eval: "A-" +--- flags: i + + + +=== TEST 14: testinput1:2905 +--- re: a] +--- s eval: "A]" +--- flags: i + + + +=== TEST 15: testinput1:2908 +--- re: a[]]b +--- s eval: "A]B" +--- flags: i + + + +=== TEST 16: testinput1:2911 +--- re: a[^bc]d +--- s eval: "AED" +--- flags: i + + + +=== TEST 17: testinput1:2914 +--- re: a[^-b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 18: testinput1:2915 +--- re: a[^-b]c +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 19: testinput1:2916 +--- re: a[^-b]c +--- s eval: "ABD" +--- flags: i + + + +=== TEST 20: testinput1:2917 +--- re: a[^-b]c +--- s eval: "A-C" +--- flags: i + + + +=== TEST 21: testinput1:2920 +--- re: a[^]b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 22: testinput1:2923 +--- re: ab|cd +--- s eval: "ABC" +--- flags: i + + + +=== TEST 23: testinput1:2924 +--- re: ab|cd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 24: testinput1:2927 +--- re: ()ef +--- s eval: "DEF" +--- flags: i + + + +=== TEST 25: testinput1:2930 +--- re: $b +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 26: testinput1:2931 +--- re: $b +--- s eval: "A]C" +--- flags: i + + + +=== TEST 27: testinput1:2932 +--- re: $b +--- s eval: "B" +--- flags: i + + + +=== TEST 28: testinput1:2935 +--- re: a\(b +--- s eval: "A(B" +--- flags: i + + + +=== TEST 29: testinput1:2938 +--- re: a\(*b +--- s eval: "AB" +--- flags: i + + + +=== TEST 30: testinput1:2939 +--- re: a\(*b +--- s eval: "A((B" +--- flags: i + + + +=== TEST 31: testinput1:2942 +--- re: a\\b +--- s eval: "A\\B" +--- flags: i + + + +=== TEST 32: testinput1:2945 +--- re: ((a)) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 33: testinput1:2948 +--- re: (a)b(c) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 34: testinput1:2951 +--- re: a+b+c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 35: testinput1:2954 +--- re: a{1,}b{1,}c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 36: testinput1:2957 +--- re: a.+?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 37: testinput1:2960 +--- re: a.*?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 38: testinput1:2963 +--- re: a.{0,5}?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 39: testinput1:2966 +--- re: (a+|b)* +--- s eval: "AB" +--- flags: i + + + +=== TEST 40: testinput1:2969 +--- re: (a+|b){0,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 41: testinput1:2972 +--- re: (a+|b)+ +--- s eval: "AB" +--- flags: i + + + +=== TEST 42: testinput1:2975 +--- re: (a+|b){1,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 43: testinput1:2978 +--- re: (a+|b)? +--- s eval: "AB" +--- flags: i + + + +=== TEST 44: testinput1:2981 +--- re: (a+|b){0,1} +--- s eval: "AB" +--- flags: i + + + +=== TEST 45: testinput1:2984 +--- re: (a+|b){0,1}? +--- s eval: "AB" +--- flags: i + + + +=== TEST 46: testinput1:2987 +--- re: [^ab]* +--- s eval: "CDE" +--- flags: i + + + +=== TEST 47: testinput1:2995 +--- re: ([abc])*d +--- s eval: "ABBBCD" +--- flags: i + + + +=== TEST 48: testinput1:2998 +--- re: ([abc])*bcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 49: testinput1:3001 +--- re: a|b|c|d|e +--- s eval: "E" +--- flags: i + + + +=== TEST 50: testinput1:3004 +--- re: (a|b|c|d|e)f +--- s eval: "EF" +--- flags: i + + + diff --git a/lib/sregex/t/03-pcre-testinput1-17.t b/lib/sregex/t/03-pcre-testinput1-17.t new file mode 100644 index 0000000..d0d3d11 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-17.t @@ -0,0 +1,346 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:3007 +--- re: abcd*efg +--- s eval: "ABCDEFG" +--- flags: i + + + +=== TEST 2: testinput1:3010 +--- re: ab* +--- s eval: "XABYABBBZ" +--- flags: i + + + +=== TEST 3: testinput1:3011 +--- re: ab* +--- s eval: "XAYABBBZ" +--- flags: i + + + +=== TEST 4: testinput1:3014 +--- re: (ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 5: testinput1:3017 +--- re: [abhgefdc]ij +--- s eval: "HIJ" +--- flags: i + + + +=== TEST 6: testinput1:3020 +--- re: ^(ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 7: testinput1:3023 +--- re: (abc|)ef +--- s eval: "ABCDEF" +--- flags: i + + + +=== TEST 8: testinput1:3026 +--- re: (a|b)c*d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 9: testinput1:3029 +--- re: (ab|ab*)bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 10: testinput1:3032 +--- re: a([bc]*)c* +--- s eval: "ABC" +--- flags: i + + + +=== TEST 11: testinput1:3035 +--- re: a([bc]*)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 12: testinput1:3038 +--- re: a([bc]+)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 13: testinput1:3041 +--- re: a([bc]*)(c+d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 14: testinput1:3044 +--- re: a[bcd]*dcdcde +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 15: testinput1:3049 +--- re: (ab|a)b*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 16: testinput1:3052 +--- re: ((a)(b)c)(d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 17: testinput1:3055 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "ALPHA" +--- flags: i + + + +=== TEST 18: testinput1:3058 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "ABH" +--- flags: i + + + +=== TEST 19: testinput1:3061 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFGZ" +--- flags: i + + + +=== TEST 20: testinput1:3062 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "IJ" +--- flags: i + + + +=== TEST 21: testinput1:3063 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "REFFGZ" +--- flags: i + + + +=== TEST 22: testinput1:3064 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 23: testinput1:3065 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 24: testinput1:3066 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFG" +--- flags: i + + + +=== TEST 25: testinput1:3067 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "BCDD" +--- flags: i + + + +=== TEST 26: testinput1:3070 +--- re: ((((((((((a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 27: testinput1:3076 +--- re: (((((((((a))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 28: testinput1:3079 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 29: testinput1:3082 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c)))))))))) +--- s eval: "C" +--- flags: i + + + +=== TEST 30: testinput1:3085 +--- re: multiple words of text +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 31: testinput1:3086 +--- re: multiple words of text +--- s eval: "AA" +--- flags: i + + + +=== TEST 32: testinput1:3087 +--- re: multiple words of text +--- s eval: "UH-UH" +--- flags: i + + + +=== TEST 33: testinput1:3090 +--- re: multiple words +--- s eval: "MULTIPLE WORDS, YEAH" +--- flags: i + + + +=== TEST 34: testinput1:3093 +--- re: (.*)c(.*) +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 35: testinput1:3096 +--- re: \((.*), (.*)\) +--- s eval: "(A, B)" +--- flags: i + + + +=== TEST 36: testinput1:3101 +--- re: abcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 37: testinput1:3104 +--- re: a(bc)d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 38: testinput1:3107 +--- re: a[-]?c +--- s eval: "AC" +--- flags: i + + + +=== TEST 39: testinput1:3125 +--- re: a(?:b|c|d)(.) +--- s eval: "ace" + + + +=== TEST 40: testinput1:3128 +--- re: a(?:b|c|d)*(.) +--- s eval: "ace" + + + +=== TEST 41: testinput1:3131 +--- re: a(?:b|c|d)+?(.) +--- s eval: "ace" + + + +=== TEST 42: testinput1:3132 +--- re: a(?:b|c|d)+?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 43: testinput1:3135 +--- re: a(?:b|c|d)+(.) +--- s eval: "acdbcdbe" + + + +=== TEST 44: testinput1:3138 +--- re: a(?:b|c|d){2}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 45: testinput1:3141 +--- re: a(?:b|c|d){4,5}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 46: testinput1:3144 +--- re: a(?:b|c|d){4,5}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 47: testinput1:3147 +--- re: ((foo)|(bar))* +--- s eval: "foobar" + + + +=== TEST 48: testinput1:3150 +--- re: a(?:b|c|d){6,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 49: testinput1:3153 +--- re: a(?:b|c|d){6,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 50: testinput1:3156 +--- re: a(?:b|c|d){5,6}(.) +--- s eval: "acdbcdbe" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-18.t b/lib/sregex/t/03-pcre-testinput1-18.t new file mode 100644 index 0000000..8481b11 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-18.t @@ -0,0 +1,308 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:3159 +--- re: a(?:b|c|d){5,6}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 2: testinput1:3162 +--- re: a(?:b|c|d){5,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 3: testinput1:3165 +--- re: a(?:b|c|d){5,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 4: testinput1:3168 +--- re: a(?:b|(c|e){1,2}?|d)+?(.) +--- s eval: "ace" + + + +=== TEST 5: testinput1:3171 +--- re: ^(.+)?B +--- s eval: "AB" + + + +=== TEST 6: testinput1:3174 +--- re: ^([^a-z])|(\^)$ +--- s eval: "." + + + +=== TEST 7: testinput1:3177 +--- re: ^[<>]& +--- s eval: "<&OUT" + + + +=== TEST 8: testinput1:3193 +--- re: (?:(f)(o)(o)|(b)(a)(r))* +--- s eval: "foobar" + + + +=== TEST 9: testinput1:3207 +--- re: (?:..)*a +--- s eval: "aba" + + + +=== TEST 10: testinput1:3210 +--- re: (?:..)*?a +--- s eval: "aba" + + + +=== TEST 11: testinput1:3216 +--- re: ^(){3,5} +--- s eval: "abc" + + + +=== TEST 12: testinput1:3219 +--- re: ^(a+)*ax +--- s eval: "aax" + + + +=== TEST 13: testinput1:3222 +--- re: ^((a|b)+)*ax +--- s eval: "aax" + + + +=== TEST 14: testinput1:3225 +--- re: ^((a|bc)+)*ax +--- s eval: "aax" + + + +=== TEST 15: testinput1:3228 +--- re: (a|x)*ab +--- s eval: "cab" + + + +=== TEST 16: testinput1:3231 +--- re: (a)*ab +--- s eval: "cab" + + + +=== TEST 17: testinput1:3344 +--- re: (?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b))) +--- s eval: "cabbbb" + + + +=== TEST 18: testinput1:3347 +--- re: (?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb))) +--- s eval: "caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + + + +=== TEST 19: testinput1:3354 +--- re: foo\w*\d{4}baz +--- s eval: "foobar1234baz" + + + +=== TEST 20: testinput1:3357 +--- re: x(~~)*(?:(?:F)?)? +--- s eval: "x~~" + + + +=== TEST 21: testinput1:3382 +--- re: ^(?:a?b?)*$ +--- s eval: "" + + + +=== TEST 22: testinput1:3383 +--- re: ^(?:a?b?)*$ +--- s eval: "a" + + + +=== TEST 23: testinput1:3384 +--- re: ^(?:a?b?)*$ +--- s eval: "ab" + + + +=== TEST 24: testinput1:3385 +--- re: ^(?:a?b?)*$ +--- s eval: "aaa " + + + +=== TEST 25: testinput1:3386 +--- re: ^(?:a?b?)*$ +--- s eval: "*** Failers" + + + +=== TEST 26: testinput1:3387 +--- re: ^(?:a?b?)*$ +--- s eval: "dbcb" + + + +=== TEST 27: testinput1:3388 +--- re: ^(?:a?b?)*$ +--- s eval: "a--" + + + +=== TEST 28: testinput1:3389 +--- re: ^(?:a?b?)*$ +--- s eval: "aa-- " + + + +=== TEST 29: testinput1:3420 +--- re: ()^b +--- s eval: "*** Failers" + + + +=== TEST 30: testinput1:3421 +--- re: ()^b +--- s eval: "a\nb\nc\n" + + + +=== TEST 31: testinput1:3477 +--- re: (\w+:)+ +--- s eval: "one:" + + + +=== TEST 32: testinput1:3491 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd" + + + +=== TEST 33: testinput1:3492 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "xy:z:::abcd" + + + +=== TEST 34: testinput1:3495 +--- re: ^[^bcd]*(c+) +--- s eval: "aexycd" + + + +=== TEST 35: testinput1:3498 +--- re: (a*)b+ +--- s eval: "caab" + + + +=== TEST 36: testinput1:3503 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "*** Failers" + + + +=== TEST 37: testinput1:3504 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd:" + + + +=== TEST 38: testinput1:3516 +--- re: ([[:]+) +--- s eval: "a:[b]:" + + + +=== TEST 39: testinput1:3519 +--- re: ([[=]+) +--- s eval: "a=[b]=" + + + +=== TEST 40: testinput1:3522 +--- re: ([[.]+) +--- s eval: "a.[b]." + + + +=== TEST 41: testinput1:3547 +--- re: b\z +--- s eval: "a\nb" + + + +=== TEST 42: testinput1:3548 +--- re: b\z +--- s eval: "*** Failers" + + + +=== TEST 43: testinput1:3640 +--- re: ((Z)+|A)* +--- s eval: "ZABCDEFG" + + + +=== TEST 44: testinput1:3643 +--- re: (Z()|A)* +--- s eval: "ZABCDEFG" + + + +=== TEST 45: testinput1:3646 +--- re: (Z(())|A)* +--- s eval: "ZABCDEFG" + + + +=== TEST 46: testinput1:3655 +--- re: a* +--- s eval: "abbab" + + + +=== TEST 47: testinput1:3658 +--- re: ^[a-\d] +--- s eval: "abcde" + + + +=== TEST 48: testinput1:3659 +--- re: ^[a-\d] +--- s eval: "-things" + + + +=== TEST 49: testinput1:3660 +--- re: ^[a-\d] +--- s eval: "0digit" + + + +=== TEST 50: testinput1:3661 +--- re: ^[a-\d] +--- s eval: "*** Failers" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-19.t b/lib/sregex/t/03-pcre-testinput1-19.t new file mode 100644 index 0000000..ab54f0b --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-19.t @@ -0,0 +1,312 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:3662 +--- re: ^[a-\d] +--- s eval: "bcdef " + + + +=== TEST 2: testinput1:3665 +--- re: ^[\d-a] +--- s eval: "abcde" + + + +=== TEST 3: testinput1:3666 +--- re: ^[\d-a] +--- s eval: "-things" + + + +=== TEST 4: testinput1:3667 +--- re: ^[\d-a] +--- s eval: "0digit" + + + +=== TEST 5: testinput1:3668 +--- re: ^[\d-a] +--- s eval: "*** Failers" + + + +=== TEST 6: testinput1:3669 +--- re: ^[\d-a] +--- s eval: "bcdef " + + + +=== TEST 7: testinput1:3678 +--- re: [\s]+ +--- s eval: "> \x09\x0a\x0c\x0d\x0b<" +--- cap: (1, 6) + + + +=== TEST 8: testinput1:3681 +--- re: \s+ +--- s eval: "> \x09\x0a\x0c\x0d\x0b<" +--- cap: (1, 6) + + + +=== TEST 9: testinput1:3684 +--- re: a b +--- s eval: "ab" + + + +=== TEST 10: testinput1:3739 +--- re: abc. +--- s eval: "abc1abc2xyzabc3 " + + + +=== TEST 11: testinput1:3819 +--- re: \M +--- s eval: "M " + + + +=== TEST 12: testinput1:3822 +--- re: (a+)*b +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " + + + +=== TEST 13: testinput1:3831 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 14: testinput1:3832 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 15: testinput1:3833 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 16: testinput1:3834 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 17: testinput1:3863 +--- re: ^ +--- s eval: "a\nb\nc\n" + + + +=== TEST 18: testinput1:3864 +--- re: ^ +--- s eval: "\ " + + + +=== TEST 19: testinput1:3880 +--- re: [[,abc,]+] +--- s eval: "abc]" + + + +=== TEST 20: testinput1:3881 +--- re: [[,abc,]+] +--- s eval: "a,b]" + + + +=== TEST 21: testinput1:3882 +--- re: [[,abc,]+] +--- s eval: "[a,b,c] " + + + +=== TEST 22: testinput1:3899 +--- re: a*b*\w +--- s eval: "aaabbbb" + + + +=== TEST 23: testinput1:3900 +--- re: a*b*\w +--- s eval: "aaaa" + + + +=== TEST 24: testinput1:3901 +--- re: a*b*\w +--- s eval: "a" + + + +=== TEST 25: testinput1:3904 +--- re: a*b?\w +--- s eval: "aaabbbb" + + + +=== TEST 26: testinput1:3905 +--- re: a*b?\w +--- s eval: "aaaa" + + + +=== TEST 27: testinput1:3906 +--- re: a*b?\w +--- s eval: "a" + + + +=== TEST 28: testinput1:3909 +--- re: a*b{0,4}\w +--- s eval: "aaabbbb" + + + +=== TEST 29: testinput1:3910 +--- re: a*b{0,4}\w +--- s eval: "aaaa" + + + +=== TEST 30: testinput1:3911 +--- re: a*b{0,4}\w +--- s eval: "a" + + + +=== TEST 31: testinput1:3914 +--- re: a*b{0,}\w +--- s eval: "aaabbbb" + + + +=== TEST 32: testinput1:3915 +--- re: a*b{0,}\w +--- s eval: "aaaa" + + + +=== TEST 33: testinput1:3916 +--- re: a*b{0,}\w +--- s eval: "a" + + + +=== TEST 34: testinput1:3919 +--- re: a*\d*\w +--- s eval: "0a" + + + +=== TEST 35: testinput1:3920 +--- re: a*\d*\w +--- s eval: "a " + + + +=== TEST 36: testinput1:3923 +--- re: a*b *\w +--- s eval: "a " + + + +=== TEST 37: testinput1:3930 +--- re: a* b *\w +--- s eval: "a " + + + +=== TEST 38: testinput1:3933 +--- re: ^\w+=.*(\\\n.*)* +--- s eval: "abc=xyz\\\npqr" + + + +=== TEST 39: testinput1:3976 +--- re: ^(a()*)* +--- s eval: "aaaa" + + + +=== TEST 40: testinput1:3979 +--- re: ^(?:a(?:(?:))*)* +--- s eval: "aaaa" + + + +=== TEST 41: testinput1:3982 +--- re: ^(a()+)+ +--- s eval: "aaaa" + + + +=== TEST 42: testinput1:3985 +--- re: ^(?:a(?:(?:))+)+ +--- s eval: "aaaa" + + + +=== TEST 43: testinput1:3993 +--- re: (a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 44: testinput1:3994 +--- re: (a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4" +--- cap: (0, 61) (59, 60) + + + +=== TEST 45: testinput1:4001 +--- re: (?:a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 46: testinput1:4002 +--- re: (?:a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4" + + + +=== TEST 47: testinput1:4020 +--- re: (.*(.)?)* +--- s eval: "abcd" +--- cap: (0, 4) (0, 4) + + + +=== TEST 48: testinput1:4032 +--- re: [[:abcd:xyz]] +--- s eval: "a]" + + + +=== TEST 49: testinput1:4033 +--- re: [[:abcd:xyz]] +--- s eval: ":] " + + + +=== TEST 50: testinput1:4036 +--- re: [abc[:x\]pqr] +--- s eval: "a" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-20.t b/lib/sregex/t/03-pcre-testinput1-20.t new file mode 100644 index 0000000..0ae6c60 --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-20.t @@ -0,0 +1,326 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:4037 +--- re: [abc[:x\]pqr] +--- s eval: "[" + + + +=== TEST 2: testinput1:4038 +--- re: [abc[:x\]pqr] +--- s eval: ":" + + + +=== TEST 3: testinput1:4039 +--- re: [abc[:x\]pqr] +--- s eval: "]" + + + +=== TEST 4: testinput1:4040 +--- re: [abc[:x\]pqr] +--- s eval: "p " + + + +=== TEST 5: testinput1:4043 +--- re: .*[op][xyz] +--- s eval: "fooabcfoo" + + + +=== TEST 6: testinput1:4078 +--- re: [\x00-\xff\s]+ +--- s eval: "\x0a\x0b\x0c\x0d" + + + +=== TEST 7: testinput1:4090 +--- re: [^a]* +--- s eval: "12abc" +--- flags: i + + + +=== TEST 8: testinput1:4091 +--- re: [^a]* +--- s eval: "12ABC" +--- flags: i + + + +=== TEST 9: testinput1:4098 +--- re: [^a]*?X +--- s eval: "** Failers" +--- flags: i + + + +=== TEST 10: testinput1:4099 +--- re: [^a]*?X +--- s eval: "12abc" +--- flags: i + + + +=== TEST 11: testinput1:4100 +--- re: [^a]*?X +--- s eval: "12ABC" +--- flags: i + + + +=== TEST 12: testinput1:4103 +--- re: [^a]+?X +--- s eval: "** Failers" +--- flags: i + + + +=== TEST 13: testinput1:4104 +--- re: [^a]+?X +--- s eval: "12abc" +--- flags: i + + + +=== TEST 14: testinput1:4105 +--- re: [^a]+?X +--- s eval: "12ABC" +--- flags: i + + + +=== TEST 15: testinput1:4108 +--- re: [^a]?X +--- s eval: "12aXbcX" +--- flags: i + + + +=== TEST 16: testinput1:4109 +--- re: [^a]?X +--- s eval: "12AXBCX" +--- flags: i + + + +=== TEST 17: testinput1:4110 +--- re: [^a]?X +--- s eval: "BCX " +--- flags: i + + + +=== TEST 18: testinput1:4113 +--- re: [^a]??X +--- s eval: "12aXbcX" +--- flags: i + + + +=== TEST 19: testinput1:4114 +--- re: [^a]??X +--- s eval: "12AXBCX" +--- flags: i + + + +=== TEST 20: testinput1:4115 +--- re: [^a]??X +--- s eval: "BCX" +--- flags: i + + + +=== TEST 21: testinput1:4123 +--- re: [^a]{2,3} +--- s eval: "abcdef" +--- flags: i + + + +=== TEST 22: testinput1:4124 +--- re: [^a]{2,3} +--- s eval: "ABCDEF " +--- flags: i + + + +=== TEST 23: testinput1:4127 +--- re: [^a]{2,3}? +--- s eval: "abcdef" +--- flags: i + + + +=== TEST 24: testinput1:4128 +--- re: [^a]{2,3}? +--- s eval: "ABCDEF " +--- flags: i + + + +=== TEST 25: testinput1:4135 +--- re: ((a|)+)+Z +--- s eval: "Z" + + + +=== TEST 26: testinput1:4138 +--- re: (a)b|(a)c +--- s eval: "ac" + + + +=== TEST 27: testinput1:4177 +--- re: (?:a+|ab)+c +--- s eval: "aabc" + + + +=== TEST 28: testinput1:4192 +--- re: ^(?:a|ab)+c +--- s eval: "aaaabc" + + + +=== TEST 29: testinput1:4253 +--- re: [:a]xxx[b:] +--- s eval: ":xxx:" + + + +=== TEST 30: testinput1:4323 +--- re: \H\h\V\v +--- s eval: "X X\x0a" + + + +=== TEST 31: testinput1:4324 +--- re: \H\h\V\v +--- s eval: "X\x09X\x0b" + + + +=== TEST 32: testinput1:4325 +--- re: \H\h\V\v +--- s eval: "** Failers" + + + +=== TEST 33: testinput1:4326 +--- re: \H\h\V\v +--- s eval: "\xa0 X\x0a " + + + +=== TEST 34: testinput1:4329 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0X\x0a\x0b\x0c\x0d\x0a" + + + +=== TEST 35: testinput1:4330 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0\x0a\x0b\x0c\x0d\x0a" + + + +=== TEST 36: testinput1:4331 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0\x0a\x0b\x0c" + + + +=== TEST 37: testinput1:4332 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "** Failers " + + + +=== TEST 38: testinput1:4333 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0\x0a\x0b" + + + +=== TEST 39: testinput1:4336 +--- re: \H{3,4} +--- s eval: "XY ABCDE" + + + +=== TEST 40: testinput1:4337 +--- re: \H{3,4} +--- s eval: "XY PQR ST " + + + +=== TEST 41: testinput1:4340 +--- re: .\h{3,4}. +--- s eval: "XY AB PQRS" + + + +=== TEST 42: testinput1:4343 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: ">XNNNYZ" + + + +=== TEST 43: testinput1:4344 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: "> X NYQZ" + + + +=== TEST 44: testinput1:4345 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: "** Failers" + + + +=== TEST 45: testinput1:4346 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: ">XYZ " + + + +=== TEST 46: testinput1:4347 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: "> X NY Z" + + + +=== TEST 47: testinput1:4350 +--- re: \v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c +--- s eval: ">XY\x0aZ\x0aA\x0bNN\x0c" + + + +=== TEST 48: testinput1:4351 +--- re: \v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c +--- s eval: ">\x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c" + + + +=== TEST 49: testinput1:4906 +--- re: \A.*?(?:a|bc) +--- s eval: "ba" + + + +=== TEST 50: testinput1:4912 +--- re: \A.*?(a|bc) +--- s eval: "ba" + + + diff --git a/lib/sregex/t/03-pcre-testinput1-21.t b/lib/sregex/t/03-pcre-testinput1-21.t new file mode 100644 index 0000000..238c4ba --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1-21.t @@ -0,0 +1,25 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:4930 +--- re: \A.*?(?:a|bc|d) +--- s eval: "ba" + + + +=== TEST 2: testinput1:4954 +--- re: ^\N+ +--- s eval: "abc\ndef" + + + +=== TEST 3: testinput1:5260 +--- re: ((?:a?)*)*c +--- s eval: "aac " +--- cap: (0, 3) (0, 2) + diff --git a/lib/sregex/t/03-pcre-testinput1.t_ b/lib/sregex/t/03-pcre-testinput1.t_ new file mode 100644 index 0000000..903c2df --- /dev/null +++ b/lib/sregex/t/03-pcre-testinput1.t_ @@ -0,0 +1,6224 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: testinput1:6 +--- re: the quick brown fox +--- s eval: "the quick brown fox" + + + +=== TEST 2: testinput1:7 +--- re: the quick brown fox +--- s eval: "The quick brown FOX" + + + +=== TEST 3: testinput1:8 +--- re: the quick brown fox +--- s eval: "What do you know about the quick brown fox?" + + + +=== TEST 4: testinput1:9 +--- re: the quick brown fox +--- s eval: "What do you know about THE QUICK BROWN FOX?" + + + +=== TEST 5: testinput1:12 +--- re: The quick brown fox +--- s eval: "the quick brown fox" +--- flags: i + + + +=== TEST 6: testinput1:13 +--- re: The quick brown fox +--- s eval: "The quick brown FOX" +--- flags: i + + + +=== TEST 7: testinput1:14 +--- re: The quick brown fox +--- s eval: "What do you know about the quick brown fox?" +--- flags: i + + + +=== TEST 8: testinput1:15 +--- re: The quick brown fox +--- s eval: "What do you know about THE QUICK BROWN FOX?" +--- flags: i + + + +=== TEST 9: testinput1:18 +--- re: abcd\t\n\r\f\a\e\071\x3b\$\\\?caxyz +--- s eval: "abcd\t\n\r\f\a\e9;\$\\?caxyz" + + + +=== TEST 10: testinput1:21 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 11: testinput1:23 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 12: testinput1:24 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 13: testinput1:25 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 14: testinput1:26 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 15: testinput1:27 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 16: testinput1:28 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypAzz" + + + +=== TEST 17: testinput1:29 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 18: testinput1:30 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqAzz" + + + +=== TEST 19: testinput1:31 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqAzz" + + + +=== TEST 20: testinput1:32 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqAzz" + + + +=== TEST 21: testinput1:33 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqqAzz" + + + +=== TEST 22: testinput1:34 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqqqAzz" + + + +=== TEST 23: testinput1:35 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 24: testinput1:36 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzzpqrrrabbxyyyypqAzz" + + + +=== TEST 25: testinput1:37 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabxyzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 26: testinput1:38 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 27: testinput1:39 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 28: testinput1:40 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abcxyzzpqrrrabbxyyyypqAzz" + + + +=== TEST 29: testinput1:41 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aabcxyzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 30: testinput1:42 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 31: testinput1:43 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbxyyyypqAzz" + + + +=== TEST 32: testinput1:44 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyyypqAzz" + + + +=== TEST 33: testinput1:45 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyyyypqAzz" + + + +=== TEST 34: testinput1:46 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypABzz" + + + +=== TEST 35: testinput1:47 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypABBzz" + + + +=== TEST 36: testinput1:48 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: ">>>aaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 37: testinput1:49 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: ">aaaabxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 38: testinput1:50 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: ">>>>abcxyzpqrrrabbxyyyypqAzz" + + + +=== TEST 39: testinput1:51 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "*** Failers" + + + +=== TEST 40: testinput1:52 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrabbxyyyypqAzz" + + + +=== TEST 41: testinput1:53 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrrrabbxyyyypqAzz" + + + +=== TEST 42: testinput1:54 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "abxyzpqrrrabxyyyypqAzz" + + + +=== TEST 43: testinput1:55 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyyyyypqAzz" + + + +=== TEST 44: testinput1:56 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaaabcxyzzzzpqrrrabbbxyyypqAzz" + + + +=== TEST 45: testinput1:57 +--- re: a*abc?xyz+pqr{3}ab{2,}xy{4,5}pq{0,6}AB{0,}zz +--- s eval: "aaabcxyzpqrrrabbxyyyypqqqqqqqAzz" + + + +=== TEST 46: testinput1:60 +--- re: ^(abc){1,2}zz +--- s eval: "abczz" + + + +=== TEST 47: testinput1:61 +--- re: ^(abc){1,2}zz +--- s eval: "abcabczz" + + + +=== TEST 48: testinput1:62 +--- re: ^(abc){1,2}zz +--- s eval: "*** Failers" + + + +=== TEST 49: testinput1:63 +--- re: ^(abc){1,2}zz +--- s eval: "zz" + + + +=== TEST 50: testinput1:64 +--- re: ^(abc){1,2}zz +--- s eval: "abcabcabczz" + + + +=== TEST 51: testinput1:65 +--- re: ^(abc){1,2}zz +--- s eval: ">>abczz" + + + +=== TEST 52: testinput1:68 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bc" + + + +=== TEST 53: testinput1:69 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbc" + + + +=== TEST 54: testinput1:70 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbc" + + + +=== TEST 55: testinput1:71 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bac" + + + +=== TEST 56: testinput1:72 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbac" + + + +=== TEST 57: testinput1:73 +--- re: ^(b+?|a){1,2}?c +--- s eval: "aac" + + + +=== TEST 58: testinput1:74 +--- re: ^(b+?|a){1,2}?c +--- s eval: "abbbbbbbbbbbc" + + + +=== TEST 59: testinput1:75 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbbbbbbbbbac" + + + +=== TEST 60: testinput1:76 +--- re: ^(b+?|a){1,2}?c +--- s eval: "*** Failers" + + + +=== TEST 61: testinput1:77 +--- re: ^(b+?|a){1,2}?c +--- s eval: "aaac" + + + +=== TEST 62: testinput1:78 +--- re: ^(b+?|a){1,2}?c +--- s eval: "abbbbbbbbbbbac" + + + +=== TEST 63: testinput1:81 +--- re: ^(b+|a){1,2}c +--- s eval: "bc" + + + +=== TEST 64: testinput1:82 +--- re: ^(b+|a){1,2}c +--- s eval: "bbc" + + + +=== TEST 65: testinput1:83 +--- re: ^(b+|a){1,2}c +--- s eval: "bbbc" + + + +=== TEST 66: testinput1:84 +--- re: ^(b+|a){1,2}c +--- s eval: "bac" + + + +=== TEST 67: testinput1:85 +--- re: ^(b+|a){1,2}c +--- s eval: "bbac" + + + +=== TEST 68: testinput1:86 +--- re: ^(b+|a){1,2}c +--- s eval: "aac" + + + +=== TEST 69: testinput1:87 +--- re: ^(b+|a){1,2}c +--- s eval: "abbbbbbbbbbbc" + + + +=== TEST 70: testinput1:88 +--- re: ^(b+|a){1,2}c +--- s eval: "bbbbbbbbbbbac" + + + +=== TEST 71: testinput1:89 +--- re: ^(b+|a){1,2}c +--- s eval: "*** Failers" + + + +=== TEST 72: testinput1:90 +--- re: ^(b+|a){1,2}c +--- s eval: "aaac" + + + +=== TEST 73: testinput1:91 +--- re: ^(b+|a){1,2}c +--- s eval: "abbbbbbbbbbbac" + + + +=== TEST 74: testinput1:94 +--- re: ^(b+|a){1,2}?bc +--- s eval: "bbc" + + + +=== TEST 75: testinput1:97 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "babc" + + + +=== TEST 76: testinput1:98 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "bbabc" + + + +=== TEST 77: testinput1:99 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "bababc" + + + +=== TEST 78: testinput1:100 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "*** Failers" + + + +=== TEST 79: testinput1:101 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "bababbc" + + + +=== TEST 80: testinput1:102 +--- re: ^(b*|ba){1,2}?bc +--- s eval: "babababc" + + + +=== TEST 81: testinput1:105 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "babc" + + + +=== TEST 82: testinput1:106 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "bbabc" + + + +=== TEST 83: testinput1:107 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "bababc" + + + +=== TEST 84: testinput1:108 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "*** Failers" + + + +=== TEST 85: testinput1:109 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "bababbc" + + + +=== TEST 86: testinput1:110 +--- re: ^(ba|b*){1,2}?bc +--- s eval: "babababc" + + + +=== TEST 87: testinput1:113 +--- re: ^\ca\cA\c[\c{\c: +--- s eval: "\x01\x01\e;z" +--- err +[error] syntax error +--- SKIP + + + +=== TEST 88: testinput1:116 +--- re: ^[ab\]cde] +--- s eval: "athing" + + + +=== TEST 89: testinput1:117 +--- re: ^[ab\]cde] +--- s eval: "bthing" + + + +=== TEST 90: testinput1:118 +--- re: ^[ab\]cde] +--- s eval: "]thing" + + + +=== TEST 91: testinput1:119 +--- re: ^[ab\]cde] +--- s eval: "cthing" + + + +=== TEST 92: testinput1:120 +--- re: ^[ab\]cde] +--- s eval: "dthing" + + + +=== TEST 93: testinput1:121 +--- re: ^[ab\]cde] +--- s eval: "ething" + + + +=== TEST 94: testinput1:122 +--- re: ^[ab\]cde] +--- s eval: "*** Failers" + + + +=== TEST 95: testinput1:123 +--- re: ^[ab\]cde] +--- s eval: "fthing" + + + +=== TEST 96: testinput1:124 +--- re: ^[ab\]cde] +--- s eval: "[thing" + + + +=== TEST 97: testinput1:125 +--- re: ^[ab\]cde] +--- s eval: "\\thing" + + + +=== TEST 98: testinput1:128 +--- re: ^[]cde] +--- s eval: "]thing" + + + +=== TEST 99: testinput1:129 +--- re: ^[]cde] +--- s eval: "cthing" + + + +=== TEST 100: testinput1:130 +--- re: ^[]cde] +--- s eval: "dthing" + + + +=== TEST 101: testinput1:131 +--- re: ^[]cde] +--- s eval: "ething" + + + +=== TEST 102: testinput1:132 +--- re: ^[]cde] +--- s eval: "*** Failers" + + + +=== TEST 103: testinput1:133 +--- re: ^[]cde] +--- s eval: "athing" + + + +=== TEST 104: testinput1:134 +--- re: ^[]cde] +--- s eval: "fthing" + + + +=== TEST 105: testinput1:137 +--- re: ^[^ab\]cde] +--- s eval: "fthing" + + + +=== TEST 106: testinput1:138 +--- re: ^[^ab\]cde] +--- s eval: "[thing" + + + +=== TEST 107: testinput1:139 +--- re: ^[^ab\]cde] +--- s eval: "\\thing" + + + +=== TEST 108: testinput1:140 +--- re: ^[^ab\]cde] +--- s eval: "*** Failers" + + + +=== TEST 109: testinput1:141 +--- re: ^[^ab\]cde] +--- s eval: "athing" + + + +=== TEST 110: testinput1:142 +--- re: ^[^ab\]cde] +--- s eval: "bthing" + + + +=== TEST 111: testinput1:143 +--- re: ^[^ab\]cde] +--- s eval: "]thing" + + + +=== TEST 112: testinput1:144 +--- re: ^[^ab\]cde] +--- s eval: "cthing" + + + +=== TEST 113: testinput1:145 +--- re: ^[^ab\]cde] +--- s eval: "dthing" + + + +=== TEST 114: testinput1:146 +--- re: ^[^ab\]cde] +--- s eval: "ething" + + + +=== TEST 115: testinput1:149 +--- re: ^[^]cde] +--- s eval: "athing" + + + +=== TEST 116: testinput1:150 +--- re: ^[^]cde] +--- s eval: "fthing" + + + +=== TEST 117: testinput1:151 +--- re: ^[^]cde] +--- s eval: "*** Failers" + + + +=== TEST 118: testinput1:152 +--- re: ^[^]cde] +--- s eval: "]thing" + + + +=== TEST 119: testinput1:153 +--- re: ^[^]cde] +--- s eval: "cthing" + + + +=== TEST 120: testinput1:154 +--- re: ^[^]cde] +--- s eval: "dthing" + + + +=== TEST 121: testinput1:155 +--- re: ^[^]cde] +--- s eval: "ething" + + + +=== TEST 122: testinput1:158 +--- re: ^\ +--- s eval: "" + + + +=== TEST 123: testinput1:161 +--- re: ^ +--- s eval: "" + + + +=== TEST 124: testinput1:164 +--- re: ^[0-9]+$ +--- s eval: "0" + + + +=== TEST 125: testinput1:165 +--- re: ^[0-9]+$ +--- s eval: "1" + + + +=== TEST 126: testinput1:166 +--- re: ^[0-9]+$ +--- s eval: "2" + + + +=== TEST 127: testinput1:167 +--- re: ^[0-9]+$ +--- s eval: "3" + + + +=== TEST 128: testinput1:168 +--- re: ^[0-9]+$ +--- s eval: "4" + + + +=== TEST 129: testinput1:169 +--- re: ^[0-9]+$ +--- s eval: "5" + + + +=== TEST 130: testinput1:170 +--- re: ^[0-9]+$ +--- s eval: "6" + + + +=== TEST 131: testinput1:171 +--- re: ^[0-9]+$ +--- s eval: "7" + + + +=== TEST 132: testinput1:172 +--- re: ^[0-9]+$ +--- s eval: "8" + + + +=== TEST 133: testinput1:173 +--- re: ^[0-9]+$ +--- s eval: "9" + + + +=== TEST 134: testinput1:174 +--- re: ^[0-9]+$ +--- s eval: "10" + + + +=== TEST 135: testinput1:175 +--- re: ^[0-9]+$ +--- s eval: "100" + + + +=== TEST 136: testinput1:176 +--- re: ^[0-9]+$ +--- s eval: "*** Failers" + + + +=== TEST 137: testinput1:177 +--- re: ^[0-9]+$ +--- s eval: "abc" + + + +=== TEST 138: testinput1:180 +--- re: ^.*nter +--- s eval: "enter" + + + +=== TEST 139: testinput1:181 +--- re: ^.*nter +--- s eval: "inter" + + + +=== TEST 140: testinput1:182 +--- re: ^.*nter +--- s eval: "uponter" + + + +=== TEST 141: testinput1:185 +--- re: ^xxx[0-9]+$ +--- s eval: "xxx0" + + + +=== TEST 142: testinput1:186 +--- re: ^xxx[0-9]+$ +--- s eval: "xxx1234" + + + +=== TEST 143: testinput1:187 +--- re: ^xxx[0-9]+$ +--- s eval: "*** Failers" + + + +=== TEST 144: testinput1:188 +--- re: ^xxx[0-9]+$ +--- s eval: "xxx" + + + +=== TEST 145: testinput1:191 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "x123" + + + +=== TEST 146: testinput1:192 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "xx123" + + + +=== TEST 147: testinput1:193 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "123456" + + + +=== TEST 148: testinput1:194 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "*** Failers" + + + +=== TEST 149: testinput1:195 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "123" + + + +=== TEST 150: testinput1:196 +--- re: ^.+[0-9][0-9][0-9]$ +--- s eval: "x1234" + + + +=== TEST 151: testinput1:199 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "x123" + + + +=== TEST 152: testinput1:200 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "xx123" + + + +=== TEST 153: testinput1:201 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "123456" + + + +=== TEST 154: testinput1:202 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "*** Failers" + + + +=== TEST 155: testinput1:203 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "123" + + + +=== TEST 156: testinput1:204 +--- re: ^.+?[0-9][0-9][0-9]$ +--- s eval: "x1234" + + + +=== TEST 157: testinput1:207 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!pqr=apquxz.ixr.zzz.ac.uk" + + + +=== TEST 158: testinput1:208 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "*** Failers" + + + +=== TEST 159: testinput1:209 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "!pqr=apquxz.ixr.zzz.ac.uk" + + + +=== TEST 160: testinput1:210 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!=apquxz.ixr.zzz.ac.uk" + + + +=== TEST 161: testinput1:211 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!pqr=apquxz:ixr.zzz.ac.uk" + + + +=== TEST 162: testinput1:212 +--- re: ^([^!]+)!(.+)=apquxz\.ixr\.zzz\.ac\.uk$ +--- s eval: "abc!pqr=apquxz.ixr.zzz.ac.ukk" + + + +=== TEST 163: testinput1:215 +--- re: : +--- s eval: "Well, we need a colon: somewhere" + + + +=== TEST 164: testinput1:216 +--- re: : +--- s eval: "*** Fail if we don't" + + + +=== TEST 165: testinput1:219 +--- re: ([\da-f:]+)$ +--- s eval: "0abc" +--- flags: i + + + +=== TEST 166: testinput1:220 +--- re: ([\da-f:]+)$ +--- s eval: "abc" +--- flags: i + + + +=== TEST 167: testinput1:221 +--- re: ([\da-f:]+)$ +--- s eval: "fed" +--- flags: i + + + +=== TEST 168: testinput1:222 +--- re: ([\da-f:]+)$ +--- s eval: "E" +--- flags: i + + + +=== TEST 169: testinput1:223 +--- re: ([\da-f:]+)$ +--- s eval: "::" +--- flags: i + + + +=== TEST 170: testinput1:224 +--- re: ([\da-f:]+)$ +--- s eval: "5f03:12C0::932e" +--- flags: i + + + +=== TEST 171: testinput1:225 +--- re: ([\da-f:]+)$ +--- s eval: "fed def" +--- flags: i + + + +=== TEST 172: testinput1:226 +--- re: ([\da-f:]+)$ +--- s eval: "Any old stuff" +--- flags: i + + + +=== TEST 173: testinput1:227 +--- re: ([\da-f:]+)$ +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 174: testinput1:228 +--- re: ([\da-f:]+)$ +--- s eval: "0zzz" +--- flags: i + + + +=== TEST 175: testinput1:229 +--- re: ([\da-f:]+)$ +--- s eval: "gzzz" +--- flags: i + + + +=== TEST 176: testinput1:230 +--- re: ([\da-f:]+)$ +--- s eval: "fed\x20" +--- flags: i + + + +=== TEST 177: testinput1:231 +--- re: ([\da-f:]+)$ +--- s eval: "Any old rubbish" +--- flags: i + + + +=== TEST 178: testinput1:234 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: ".1.2.3" + + + +=== TEST 179: testinput1:235 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "A.12.123.0" + + + +=== TEST 180: testinput1:236 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "*** Failers" + + + +=== TEST 181: testinput1:237 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: ".1.2.3333" + + + +=== TEST 182: testinput1:238 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "1.2.3" + + + +=== TEST 183: testinput1:239 +--- re: ^.*\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$ +--- s eval: "1234.2.3" + + + +=== TEST 184: testinput1:242 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "1 IN SOA non-sp1 non-sp2(" + + + +=== TEST 185: testinput1:243 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "1 IN SOA non-sp1 non-sp2 (" + + + +=== TEST 186: testinput1:244 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "*** Failers" + + + +=== TEST 187: testinput1:245 +--- re: ^(\d+)\s+IN\s+SOA\s+(\S+)\s+(\S+)\s*\(\s*$ +--- s eval: "1IN SOA non-sp1 non-sp2(" + + + +=== TEST 188: testinput1:248 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "a." + + + +=== TEST 189: testinput1:249 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "Z." + + + +=== TEST 190: testinput1:250 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "2." + + + +=== TEST 191: testinput1:251 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "ab-c.pq-r." + + + +=== TEST 192: testinput1:252 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "sxk.zzz.ac.uk." + + + +=== TEST 193: testinput1:253 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "x-.y-." + + + +=== TEST 194: testinput1:254 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "*** Failers" + + + +=== TEST 195: testinput1:255 +--- re: ^[a-zA-Z\d][a-zA-Z\d\-]*(\.[a-zA-Z\d][a-zA-z\d\-]*)*\.$ +--- s eval: "-abc.peq." + + + +=== TEST 196: testinput1:258 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.a" + + + +=== TEST 197: testinput1:259 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.b0-a" + + + +=== TEST 198: testinput1:260 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.c3-b.c" + + + +=== TEST 199: testinput1:261 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.c-a.b-c" + + + +=== TEST 200: testinput1:262 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*** Failers" + + + +=== TEST 201: testinput1:263 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.0" + + + +=== TEST 202: testinput1:264 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.a-" + + + +=== TEST 203: testinput1:265 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.a-b.c-" + + + +=== TEST 204: testinput1:266 +--- re: ^\*\.[a-z]([a-z\-\d]*[a-z\d]+)?(\.[a-z]([a-z\-\d]*[a-z\d]+)?)*$ +--- s eval: "*.c-a.0-c" + + + +=== TEST 205: testinput1:278 +--- re: ^[\da-f](\.[\da-f])*$ +--- s eval: "a.b.c.d" +--- flags: i + + + +=== TEST 206: testinput1:279 +--- re: ^[\da-f](\.[\da-f])*$ +--- s eval: "A.B.C.D" +--- flags: i + + + +=== TEST 207: testinput1:280 +--- re: ^[\da-f](\.[\da-f])*$ +--- s eval: "a.b.c.1.2.3.C" +--- flags: i + + + +=== TEST 208: testinput1:283 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"1234\"" + + + +=== TEST 209: testinput1:284 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"abcd\" ;" + + + +=== TEST 210: testinput1:285 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"\" ; rhubarb" + + + +=== TEST 211: testinput1:286 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "*** Failers" + + + +=== TEST 212: testinput1:287 +--- re: ^\".*\"\s*(;.*)?$ +--- s eval: "\"1234\" : things" + + + +=== TEST 213: testinput1:290 +--- re: ^$ +--- s eval: "" + + + +=== TEST 214: testinput1:291 +--- re: ^$ +--- s eval: "*** Failers" + + + +=== TEST 215: testinput1:306 +--- re: ^ a\ b[c ]d $ +--- s eval: "a bcd" + + + +=== TEST 216: testinput1:307 +--- re: ^ a\ b[c ]d $ +--- s eval: "a b d" + + + +=== TEST 217: testinput1:308 +--- re: ^ a\ b[c ]d $ +--- s eval: "*** Failers" + + + +=== TEST 218: testinput1:309 +--- re: ^ a\ b[c ]d $ +--- s eval: "abcd" + + + +=== TEST 219: testinput1:310 +--- re: ^ a\ b[c ]d $ +--- s eval: "ab d" + + + +=== TEST 220: testinput1:313 +--- re: ^(a(b(c)))(d(e(f)))(h(i(j)))(k(l(m)))$ +--- s eval: "abcdefhijklm" + + + +=== TEST 221: testinput1:316 +--- re: ^(?:a(b(c)))(?:d(e(f)))(?:h(i(j)))(?:k(l(m)))$ +--- s eval: "abcdefhijklm" + + + +=== TEST 222: testinput1:319 +--- re: ^[\w][\W][\s][\S][\d][\D][\b][\n][\c]][\022] +--- s eval: "a+ Z0+\x08\n\x1d\x12" + + + +=== TEST 223: testinput1:325 +--- re: ^a*\w +--- s eval: "z" + + + +=== TEST 224: testinput1:326 +--- re: ^a*\w +--- s eval: "az" + + + +=== TEST 225: testinput1:327 +--- re: ^a*\w +--- s eval: "aaaz" + + + +=== TEST 226: testinput1:328 +--- re: ^a*\w +--- s eval: "a" + + + +=== TEST 227: testinput1:329 +--- re: ^a*\w +--- s eval: "aa" + + + +=== TEST 228: testinput1:330 +--- re: ^a*\w +--- s eval: "aaaa" + + + +=== TEST 229: testinput1:331 +--- re: ^a*\w +--- s eval: "a+" + + + +=== TEST 230: testinput1:332 +--- re: ^a*\w +--- s eval: "aa+" + + + +=== TEST 231: testinput1:335 +--- re: ^a*?\w +--- s eval: "z" + + + +=== TEST 232: testinput1:336 +--- re: ^a*?\w +--- s eval: "az" + + + +=== TEST 233: testinput1:337 +--- re: ^a*?\w +--- s eval: "aaaz" + + + +=== TEST 234: testinput1:338 +--- re: ^a*?\w +--- s eval: "a" + + + +=== TEST 235: testinput1:339 +--- re: ^a*?\w +--- s eval: "aa" + + + +=== TEST 236: testinput1:340 +--- re: ^a*?\w +--- s eval: "aaaa" + + + +=== TEST 237: testinput1:341 +--- re: ^a*?\w +--- s eval: "a+" + + + +=== TEST 238: testinput1:342 +--- re: ^a*?\w +--- s eval: "aa+" + + + +=== TEST 239: testinput1:345 +--- re: ^a+\w +--- s eval: "az" + + + +=== TEST 240: testinput1:346 +--- re: ^a+\w +--- s eval: "aaaz" + + + +=== TEST 241: testinput1:347 +--- re: ^a+\w +--- s eval: "aa" + + + +=== TEST 242: testinput1:348 +--- re: ^a+\w +--- s eval: "aaaa" + + + +=== TEST 243: testinput1:349 +--- re: ^a+\w +--- s eval: "aa+" + + + +=== TEST 244: testinput1:352 +--- re: ^a+?\w +--- s eval: "az" + + + +=== TEST 245: testinput1:353 +--- re: ^a+?\w +--- s eval: "aaaz" + + + +=== TEST 246: testinput1:354 +--- re: ^a+?\w +--- s eval: "aa" + + + +=== TEST 247: testinput1:355 +--- re: ^a+?\w +--- s eval: "aaaa" + + + +=== TEST 248: testinput1:356 +--- re: ^a+?\w +--- s eval: "aa+" + + + +=== TEST 249: testinput1:359 +--- re: ^\d{8}\w{2,} +--- s eval: "1234567890" + + + +=== TEST 250: testinput1:360 +--- re: ^\d{8}\w{2,} +--- s eval: "12345678ab" + + + +=== TEST 251: testinput1:361 +--- re: ^\d{8}\w{2,} +--- s eval: "12345678__" + + + +=== TEST 252: testinput1:362 +--- re: ^\d{8}\w{2,} +--- s eval: "*** Failers" + + + +=== TEST 253: testinput1:363 +--- re: ^\d{8}\w{2,} +--- s eval: "1234567" + + + +=== TEST 254: testinput1:366 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "uoie" + + + +=== TEST 255: testinput1:367 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "1234" + + + +=== TEST 256: testinput1:368 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "12345" + + + +=== TEST 257: testinput1:369 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "aaaaa" + + + +=== TEST 258: testinput1:370 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "*** Failers" + + + +=== TEST 259: testinput1:371 +--- re: ^[aeiou\d]{4,5}$ +--- s eval: "123456" + + + +=== TEST 260: testinput1:374 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "uoie" + + + +=== TEST 261: testinput1:375 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "1234" + + + +=== TEST 262: testinput1:376 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "12345" + + + +=== TEST 263: testinput1:377 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "aaaaa" + + + +=== TEST 264: testinput1:378 +--- re: ^[aeiou\d]{4,5}? +--- s eval: "123456" + + + +=== TEST 265: testinput1:397 +--- re: ^From +([^ ]+) +[a-zA-Z][a-zA-Z][a-zA-Z] +[a-zA-Z][a-zA-Z][a-zA-Z] +[0-9]?[0-9] +[0-9][0-9]:[0-9][0-9] +--- s eval: "From abcd Mon Sep 01 12:33:02 1997" + + + +=== TEST 266: testinput1:400 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "From abcd Mon Sep 01 12:33:02 1997" + + + +=== TEST 267: testinput1:401 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "From abcd Mon Sep 1 12:33:02 1997" + + + +=== TEST 268: testinput1:402 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "*** Failers" + + + +=== TEST 269: testinput1:403 +--- re: ^From\s+\S+\s+([a-zA-Z]{3}\s+){2}\d{1,2}\s+\d\d:\d\d +--- s eval: "From abcd Sep 01 12:33:02 1997" + + + +=== TEST 270: testinput1:406 +--- re: ^12.34 +--- s eval: "12\n34" + + + +=== TEST 271: testinput1:407 +--- re: ^12.34 +--- s eval: "12\r34" + + + +=== TEST 272: testinput1:439 +--- re: ^abcd#rhubarb +--- s eval: "abcd" + + + +=== TEST 273: testinput1:458 +--- re: ^[ab]{1,3}(ab*|b) +--- s eval: "aabbbbb" + + + +=== TEST 274: testinput1:461 +--- re: ^[ab]{1,3}?(ab*|b) +--- s eval: "aabbbbb" + + + +=== TEST 275: testinput1:464 +--- re: ^[ab]{1,3}?(ab*?|b) +--- s eval: "aabbbbb" + + + +=== TEST 276: testinput1:467 +--- re: ^[ab]{1,3}(ab*?|b) +--- s eval: "aabbbbb" + + + +=== TEST 277: testinput1:1266 +--- re: abc\0def\00pqr\000xyz\0000AB +--- s eval: "abc\0def\00pqr\000xyz\0000AB" + + + +=== TEST 278: testinput1:1267 +--- re: abc\0def\00pqr\000xyz\0000AB +--- s eval: "abc456 abc\0def\00pqr\000xyz\0000ABCDE" + + + +=== TEST 279: testinput1:1270 +--- re: abc\x0def\x00pqr\x000xyz\x0000AB +--- s eval: "abc\x0def\x00pqr\x000xyz\x0000AB" + + + +=== TEST 280: testinput1:1271 +--- re: abc\x0def\x00pqr\x000xyz\x0000AB +--- s eval: "abc456 abc\x0def\x00pqr\x000xyz\x0000ABCDE" + + + +=== TEST 281: testinput1:1274 +--- re: ^[\000-\037] +--- s eval: "\0A" + + + +=== TEST 282: testinput1:1275 +--- re: ^[\000-\037] +--- s eval: "\01B" + + + +=== TEST 283: testinput1:1276 +--- re: ^[\000-\037] +--- s eval: "\037C" + + + +=== TEST 284: testinput1:1279 +--- re: \0* +--- s eval: "\0\0\0\0" + + + +=== TEST 285: testinput1:1282 +--- re: A\x0{2,3}Z +--- s eval: "The A\x{0}\x{0}Z" + + + +=== TEST 286: testinput1:1283 +--- re: A\x0{2,3}Z +--- s eval: "An A\0\x{0}\0Z" + + + +=== TEST 287: testinput1:1284 +--- re: A\x0{2,3}Z +--- s eval: "*** Failers" + + + +=== TEST 288: testinput1:1285 +--- re: A\x0{2,3}Z +--- s eval: "A\0Z" + + + +=== TEST 289: testinput1:1286 +--- re: A\x0{2,3}Z +--- s eval: "A\0\x{0}\0\x{0}Z" + + + +=== TEST 290: testinput1:1295 +--- re: ^\s +--- s eval: "\040abc" + + + +=== TEST 291: testinput1:1296 +--- re: ^\s +--- s eval: "\x0cabc" + + + +=== TEST 292: testinput1:1297 +--- re: ^\s +--- s eval: "\nabc" + + + +=== TEST 293: testinput1:1298 +--- re: ^\s +--- s eval: "\rabc" + + + +=== TEST 294: testinput1:1299 +--- re: ^\s +--- s eval: "\tabc" + + + +=== TEST 295: testinput1:1300 +--- re: ^\s +--- s eval: "*** Failers" + + + +=== TEST 296: testinput1:1301 +--- re: ^\s +--- s eval: "abc" + + + +=== TEST 297: testinput1:1346 +--- re: ab{1,3}bc +--- s eval: "abbbbc" + + + +=== TEST 298: testinput1:1347 +--- re: ab{1,3}bc +--- s eval: "abbbc" + + + +=== TEST 299: testinput1:1348 +--- re: ab{1,3}bc +--- s eval: "abbc" + + + +=== TEST 300: testinput1:1349 +--- re: ab{1,3}bc +--- s eval: "*** Failers" + + + +=== TEST 301: testinput1:1350 +--- re: ab{1,3}bc +--- s eval: "abc" + + + +=== TEST 302: testinput1:1351 +--- re: ab{1,3}bc +--- s eval: "abbbbbc" + + + +=== TEST 303: testinput1:1354 +--- re: ([^.]*)\.([^:]*):[T ]+(.*) +--- s eval: "track1.title:TBlah blah blah" + + + +=== TEST 304: testinput1:1357 +--- re: ([^.]*)\.([^:]*):[T ]+(.*) +--- s eval: "track1.title:TBlah blah blah" +--- flags: i + + + +=== TEST 305: testinput1:1360 +--- re: ([^.]*)\.([^:]*):[t ]+(.*) +--- s eval: "track1.title:TBlah blah blah" +--- flags: i + + + +=== TEST 306: testinput1:1363 +--- re: ^[W-c]+$ +--- s eval: "WXY_^abc" + + + +=== TEST 307: testinput1:1364 +--- re: ^[W-c]+$ +--- s eval: "*** Failers" + + + +=== TEST 308: testinput1:1365 +--- re: ^[W-c]+$ +--- s eval: "wxy" + + + +=== TEST 309: testinput1:1368 +--- re: ^[W-c]+$ +--- s eval: "WXY_^abc" +--- flags: i + + + +=== TEST 310: testinput1:1369 +--- re: ^[W-c]+$ +--- s eval: "wxy_^ABC" +--- flags: i + + + +=== TEST 311: testinput1:1372 +--- re: ^[\x3f-\x5F]+$ +--- s eval: "WXY_^abc" +--- flags: i + + + +=== TEST 312: testinput1:1373 +--- re: ^[\x3f-\x5F]+$ +--- s eval: "wxy_^ABC" +--- flags: i + + + +=== TEST 313: testinput1:1376 +--- re: ^abc$ +--- s eval: "abc" + + + +=== TEST 314: testinput1:1377 +--- re: ^abc$ +--- s eval: "qqq\nabc" + + + +=== TEST 315: testinput1:1378 +--- re: ^abc$ +--- s eval: "abc\nzzz" + + + +=== TEST 316: testinput1:1379 +--- re: ^abc$ +--- s eval: "qqq\nabc\nzzz" + + + +=== TEST 317: testinput1:1383 +--- re: ^abc$ +--- s eval: "*** Failers" + + + +=== TEST 318: testinput1:1404 +--- re: (?:b)|(?::+) +--- s eval: "b::c" + + + +=== TEST 319: testinput1:1405 +--- re: (?:b)|(?::+) +--- s eval: "c::b" + + + +=== TEST 320: testinput1:1408 +--- re: [-az]+ +--- s eval: "az-" + + + +=== TEST 321: testinput1:1409 +--- re: [-az]+ +--- s eval: "*** Failers" + + + +=== TEST 322: testinput1:1410 +--- re: [-az]+ +--- s eval: "b" + + + +=== TEST 323: testinput1:1413 +--- re: [az-]+ +--- s eval: "za-" + + + +=== TEST 324: testinput1:1414 +--- re: [az-]+ +--- s eval: "*** Failers" + + + +=== TEST 325: testinput1:1415 +--- re: [az-]+ +--- s eval: "b" + + + +=== TEST 326: testinput1:1418 +--- re: [a\-z]+ +--- s eval: "a-z" + + + +=== TEST 327: testinput1:1419 +--- re: [a\-z]+ +--- s eval: "*** Failers" + + + +=== TEST 328: testinput1:1420 +--- re: [a\-z]+ +--- s eval: "b" + + + +=== TEST 329: testinput1:1423 +--- re: [a-z]+ +--- s eval: "abcdxyz" + + + +=== TEST 330: testinput1:1426 +--- re: [\d-]+ +--- s eval: "12-34" + + + +=== TEST 331: testinput1:1427 +--- re: [\d-]+ +--- s eval: "*** Failers" + + + +=== TEST 332: testinput1:1428 +--- re: [\d-]+ +--- s eval: "aaa" + + + +=== TEST 333: testinput1:1431 +--- re: [\d-z]+ +--- s eval: "12-34z" + + + +=== TEST 334: testinput1:1432 +--- re: [\d-z]+ +--- s eval: "*** Failers" + + + +=== TEST 335: testinput1:1433 +--- re: [\d-z]+ +--- s eval: "aaa" + + + +=== TEST 336: testinput1:1436 +--- re: \x5c +--- s eval: "\\" + + + +=== TEST 337: testinput1:1439 +--- re: \x20Z +--- s eval: "the Zoo" + + + +=== TEST 338: testinput1:1440 +--- re: \x20Z +--- s eval: "*** Failers" + + + +=== TEST 339: testinput1:1441 +--- re: \x20Z +--- s eval: "Zulu" + + + +=== TEST 340: testinput1:1449 +--- re: ab{3cd +--- s eval: "ab{3cd" + + + +=== TEST 341: testinput1:1452 +--- re: ab{3,cd +--- s eval: "ab{3,cd" + + + +=== TEST 342: testinput1:1455 +--- re: ab{3,4a}cd +--- s eval: "ab{3,4a}cd" + + + +=== TEST 343: testinput1:1458 +--- re: {4,5a}bc +--- s eval: "{4,5a}bc" + + + +=== TEST 344: testinput1:1461 +--- re: abc$ +--- s eval: "abc" + + + +=== TEST 345: testinput1:1462 +--- re: abc$ +--- s eval: "abc\n" + + + +=== TEST 346: testinput1:1463 +--- re: abc$ +--- s eval: "*** Failers" + + + +=== TEST 347: testinput1:1464 +--- re: abc$ +--- s eval: "abc\ndef" + + + +=== TEST 348: testinput1:1502 +--- re: ab\idef +--- s eval: "abidef" + + + +=== TEST 349: testinput1:1505 +--- re: a{0}bc +--- s eval: "bc" + + + +=== TEST 350: testinput1:1508 +--- re: (a|(bc)){0,0}?xyz +--- s eval: "xyz" +--- cap: (0, 3) + + + +=== TEST 351: testinput1:1523 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baNOTccccd" + + + +=== TEST 352: testinput1:1524 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baNOTcccd" + + + +=== TEST 353: testinput1:1525 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baNOTccd" + + + +=== TEST 354: testinput1:1526 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "bacccd" + + + +=== TEST 355: testinput1:1527 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "*** Failers" + + + +=== TEST 356: testinput1:1528 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "anything" + + + +=== TEST 357: testinput1:1529 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "b\bc " + + + +=== TEST 358: testinput1:1530 +--- re: ^([^a])([^\b])([^c]*)([^d]{3,4}) +--- s eval: "baccd" + + + +=== TEST 359: testinput1:1533 +--- re: [^a] +--- s eval: "Abc" + + + +=== TEST 360: testinput1:1536 +--- re: [^a] +--- s eval: "Abc " +--- flags: i + + + +=== TEST 361: testinput1:1539 +--- re: [^a]+ +--- s eval: "AAAaAbc" + + + +=== TEST 362: testinput1:1542 +--- re: [^a]+ +--- s eval: "AAAaAbc " +--- flags: i + + + +=== TEST 363: testinput1:1545 +--- re: [^a]+ +--- s eval: "bbb\nccc" + + + +=== TEST 364: testinput1:1548 +--- re: [^k]$ +--- s eval: "abc" + + + +=== TEST 365: testinput1:1549 +--- re: [^k]$ +--- s eval: "*** Failers" + + + +=== TEST 366: testinput1:1550 +--- re: [^k]$ +--- s eval: "abk " + + + +=== TEST 367: testinput1:1553 +--- re: [^k]{2,3}$ +--- s eval: "abc" + + + +=== TEST 368: testinput1:1554 +--- re: [^k]{2,3}$ +--- s eval: "kbc" + + + +=== TEST 369: testinput1:1555 +--- re: [^k]{2,3}$ +--- s eval: "kabc " + + + +=== TEST 370: testinput1:1556 +--- re: [^k]{2,3}$ +--- s eval: "*** Failers" + + + +=== TEST 371: testinput1:1557 +--- re: [^k]{2,3}$ +--- s eval: "abk" + + + +=== TEST 372: testinput1:1558 +--- re: [^k]{2,3}$ +--- s eval: "akb" + + + +=== TEST 373: testinput1:1559 +--- re: [^k]{2,3}$ +--- s eval: "akk " + + + +=== TEST 374: testinput1:1562 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "12345678\@a.b.c.d" + + + +=== TEST 375: testinput1:1563 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "123456789\@x.y.z" + + + +=== TEST 376: testinput1:1564 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "*** Failers" + + + +=== TEST 377: testinput1:1565 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "12345678\@x.y.uk" + + + +=== TEST 378: testinput1:1566 +--- re: ^\d{8,}\@.+[^k]$ +--- s eval: "1234567\@a.b.c.d " + + + +=== TEST 379: testinput1:1575 +--- re: [^a] +--- s eval: "aaaabcd" + + + +=== TEST 380: testinput1:1576 +--- re: [^a] +--- s eval: "aaAabcd " + + + +=== TEST 381: testinput1:1579 +--- re: [^a] +--- s eval: "aaaabcd" +--- flags: i + + + +=== TEST 382: testinput1:1580 +--- re: [^a] +--- s eval: "aaAabcd " +--- flags: i + + + +=== TEST 383: testinput1:1583 +--- re: [^az] +--- s eval: "aaaabcd" + + + +=== TEST 384: testinput1:1584 +--- re: [^az] +--- s eval: "aaAabcd " + + + +=== TEST 385: testinput1:1587 +--- re: [^az] +--- s eval: "aaaabcd" +--- flags: i + + + +=== TEST 386: testinput1:1588 +--- re: [^az] +--- s eval: "aaAabcd " +--- flags: i + + + +=== TEST 387: testinput1:1594 +--- re: P[^*]TAIRE[^*]{1,6}?LL +--- s eval: "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" + + + +=== TEST 388: testinput1:1597 +--- re: P[^*]TAIRE[^*]{1,}?LL +--- s eval: "xxxxxxxxxxxPSTAIREISLLxxxxxxxxx" + + + +=== TEST 389: testinput1:1600 +--- re: (\.\d\d[1-9]?)\d+ +--- s eval: "1.230003938" + + + +=== TEST 390: testinput1:1601 +--- re: (\.\d\d[1-9]?)\d+ +--- s eval: "1.875000282 " + + + +=== TEST 391: testinput1:1602 +--- re: (\.\d\d[1-9]?)\d+ +--- s eval: "1.235 " + + + +=== TEST 392: testinput1:1614 +--- re: \b(foo)\s+(\w+) +--- s eval: "Food is on the foo table" +--- flags: i + + + +=== TEST 393: testinput1:1617 +--- re: foo(.*)bar +--- s eval: "The food is under the bar in the barn." + + + +=== TEST 394: testinput1:1620 +--- re: foo(.*?)bar +--- s eval: "The food is under the bar in the barn." + + + +=== TEST 395: testinput1:1623 +--- re: (.*)(\d*) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 396: testinput1:1626 +--- re: (.*)(\d+) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 397: testinput1:1629 +--- re: (.*?)(\d*) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 398: testinput1:1632 +--- re: (.*?)(\d+) +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 399: testinput1:1635 +--- re: (.*)(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 400: testinput1:1638 +--- re: (.*?)(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 401: testinput1:1641 +--- re: (.*)\b(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 402: testinput1:1644 +--- re: (.*\D)(\d+)$ +--- s eval: "I have 2 numbers: 53147" + + + +=== TEST 403: testinput1:1655 +--- re: ^[W-]46] +--- s eval: "W46]789 " + + + +=== TEST 404: testinput1:1656 +--- re: ^[W-]46] +--- s eval: "-46]789" + + + +=== TEST 405: testinput1:1657 +--- re: ^[W-]46] +--- s eval: "*** Failers" + + + +=== TEST 406: testinput1:1658 +--- re: ^[W-]46] +--- s eval: "Wall" + + + +=== TEST 407: testinput1:1659 +--- re: ^[W-]46] +--- s eval: "Zebra" + + + +=== TEST 408: testinput1:1660 +--- re: ^[W-]46] +--- s eval: "42" + + + +=== TEST 409: testinput1:1661 +--- re: ^[W-]46] +--- s eval: "[abcd] " + + + +=== TEST 410: testinput1:1662 +--- re: ^[W-]46] +--- s eval: "]abcd[" + + + +=== TEST 411: testinput1:1665 +--- re: ^[W-\]46] +--- s eval: "W46]789 " + + + +=== TEST 412: testinput1:1666 +--- re: ^[W-\]46] +--- s eval: "Wall" + + + +=== TEST 413: testinput1:1667 +--- re: ^[W-\]46] +--- s eval: "Zebra" + + + +=== TEST 414: testinput1:1668 +--- re: ^[W-\]46] +--- s eval: "Xylophone " + + + +=== TEST 415: testinput1:1669 +--- re: ^[W-\]46] +--- s eval: "42" + + + +=== TEST 416: testinput1:1670 +--- re: ^[W-\]46] +--- s eval: "[abcd] " + + + +=== TEST 417: testinput1:1671 +--- re: ^[W-\]46] +--- s eval: "]abcd[" + + + +=== TEST 418: testinput1:1672 +--- re: ^[W-\]46] +--- s eval: "\\backslash " + + + +=== TEST 419: testinput1:1673 +--- re: ^[W-\]46] +--- s eval: "*** Failers" + + + +=== TEST 420: testinput1:1674 +--- re: ^[W-\]46] +--- s eval: "-46]789" + + + +=== TEST 421: testinput1:1675 +--- re: ^[W-\]46] +--- s eval: "well" + + + +=== TEST 422: testinput1:1678 +--- re: \d\d\/\d\d\/\d\d\d\d +--- s eval: "01/01/2000" + + + +=== TEST 423: testinput1:1681 +--- re: word (?:[a-zA-Z0-9]+ ){0,10}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark otherword" + + + +=== TEST 424: testinput1:1682 +--- re: word (?:[a-zA-Z0-9]+ ){0,10}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark" + + + +=== TEST 425: testinput1:1685 +--- re: word (?:[a-zA-Z0-9]+ ){0,300}otherword +--- s eval: "word cat dog elephant mussel cow horse canary baboon snake shark the quick brown fox and the lazy dog and several other words getting close to thirty by now I hope" + + + +=== TEST 426: testinput1:1688 +--- re: ^(a){0,0} +--- s eval: "bcd" + + + +=== TEST 427: testinput1:1689 +--- re: ^(a){0,0} +--- s eval: "abc" + + + +=== TEST 428: testinput1:1690 +--- re: ^(a){0,0} +--- s eval: "aab " + + + +=== TEST 429: testinput1:1693 +--- re: ^(a){0,1} +--- s eval: "bcd" + + + +=== TEST 430: testinput1:1694 +--- re: ^(a){0,1} +--- s eval: "abc" + + + +=== TEST 431: testinput1:1695 +--- re: ^(a){0,1} +--- s eval: "aab " + + + +=== TEST 432: testinput1:1698 +--- re: ^(a){0,2} +--- s eval: "bcd" + + + +=== TEST 433: testinput1:1699 +--- re: ^(a){0,2} +--- s eval: "abc" + + + +=== TEST 434: testinput1:1700 +--- re: ^(a){0,2} +--- s eval: "aab " + + + +=== TEST 435: testinput1:1703 +--- re: ^(a){0,3} +--- s eval: "bcd" + + + +=== TEST 436: testinput1:1704 +--- re: ^(a){0,3} +--- s eval: "abc" + + + +=== TEST 437: testinput1:1705 +--- re: ^(a){0,3} +--- s eval: "aab" + + + +=== TEST 438: testinput1:1706 +--- re: ^(a){0,3} +--- s eval: "aaa " + + + +=== TEST 439: testinput1:1709 +--- re: ^(a){0,} +--- s eval: "bcd" + + + +=== TEST 440: testinput1:1710 +--- re: ^(a){0,} +--- s eval: "abc" + + + +=== TEST 441: testinput1:1711 +--- re: ^(a){0,} +--- s eval: "aab" + + + +=== TEST 442: testinput1:1712 +--- re: ^(a){0,} +--- s eval: "aaa" + + + +=== TEST 443: testinput1:1713 +--- re: ^(a){0,} +--- s eval: "aaaaaaaa " + + + +=== TEST 444: testinput1:1716 +--- re: ^(a){1,1} +--- s eval: "bcd" + + + +=== TEST 445: testinput1:1717 +--- re: ^(a){1,1} +--- s eval: "abc" + + + +=== TEST 446: testinput1:1718 +--- re: ^(a){1,1} +--- s eval: "aab " + + + +=== TEST 447: testinput1:1721 +--- re: ^(a){1,2} +--- s eval: "bcd" + + + +=== TEST 448: testinput1:1722 +--- re: ^(a){1,2} +--- s eval: "abc" + + + +=== TEST 449: testinput1:1723 +--- re: ^(a){1,2} +--- s eval: "aab " + + + +=== TEST 450: testinput1:1726 +--- re: ^(a){1,3} +--- s eval: "bcd" + + + +=== TEST 451: testinput1:1727 +--- re: ^(a){1,3} +--- s eval: "abc" + + + +=== TEST 452: testinput1:1728 +--- re: ^(a){1,3} +--- s eval: "aab" + + + +=== TEST 453: testinput1:1729 +--- re: ^(a){1,3} +--- s eval: "aaa " + + + +=== TEST 454: testinput1:1732 +--- re: ^(a){1,} +--- s eval: "bcd" + + + +=== TEST 455: testinput1:1733 +--- re: ^(a){1,} +--- s eval: "abc" + + + +=== TEST 456: testinput1:1734 +--- re: ^(a){1,} +--- s eval: "aab" + + + +=== TEST 457: testinput1:1735 +--- re: ^(a){1,} +--- s eval: "aaa" + + + +=== TEST 458: testinput1:1736 +--- re: ^(a){1,} +--- s eval: "aaaaaaaa " + + + +=== TEST 459: testinput1:1739 +--- re: .*\.gif +--- s eval: "borfle\nbib.gif\nno" + + + +=== TEST 460: testinput1:1742 +--- re: .{0,}\.gif +--- s eval: "borfle\nbib.gif\nno" + + + +=== TEST 461: testinput1:1754 +--- re: .*$ +--- s eval: "borfle\nbib.gif\nno" + + + +=== TEST 462: testinput1:1766 +--- re: .*$ +--- s eval: "borfle\nbib.gif\nno\n" + + + +=== TEST 463: testinput1:1778 +--- re: (.*X|^B) +--- s eval: "abcde\n1234Xyz" + + + +=== TEST 464: testinput1:1779 +--- re: (.*X|^B) +--- s eval: "BarFoo " + + + +=== TEST 465: testinput1:1780 +--- re: (.*X|^B) +--- s eval: "*** Failers" + + + +=== TEST 466: testinput1:1781 +--- re: (.*X|^B) +--- s eval: "abcde\nBar " + + + +=== TEST 467: testinput1:1812 +--- re: ^.*B +--- s eval: "**** Failers" + + + +=== TEST 468: testinput1:1813 +--- re: ^.*B +--- s eval: "abc\nB" + + + +=== TEST 469: testinput1:1831 +--- re: ^[0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9] +--- s eval: "123456654321" + + + +=== TEST 470: testinput1:1834 +--- re: ^\d\d\d\d\d\d\d\d\d\d\d\d +--- s eval: "123456654321 " + + + +=== TEST 471: testinput1:1837 +--- re: ^[\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d][\d] +--- s eval: "123456654321" + + + +=== TEST 472: testinput1:1840 +--- re: ^[abc]{12} +--- s eval: "abcabcabcabc" + + + +=== TEST 473: testinput1:1843 +--- re: ^[a-c]{12} +--- s eval: "abcabcabcabc" + + + +=== TEST 474: testinput1:1846 +--- re: ^(a|b|c){12} +--- s eval: "abcabcabcabc " + + + +=== TEST 475: testinput1:1849 +--- re: ^[abcdefghijklmnopqrstuvwxy0123456789] +--- s eval: "n" + + + +=== TEST 476: testinput1:1850 +--- re: ^[abcdefghijklmnopqrstuvwxy0123456789] +--- s eval: "*** Failers " + + + +=== TEST 477: testinput1:1851 +--- re: ^[abcdefghijklmnopqrstuvwxy0123456789] +--- s eval: "z " + + + +=== TEST 478: testinput1:1854 +--- re: abcde{0,0} +--- s eval: "abcd" + + + +=== TEST 479: testinput1:1855 +--- re: abcde{0,0} +--- s eval: "*** Failers" + + + +=== TEST 480: testinput1:1856 +--- re: abcde{0,0} +--- s eval: "abce " + + + +=== TEST 481: testinput1:1859 +--- re: ab[cd]{0,0}e +--- s eval: "abe" + + + +=== TEST 482: testinput1:1860 +--- re: ab[cd]{0,0}e +--- s eval: "*** Failers" + + + +=== TEST 483: testinput1:1861 +--- re: ab[cd]{0,0}e +--- s eval: "abcde " + + + +=== TEST 484: testinput1:1864 +--- re: ab(c){0,0}d +--- s eval: "abd" + + + +=== TEST 485: testinput1:1865 +--- re: ab(c){0,0}d +--- s eval: "*** Failers" + + + +=== TEST 486: testinput1:1866 +--- re: ab(c){0,0}d +--- s eval: "abcd " + + + +=== TEST 487: testinput1:1869 +--- re: a(b*) +--- s eval: "a" + + + +=== TEST 488: testinput1:1870 +--- re: a(b*) +--- s eval: "ab" + + + +=== TEST 489: testinput1:1871 +--- re: a(b*) +--- s eval: "abbbb" + + + +=== TEST 490: testinput1:1872 +--- re: a(b*) +--- s eval: "*** Failers" + + + +=== TEST 491: testinput1:1873 +--- re: a(b*) +--- s eval: "bbbbb " + + + +=== TEST 492: testinput1:1876 +--- re: ab\d{0}e +--- s eval: "abe" + + + +=== TEST 493: testinput1:1877 +--- re: ab\d{0}e +--- s eval: "*** Failers" + + + +=== TEST 494: testinput1:1878 +--- re: ab\d{0}e +--- s eval: "ab1e " + + + +=== TEST 495: testinput1:1881 +--- re: "([^\\"]+|\\.)*" +--- s eval: "the \"quick\" brown fox" + + + +=== TEST 496: testinput1:1882 +--- re: "([^\\"]+|\\.)*" +--- s eval: "\"the \\\"quick\\\" brown fox\" " + + + +=== TEST 497: testinput1:1885 +--- re: .*? +--- s eval: "abc" + + + +=== TEST 498: testinput1:1888 +--- re: \b +--- s eval: "abc " + + + +=== TEST 499: testinput1:1894 +--- re: +--- s eval: "abc" + + + +=== TEST 500: testinput1:1897 +--- re: ]{0,})>]{0,})>([\d]{0,}\.)(.*)((
([\w\W\s\d][^<>]{0,})|[\s]{0,}))<\/a><\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD>]{0,})>([\w\W\s\d][^<>]{0,})<\/TD><\/TR> +--- s eval: "43.Word Processor
(N-1286)
Lega lstaff.comCA - Statewide" +--- flags: i + + + +=== TEST 501: testinput1:1900 +--- re: a[^a]b +--- s eval: "acb" + + + +=== TEST 502: testinput1:1901 +--- re: a[^a]b +--- s eval: "a\nb" + + + +=== TEST 503: testinput1:1904 +--- re: a.b +--- s eval: "acb" + + + +=== TEST 504: testinput1:1905 +--- re: a.b +--- s eval: "*** Failers " + + + +=== TEST 505: testinput1:1906 +--- re: a.b +--- s eval: "a\nb " + + + +=== TEST 506: testinput1:1910 +--- re: a[^a]b +--- s eval: "a\nb " + + + +=== TEST 507: testinput1:1914 +--- re: a.b +--- s eval: "a\nb " + + + +=== TEST 508: testinput1:1919 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbac" + + + +=== TEST 509: testinput1:1920 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbbac" + + + +=== TEST 510: testinput1:1921 +--- re: ^(b+?|a){1,2}?c +--- s eval: "bbbbbac " + + + +=== TEST 511: testinput1:1924 +--- re: ^(b+|a){1,2}?c +--- s eval: "bac" + + + +=== TEST 512: testinput1:1925 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbac" + + + +=== TEST 513: testinput1:1926 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbbac" + + + +=== TEST 514: testinput1:1927 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbbbac" + + + +=== TEST 515: testinput1:1928 +--- re: ^(b+|a){1,2}?c +--- s eval: "bbbbbac " + + + +=== TEST 516: testinput1:1935 +--- re: \x0{ab} +--- s eval: "\0{ab} " + + + +=== TEST 517: testinput1:1938 +--- re: (A|B)*?CD +--- s eval: "CD " + + + +=== TEST 518: testinput1:1941 +--- re: (A|B)*CD +--- s eval: "CD " + + + +=== TEST 519: testinput1:1972 +--- re: \Aabc\z +--- s eval: "abc" + + + +=== TEST 520: testinput1:1973 +--- re: \Aabc\z +--- s eval: "*** Failers" + + + +=== TEST 521: testinput1:1974 +--- re: \Aabc\z +--- s eval: "abc\n " + + + +=== TEST 522: testinput1:1975 +--- re: \Aabc\z +--- s eval: "qqq\nabc" + + + +=== TEST 523: testinput1:1976 +--- re: \Aabc\z +--- s eval: "abc\nzzz" + + + +=== TEST 524: testinput1:1977 +--- re: \Aabc\z +--- s eval: "qqq\nabc\nzzz" + + + +=== TEST 525: testinput1:1980 +--- re: \Aabc\z +--- s eval: "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/it/you/see/" + + + +=== TEST 526: testinput1:1983 +--- re: \Aabc\z +--- s eval: "/this/is/a/very/long/line/in/deed/with/very/many/slashes/in/and/foo" + + + +=== TEST 527: testinput1:1997 +--- re: (\d+)(\w) +--- s eval: "12345a" + + + +=== TEST 528: testinput1:1998 +--- re: (\d+)(\w) +--- s eval: "12345+ " + + + +=== TEST 529: testinput1:2210 +--- re: (abc|)+ +--- s eval: "abc" +--- cap: (0, 3) (0, 3) + + + +=== TEST 530: testinput1:2211 +--- re: (abc|)+ +--- s eval: "abcabc" +--- cap: (0, 6) (3, 6) + + + +=== TEST 531: testinput1:2212 +--- re: (abc|)+ +--- s eval: "abcabcabc" +--- cap: (0, 9) (6, 9) + + + +=== TEST 532: testinput1:2213 +--- re: (abc|)+ +--- s eval: "xyz " + + + +=== TEST 533: testinput1:2216 +--- re: ([a]*)* +--- s eval: "a" +--- cap: (0, 1) (0, 1) + + + +=== TEST 534: testinput1:2217 +--- re: ([a]*)* +--- s eval: "aaaaa " +--- cap: (0, 5) (0, 5) + + + +=== TEST 535: testinput1:2220 +--- re: ([ab]*)* +--- s eval: "a" +--- cap: (0, 1) (0, 1) + + + +=== TEST 536: testinput1:2221 +--- re: ([ab]*)* +--- s eval: "b" +--- cap: (0, 1) (0, 1) + + + +=== TEST 537: testinput1:2222 +--- re: ([ab]*)* +--- s eval: "ababab" +--- cap: (0, 6) (0, 6) + + + +=== TEST 538: testinput1:2223 +--- re: ([ab]*)* +--- s eval: "aaaabcde" +--- cap: (0, 5) (0, 5) + + + +=== TEST 539: testinput1:2224 +--- re: ([ab]*)* +--- s eval: "bbbb " +--- cap: (0, 4) (0, 4) + + + +=== TEST 540: testinput1:2227 +--- re: ([^a]*)* +--- s eval: "b" +--- cap: (0, 1) (0, 1) + + + +=== TEST 541: testinput1:2228 +--- re: ([^a]*)* +--- s eval: "bbbb" +--- cap: (0, 4) (0, 4) + + + +=== TEST 542: testinput1:2229 +--- re: ([^a]*)* +--- s eval: "aaa " + + + +=== TEST 543: testinput1:2232 +--- re: ([^ab]*)* +--- s eval: "cccc" +--- cap: (0, 4) (0, 4) + + + +=== TEST 544: testinput1:2233 +--- re: ([^ab]*)* +--- s eval: "abab " + + + +=== TEST 545: testinput1:2236 +--- re: ([a]*?)* +--- s eval: "a" + + + +=== TEST 546: testinput1:2237 +--- re: ([a]*?)* +--- s eval: "aaaa " + + + +=== TEST 547: testinput1:2240 +--- re: ([ab]*?)* +--- s eval: "a" + + + +=== TEST 548: testinput1:2241 +--- re: ([ab]*?)* +--- s eval: "b" + + + +=== TEST 549: testinput1:2242 +--- re: ([ab]*?)* +--- s eval: "abab" + + + +=== TEST 550: testinput1:2243 +--- re: ([ab]*?)* +--- s eval: "baba " + + + +=== TEST 551: testinput1:2246 +--- re: ([^a]*?)* +--- s eval: "b" + + + +=== TEST 552: testinput1:2247 +--- re: ([^a]*?)* +--- s eval: "bbbb" + + + +=== TEST 553: testinput1:2248 +--- re: ([^a]*?)* +--- s eval: "aaa " + + + +=== TEST 554: testinput1:2251 +--- re: ([^ab]*?)* +--- s eval: "c" + + + +=== TEST 555: testinput1:2252 +--- re: ([^ab]*?)* +--- s eval: "cccc" + + + +=== TEST 556: testinput1:2253 +--- re: ([^ab]*?)* +--- s eval: "baba " + + + +=== TEST 557: testinput1:2378 +--- re: abc +--- s eval: "abc" + + + +=== TEST 558: testinput1:2379 +--- re: abc +--- s eval: "xabcy" + + + +=== TEST 559: testinput1:2380 +--- re: abc +--- s eval: "ababc" + + + +=== TEST 560: testinput1:2381 +--- re: abc +--- s eval: "*** Failers" + + + +=== TEST 561: testinput1:2382 +--- re: abc +--- s eval: "xbc" + + + +=== TEST 562: testinput1:2383 +--- re: abc +--- s eval: "axc" + + + +=== TEST 563: testinput1:2384 +--- re: abc +--- s eval: "abx" + + + +=== TEST 564: testinput1:2387 +--- re: ab*c +--- s eval: "abc" + + + +=== TEST 565: testinput1:2390 +--- re: ab*bc +--- s eval: "abc" + + + +=== TEST 566: testinput1:2391 +--- re: ab*bc +--- s eval: "abbc" + + + +=== TEST 567: testinput1:2392 +--- re: ab*bc +--- s eval: "abbbbc" + + + +=== TEST 568: testinput1:2395 +--- re: .{1} +--- s eval: "abbbbc" + + + +=== TEST 569: testinput1:2398 +--- re: .{3,4} +--- s eval: "abbbbc" + + + +=== TEST 570: testinput1:2401 +--- re: ab{0,}bc +--- s eval: "abbbbc" + + + +=== TEST 571: testinput1:2404 +--- re: ab+bc +--- s eval: "abbc" + + + +=== TEST 572: testinput1:2405 +--- re: ab+bc +--- s eval: "*** Failers" + + + +=== TEST 573: testinput1:2406 +--- re: ab+bc +--- s eval: "abc" + + + +=== TEST 574: testinput1:2407 +--- re: ab+bc +--- s eval: "abq" + + + +=== TEST 575: testinput1:2412 +--- re: ab+bc +--- s eval: "abbbbc" + + + +=== TEST 576: testinput1:2415 +--- re: ab{1,}bc +--- s eval: "abbbbc" + + + +=== TEST 577: testinput1:2421 +--- re: ab{3,4}bc +--- s eval: "abbbbc" + + + +=== TEST 578: testinput1:2424 +--- re: ab{4,5}bc +--- s eval: "*** Failers" + + + +=== TEST 579: testinput1:2425 +--- re: ab{4,5}bc +--- s eval: "abq" + + + +=== TEST 580: testinput1:2426 +--- re: ab{4,5}bc +--- s eval: "abbbbc" + + + +=== TEST 581: testinput1:2429 +--- re: ab?bc +--- s eval: "abbc" + + + +=== TEST 582: testinput1:2430 +--- re: ab?bc +--- s eval: "abc" + + + +=== TEST 583: testinput1:2433 +--- re: ab{0,1}bc +--- s eval: "abc" + + + +=== TEST 584: testinput1:2438 +--- re: ab?c +--- s eval: "abc" + + + +=== TEST 585: testinput1:2441 +--- re: ab{0,1}c +--- s eval: "abc" + + + +=== TEST 586: testinput1:2446 +--- re: ^abc$ +--- s eval: "abbbbc" + + + +=== TEST 587: testinput1:2447 +--- re: ^abc$ +--- s eval: "abcc" + + + +=== TEST 588: testinput1:2450 +--- re: ^abc +--- s eval: "abcc" + + + +=== TEST 589: testinput1:2455 +--- re: abc$ +--- s eval: "aabc" + + + +=== TEST 590: testinput1:2458 +--- re: abc$ +--- s eval: "aabcd" + + + +=== TEST 591: testinput1:2461 +--- re: ^ +--- s eval: "abc" + + + +=== TEST 592: testinput1:2464 +--- re: $ +--- s eval: "abc" + + + +=== TEST 593: testinput1:2467 +--- re: a.c +--- s eval: "abc" + + + +=== TEST 594: testinput1:2468 +--- re: a.c +--- s eval: "axc" + + + +=== TEST 595: testinput1:2471 +--- re: a.*c +--- s eval: "axyzc" + + + +=== TEST 596: testinput1:2474 +--- re: a[bc]d +--- s eval: "abd" + + + +=== TEST 597: testinput1:2475 +--- re: a[bc]d +--- s eval: "*** Failers" + + + +=== TEST 598: testinput1:2476 +--- re: a[bc]d +--- s eval: "axyzd" + + + +=== TEST 599: testinput1:2477 +--- re: a[bc]d +--- s eval: "abc" + + + +=== TEST 600: testinput1:2480 +--- re: a[b-d]e +--- s eval: "ace" + + + +=== TEST 601: testinput1:2483 +--- re: a[b-d] +--- s eval: "aac" + + + +=== TEST 602: testinput1:2486 +--- re: a[-b] +--- s eval: "a-" + + + +=== TEST 603: testinput1:2489 +--- re: a[b-] +--- s eval: "a-" + + + +=== TEST 604: testinput1:2492 +--- re: a] +--- s eval: "a]" + + + +=== TEST 605: testinput1:2495 +--- re: a[]]b +--- s eval: "a]b" + + + +=== TEST 606: testinput1:2498 +--- re: a[^bc]d +--- s eval: "aed" + + + +=== TEST 607: testinput1:2499 +--- re: a[^bc]d +--- s eval: "*** Failers" + + + +=== TEST 608: testinput1:2500 +--- re: a[^bc]d +--- s eval: "abd" + + + +=== TEST 609: testinput1:2504 +--- re: a[^-b]c +--- s eval: "adc" + + + +=== TEST 610: testinput1:2507 +--- re: a[^]b]c +--- s eval: "adc" + + + +=== TEST 611: testinput1:2508 +--- re: a[^]b]c +--- s eval: "*** Failers" + + + +=== TEST 612: testinput1:2509 +--- re: a[^]b]c +--- s eval: "a-c" + + + +=== TEST 613: testinput1:2510 +--- re: a[^]b]c +--- s eval: "a]c" + + + +=== TEST 614: testinput1:2513 +--- re: \ba\b +--- s eval: "a-" + + + +=== TEST 615: testinput1:2514 +--- re: \ba\b +--- s eval: "-a" + + + +=== TEST 616: testinput1:2515 +--- re: \ba\b +--- s eval: "-a-" + + + +=== TEST 617: testinput1:2518 +--- re: \by\b +--- s eval: "*** Failers" + + + +=== TEST 618: testinput1:2519 +--- re: \by\b +--- s eval: "xy" + + + +=== TEST 619: testinput1:2520 +--- re: \by\b +--- s eval: "yz" + + + +=== TEST 620: testinput1:2521 +--- re: \by\b +--- s eval: "xyz" + + + +=== TEST 621: testinput1:2524 +--- re: \Ba\B +--- s eval: "*** Failers" + + + +=== TEST 622: testinput1:2525 +--- re: \Ba\B +--- s eval: "a-" + + + +=== TEST 623: testinput1:2526 +--- re: \Ba\B +--- s eval: "-a" + + + +=== TEST 624: testinput1:2527 +--- re: \Ba\B +--- s eval: "-a-" + + + +=== TEST 625: testinput1:2530 +--- re: \By\b +--- s eval: "xy" + + + +=== TEST 626: testinput1:2533 +--- re: \by\B +--- s eval: "yz" + + + +=== TEST 627: testinput1:2536 +--- re: \By\B +--- s eval: "xyz" + + + +=== TEST 628: testinput1:2539 +--- re: \w +--- s eval: "a" + + + +=== TEST 629: testinput1:2542 +--- re: \W +--- s eval: "-" + + + +=== TEST 630: testinput1:2543 +--- re: \W +--- s eval: "*** Failers" + + + +=== TEST 631: testinput1:2545 +--- re: \W +--- s eval: "a" + + + +=== TEST 632: testinput1:2548 +--- re: a\sb +--- s eval: "a b" + + + +=== TEST 633: testinput1:2551 +--- re: a\Sb +--- s eval: "a-b" + + + +=== TEST 634: testinput1:2552 +--- re: a\Sb +--- s eval: "*** Failers" + + + +=== TEST 635: testinput1:2554 +--- re: a\Sb +--- s eval: "a b" + + + +=== TEST 636: testinput1:2557 +--- re: \d +--- s eval: "1" + + + +=== TEST 637: testinput1:2560 +--- re: \D +--- s eval: "-" + + + +=== TEST 638: testinput1:2561 +--- re: \D +--- s eval: "*** Failers" + + + +=== TEST 639: testinput1:2563 +--- re: \D +--- s eval: "1" + + + +=== TEST 640: testinput1:2566 +--- re: [\w] +--- s eval: "a" + + + +=== TEST 641: testinput1:2569 +--- re: [\W] +--- s eval: "-" + + + +=== TEST 642: testinput1:2570 +--- re: [\W] +--- s eval: "*** Failers" + + + +=== TEST 643: testinput1:2572 +--- re: [\W] +--- s eval: "a" + + + +=== TEST 644: testinput1:2575 +--- re: a[\s]b +--- s eval: "a b" + + + +=== TEST 645: testinput1:2578 +--- re: a[\S]b +--- s eval: "a-b" + + + +=== TEST 646: testinput1:2579 +--- re: a[\S]b +--- s eval: "*** Failers" + + + +=== TEST 647: testinput1:2581 +--- re: a[\S]b +--- s eval: "a b" + + + +=== TEST 648: testinput1:2584 +--- re: [\d] +--- s eval: "1" + + + +=== TEST 649: testinput1:2587 +--- re: [\D] +--- s eval: "-" + + + +=== TEST 650: testinput1:2588 +--- re: [\D] +--- s eval: "*** Failers" + + + +=== TEST 651: testinput1:2590 +--- re: [\D] +--- s eval: "1" + + + +=== TEST 652: testinput1:2593 +--- re: ab|cd +--- s eval: "abc" + + + +=== TEST 653: testinput1:2594 +--- re: ab|cd +--- s eval: "abcd" + + + +=== TEST 654: testinput1:2597 +--- re: ()ef +--- s eval: "def" + + + +=== TEST 655: testinput1:2602 +--- re: a\(b +--- s eval: "a(b" + + + +=== TEST 656: testinput1:2605 +--- re: a\(*b +--- s eval: "ab" + + + +=== TEST 657: testinput1:2606 +--- re: a\(*b +--- s eval: "a((b" + + + +=== TEST 658: testinput1:2609 +--- re: a\\b +--- s eval: "a\b" + + + +=== TEST 659: testinput1:2612 +--- re: ((a)) +--- s eval: "abc" + + + +=== TEST 660: testinput1:2615 +--- re: (a)b(c) +--- s eval: "abc" + + + +=== TEST 661: testinput1:2618 +--- re: a+b+c +--- s eval: "aabbabc" + + + +=== TEST 662: testinput1:2621 +--- re: a{1,}b{1,}c +--- s eval: "aabbabc" + + + +=== TEST 663: testinput1:2624 +--- re: a.+?c +--- s eval: "abcabc" + + + +=== TEST 664: testinput1:2627 +--- re: (a+|b)* +--- s eval: "ab" + + + +=== TEST 665: testinput1:2630 +--- re: (a+|b){0,} +--- s eval: "ab" + + + +=== TEST 666: testinput1:2633 +--- re: (a+|b)+ +--- s eval: "ab" + + + +=== TEST 667: testinput1:2636 +--- re: (a+|b){1,} +--- s eval: "ab" + + + +=== TEST 668: testinput1:2639 +--- re: (a+|b)? +--- s eval: "ab" + + + +=== TEST 669: testinput1:2642 +--- re: (a+|b){0,1} +--- s eval: "ab" + + + +=== TEST 670: testinput1:2645 +--- re: [^ab]* +--- s eval: "cde" + + + +=== TEST 671: testinput1:2649 +--- re: abc +--- s eval: "b" + + + +=== TEST 672: testinput1:2656 +--- re: ([abc])*d +--- s eval: "abbbcd" + + + +=== TEST 673: testinput1:2659 +--- re: ([abc])*bcd +--- s eval: "abcd" + + + +=== TEST 674: testinput1:2662 +--- re: a|b|c|d|e +--- s eval: "e" + + + +=== TEST 675: testinput1:2665 +--- re: (a|b|c|d|e)f +--- s eval: "ef" + + + +=== TEST 676: testinput1:2668 +--- re: abcd*efg +--- s eval: "abcdefg" + + + +=== TEST 677: testinput1:2671 +--- re: ab* +--- s eval: "xabyabbbz" + + + +=== TEST 678: testinput1:2672 +--- re: ab* +--- s eval: "xayabbbz" + + + +=== TEST 679: testinput1:2675 +--- re: (ab|cd)e +--- s eval: "abcde" + + + +=== TEST 680: testinput1:2678 +--- re: [abhgefdc]ij +--- s eval: "hij" + + + +=== TEST 681: testinput1:2683 +--- re: (abc|)ef +--- s eval: "abcdef" + + + +=== TEST 682: testinput1:2686 +--- re: (a|b)c*d +--- s eval: "abcd" + + + +=== TEST 683: testinput1:2689 +--- re: (ab|ab*)bc +--- s eval: "abc" + + + +=== TEST 684: testinput1:2692 +--- re: a([bc]*)c* +--- s eval: "abc" + + + +=== TEST 685: testinput1:2695 +--- re: a([bc]*)(c*d) +--- s eval: "abcd" + + + +=== TEST 686: testinput1:2698 +--- re: a([bc]+)(c*d) +--- s eval: "abcd" + + + +=== TEST 687: testinput1:2701 +--- re: a([bc]*)(c+d) +--- s eval: "abcd" + + + +=== TEST 688: testinput1:2704 +--- re: a[bcd]*dcdcde +--- s eval: "adcdcde" + + + +=== TEST 689: testinput1:2707 +--- re: a[bcd]+dcdcde +--- s eval: "*** Failers" + + + +=== TEST 690: testinput1:2708 +--- re: a[bcd]+dcdcde +--- s eval: "abcde" + + + +=== TEST 691: testinput1:2709 +--- re: a[bcd]+dcdcde +--- s eval: "adcdcde" + + + +=== TEST 692: testinput1:2712 +--- re: (ab|a)b*c +--- s eval: "abc" + + + +=== TEST 693: testinput1:2715 +--- re: ((a)(b)c)(d) +--- s eval: "abcd" + + + +=== TEST 694: testinput1:2718 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "alpha" + + + +=== TEST 695: testinput1:2721 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "abh" + + + +=== TEST 696: testinput1:2724 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effgz" + + + +=== TEST 697: testinput1:2725 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "ij" + + + +=== TEST 698: testinput1:2726 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "reffgz" + + + +=== TEST 699: testinput1:2727 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "*** Failers" + + + +=== TEST 700: testinput1:2728 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "effg" + + + +=== TEST 701: testinput1:2729 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "bcdd" + + + +=== TEST 702: testinput1:2732 +--- re: ((((((((((a)))))))))) +--- s eval: "a" + + + +=== TEST 703: testinput1:2738 +--- re: (((((((((a))))))))) +--- s eval: "a" + + + +=== TEST 704: testinput1:2741 +--- re: multiple words of text +--- s eval: "*** Failers" + + + +=== TEST 705: testinput1:2742 +--- re: multiple words of text +--- s eval: "aa" + + + +=== TEST 706: testinput1:2743 +--- re: multiple words of text +--- s eval: "uh-uh" + + + +=== TEST 707: testinput1:2746 +--- re: multiple words +--- s eval: "multiple words, yeah" + + + +=== TEST 708: testinput1:2749 +--- re: (.*)c(.*) +--- s eval: "abcde" + + + +=== TEST 709: testinput1:2752 +--- re: \((.*), (.*)\) +--- s eval: "(a, b)" + + + +=== TEST 710: testinput1:2757 +--- re: abcd +--- s eval: "abcd" + + + +=== TEST 711: testinput1:2760 +--- re: a(bc)d +--- s eval: "abcd" + + + +=== TEST 712: testinput1:2763 +--- re: a[-]?c +--- s eval: "ac" + + + +=== TEST 713: testinput1:2790 +--- re: abc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 714: testinput1:2791 +--- re: abc +--- s eval: "XABCY" +--- flags: i + + + +=== TEST 715: testinput1:2792 +--- re: abc +--- s eval: "ABABC" +--- flags: i + + + +=== TEST 716: testinput1:2793 +--- re: abc +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 717: testinput1:2794 +--- re: abc +--- s eval: "aaxabxbaxbbx" +--- flags: i + + + +=== TEST 718: testinput1:2795 +--- re: abc +--- s eval: "XBC" +--- flags: i + + + +=== TEST 719: testinput1:2796 +--- re: abc +--- s eval: "AXC" +--- flags: i + + + +=== TEST 720: testinput1:2797 +--- re: abc +--- s eval: "ABX" +--- flags: i + + + +=== TEST 721: testinput1:2800 +--- re: ab*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 722: testinput1:2803 +--- re: ab*bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 723: testinput1:2804 +--- re: ab*bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 724: testinput1:2807 +--- re: ab*?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 725: testinput1:2810 +--- re: ab{0,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 726: testinput1:2813 +--- re: ab+?bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 727: testinput1:2816 +--- re: ab+bc +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 728: testinput1:2817 +--- re: ab+bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 729: testinput1:2818 +--- re: ab+bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 730: testinput1:2823 +--- re: ab+bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 731: testinput1:2826 +--- re: ab{1,}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 732: testinput1:2829 +--- re: ab{1,3}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 733: testinput1:2832 +--- re: ab{3,4}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 734: testinput1:2835 +--- re: ab{4,5}?bc +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 735: testinput1:2836 +--- re: ab{4,5}?bc +--- s eval: "ABQ" +--- flags: i + + + +=== TEST 736: testinput1:2837 +--- re: ab{4,5}?bc +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 737: testinput1:2840 +--- re: ab??bc +--- s eval: "ABBC" +--- flags: i + + + +=== TEST 738: testinput1:2841 +--- re: ab??bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 739: testinput1:2844 +--- re: ab{0,1}?bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 740: testinput1:2849 +--- re: ab??c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 741: testinput1:2852 +--- re: ab{0,1}?c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 742: testinput1:2855 +--- re: ^abc$ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 743: testinput1:2856 +--- re: ^abc$ +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 744: testinput1:2857 +--- re: ^abc$ +--- s eval: "ABBBBC" +--- flags: i + + + +=== TEST 745: testinput1:2858 +--- re: ^abc$ +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 746: testinput1:2861 +--- re: ^abc +--- s eval: "ABCC" +--- flags: i + + + +=== TEST 747: testinput1:2866 +--- re: abc$ +--- s eval: "AABC" +--- flags: i + + + +=== TEST 748: testinput1:2869 +--- re: ^ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 749: testinput1:2872 +--- re: $ +--- s eval: "ABC" +--- flags: i + + + +=== TEST 750: testinput1:2875 +--- re: a.c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 751: testinput1:2876 +--- re: a.c +--- s eval: "AXC" +--- flags: i + + + +=== TEST 752: testinput1:2879 +--- re: a.*?c +--- s eval: "AXYZC" +--- flags: i + + + +=== TEST 753: testinput1:2882 +--- re: a.*c +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 754: testinput1:2883 +--- re: a.*c +--- s eval: "AABC" +--- flags: i + + + +=== TEST 755: testinput1:2884 +--- re: a.*c +--- s eval: "AXYZD" +--- flags: i + + + +=== TEST 756: testinput1:2887 +--- re: a[bc]d +--- s eval: "ABD" +--- flags: i + + + +=== TEST 757: testinput1:2890 +--- re: a[b-d]e +--- s eval: "ACE" +--- flags: i + + + +=== TEST 758: testinput1:2891 +--- re: a[b-d]e +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 759: testinput1:2892 +--- re: a[b-d]e +--- s eval: "ABC" +--- flags: i + + + +=== TEST 760: testinput1:2893 +--- re: a[b-d]e +--- s eval: "ABD" +--- flags: i + + + +=== TEST 761: testinput1:2896 +--- re: a[b-d] +--- s eval: "AAC" +--- flags: i + + + +=== TEST 762: testinput1:2899 +--- re: a[-b] +--- s eval: "A-" +--- flags: i + + + +=== TEST 763: testinput1:2902 +--- re: a[b-] +--- s eval: "A-" +--- flags: i + + + +=== TEST 764: testinput1:2905 +--- re: a] +--- s eval: "A]" +--- flags: i + + + +=== TEST 765: testinput1:2908 +--- re: a[]]b +--- s eval: "A]B" +--- flags: i + + + +=== TEST 766: testinput1:2911 +--- re: a[^bc]d +--- s eval: "AED" +--- flags: i + + + +=== TEST 767: testinput1:2914 +--- re: a[^-b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 768: testinput1:2915 +--- re: a[^-b]c +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 769: testinput1:2916 +--- re: a[^-b]c +--- s eval: "ABD" +--- flags: i + + + +=== TEST 770: testinput1:2917 +--- re: a[^-b]c +--- s eval: "A-C" +--- flags: i + + + +=== TEST 771: testinput1:2920 +--- re: a[^]b]c +--- s eval: "ADC" +--- flags: i + + + +=== TEST 772: testinput1:2923 +--- re: ab|cd +--- s eval: "ABC" +--- flags: i + + + +=== TEST 773: testinput1:2924 +--- re: ab|cd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 774: testinput1:2927 +--- re: ()ef +--- s eval: "DEF" +--- flags: i + + + +=== TEST 775: testinput1:2930 +--- re: $b +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 776: testinput1:2931 +--- re: $b +--- s eval: "A]C" +--- flags: i + + + +=== TEST 777: testinput1:2932 +--- re: $b +--- s eval: "B" +--- flags: i + + + +=== TEST 778: testinput1:2935 +--- re: a\(b +--- s eval: "A(B" +--- flags: i + + + +=== TEST 779: testinput1:2938 +--- re: a\(*b +--- s eval: "AB" +--- flags: i + + + +=== TEST 780: testinput1:2939 +--- re: a\(*b +--- s eval: "A((B" +--- flags: i + + + +=== TEST 781: testinput1:2942 +--- re: a\\b +--- s eval: "A\\B" +--- flags: i + + + +=== TEST 782: testinput1:2945 +--- re: ((a)) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 783: testinput1:2948 +--- re: (a)b(c) +--- s eval: "ABC" +--- flags: i + + + +=== TEST 784: testinput1:2951 +--- re: a+b+c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 785: testinput1:2954 +--- re: a{1,}b{1,}c +--- s eval: "AABBABC" +--- flags: i + + + +=== TEST 786: testinput1:2957 +--- re: a.+?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 787: testinput1:2960 +--- re: a.*?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 788: testinput1:2963 +--- re: a.{0,5}?c +--- s eval: "ABCABC" +--- flags: i + + + +=== TEST 789: testinput1:2966 +--- re: (a+|b)* +--- s eval: "AB" +--- flags: i + + + +=== TEST 790: testinput1:2969 +--- re: (a+|b){0,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 791: testinput1:2972 +--- re: (a+|b)+ +--- s eval: "AB" +--- flags: i + + + +=== TEST 792: testinput1:2975 +--- re: (a+|b){1,} +--- s eval: "AB" +--- flags: i + + + +=== TEST 793: testinput1:2978 +--- re: (a+|b)? +--- s eval: "AB" +--- flags: i + + + +=== TEST 794: testinput1:2981 +--- re: (a+|b){0,1} +--- s eval: "AB" +--- flags: i + + + +=== TEST 795: testinput1:2984 +--- re: (a+|b){0,1}? +--- s eval: "AB" +--- flags: i + + + +=== TEST 796: testinput1:2987 +--- re: [^ab]* +--- s eval: "CDE" +--- flags: i + + + +=== TEST 797: testinput1:2995 +--- re: ([abc])*d +--- s eval: "ABBBCD" +--- flags: i + + + +=== TEST 798: testinput1:2998 +--- re: ([abc])*bcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 799: testinput1:3001 +--- re: a|b|c|d|e +--- s eval: "E" +--- flags: i + + + +=== TEST 800: testinput1:3004 +--- re: (a|b|c|d|e)f +--- s eval: "EF" +--- flags: i + + + +=== TEST 801: testinput1:3007 +--- re: abcd*efg +--- s eval: "ABCDEFG" +--- flags: i + + + +=== TEST 802: testinput1:3010 +--- re: ab* +--- s eval: "XABYABBBZ" +--- flags: i + + + +=== TEST 803: testinput1:3011 +--- re: ab* +--- s eval: "XAYABBBZ" +--- flags: i + + + +=== TEST 804: testinput1:3014 +--- re: (ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 805: testinput1:3017 +--- re: [abhgefdc]ij +--- s eval: "HIJ" +--- flags: i + + + +=== TEST 806: testinput1:3020 +--- re: ^(ab|cd)e +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 807: testinput1:3023 +--- re: (abc|)ef +--- s eval: "ABCDEF" +--- flags: i + + + +=== TEST 808: testinput1:3026 +--- re: (a|b)c*d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 809: testinput1:3029 +--- re: (ab|ab*)bc +--- s eval: "ABC" +--- flags: i + + + +=== TEST 810: testinput1:3032 +--- re: a([bc]*)c* +--- s eval: "ABC" +--- flags: i + + + +=== TEST 811: testinput1:3035 +--- re: a([bc]*)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 812: testinput1:3038 +--- re: a([bc]+)(c*d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 813: testinput1:3041 +--- re: a([bc]*)(c+d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 814: testinput1:3044 +--- re: a[bcd]*dcdcde +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 815: testinput1:3049 +--- re: (ab|a)b*c +--- s eval: "ABC" +--- flags: i + + + +=== TEST 816: testinput1:3052 +--- re: ((a)(b)c)(d) +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 817: testinput1:3055 +--- re: [a-zA-Z_][a-zA-Z0-9_]* +--- s eval: "ALPHA" +--- flags: i + + + +=== TEST 818: testinput1:3058 +--- re: ^a(bc+|b[eh])g|.h$ +--- s eval: "ABH" +--- flags: i + + + +=== TEST 819: testinput1:3061 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFGZ" +--- flags: i + + + +=== TEST 820: testinput1:3062 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "IJ" +--- flags: i + + + +=== TEST 821: testinput1:3063 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "REFFGZ" +--- flags: i + + + +=== TEST 822: testinput1:3064 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 823: testinput1:3065 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "ADCDCDE" +--- flags: i + + + +=== TEST 824: testinput1:3066 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "EFFG" +--- flags: i + + + +=== TEST 825: testinput1:3067 +--- re: (bc+d$|ef*g.|h?i(j|k)) +--- s eval: "BCDD" +--- flags: i + + + +=== TEST 826: testinput1:3070 +--- re: ((((((((((a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 827: testinput1:3076 +--- re: (((((((((a))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 828: testinput1:3079 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a)))))))))) +--- s eval: "A" +--- flags: i + + + +=== TEST 829: testinput1:3082 +--- re: (?:(?:(?:(?:(?:(?:(?:(?:(?:(a|b|c)))))))))) +--- s eval: "C" +--- flags: i + + + +=== TEST 830: testinput1:3085 +--- re: multiple words of text +--- s eval: "*** Failers" +--- flags: i + + + +=== TEST 831: testinput1:3086 +--- re: multiple words of text +--- s eval: "AA" +--- flags: i + + + +=== TEST 832: testinput1:3087 +--- re: multiple words of text +--- s eval: "UH-UH" +--- flags: i + + + +=== TEST 833: testinput1:3090 +--- re: multiple words +--- s eval: "MULTIPLE WORDS, YEAH" +--- flags: i + + + +=== TEST 834: testinput1:3093 +--- re: (.*)c(.*) +--- s eval: "ABCDE" +--- flags: i + + + +=== TEST 835: testinput1:3096 +--- re: \((.*), (.*)\) +--- s eval: "(A, B)" +--- flags: i + + + +=== TEST 836: testinput1:3101 +--- re: abcd +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 837: testinput1:3104 +--- re: a(bc)d +--- s eval: "ABCD" +--- flags: i + + + +=== TEST 838: testinput1:3107 +--- re: a[-]?c +--- s eval: "AC" +--- flags: i + + + +=== TEST 839: testinput1:3125 +--- re: a(?:b|c|d)(.) +--- s eval: "ace" + + + +=== TEST 840: testinput1:3128 +--- re: a(?:b|c|d)*(.) +--- s eval: "ace" + + + +=== TEST 841: testinput1:3131 +--- re: a(?:b|c|d)+?(.) +--- s eval: "ace" + + + +=== TEST 842: testinput1:3132 +--- re: a(?:b|c|d)+?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 843: testinput1:3135 +--- re: a(?:b|c|d)+(.) +--- s eval: "acdbcdbe" + + + +=== TEST 844: testinput1:3138 +--- re: a(?:b|c|d){2}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 845: testinput1:3141 +--- re: a(?:b|c|d){4,5}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 846: testinput1:3144 +--- re: a(?:b|c|d){4,5}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 847: testinput1:3147 +--- re: ((foo)|(bar))* +--- s eval: "foobar" + + + +=== TEST 848: testinput1:3150 +--- re: a(?:b|c|d){6,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 849: testinput1:3153 +--- re: a(?:b|c|d){6,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 850: testinput1:3156 +--- re: a(?:b|c|d){5,6}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 851: testinput1:3159 +--- re: a(?:b|c|d){5,6}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 852: testinput1:3162 +--- re: a(?:b|c|d){5,7}(.) +--- s eval: "acdbcdbe" + + + +=== TEST 853: testinput1:3165 +--- re: a(?:b|c|d){5,7}?(.) +--- s eval: "acdbcdbe" + + + +=== TEST 854: testinput1:3168 +--- re: a(?:b|(c|e){1,2}?|d)+?(.) +--- s eval: "ace" + + + +=== TEST 855: testinput1:3171 +--- re: ^(.+)?B +--- s eval: "AB" + + + +=== TEST 856: testinput1:3174 +--- re: ^([^a-z])|(\^)$ +--- s eval: "." + + + +=== TEST 857: testinput1:3177 +--- re: ^[<>]& +--- s eval: "<&OUT" + + + +=== TEST 858: testinput1:3193 +--- re: (?:(f)(o)(o)|(b)(a)(r))* +--- s eval: "foobar" + + + +=== TEST 859: testinput1:3207 +--- re: (?:..)*a +--- s eval: "aba" + + + +=== TEST 860: testinput1:3210 +--- re: (?:..)*?a +--- s eval: "aba" + + + +=== TEST 861: testinput1:3216 +--- re: ^(){3,5} +--- s eval: "abc" + + + +=== TEST 862: testinput1:3219 +--- re: ^(a+)*ax +--- s eval: "aax" + + + +=== TEST 863: testinput1:3222 +--- re: ^((a|b)+)*ax +--- s eval: "aax" + + + +=== TEST 864: testinput1:3225 +--- re: ^((a|bc)+)*ax +--- s eval: "aax" + + + +=== TEST 865: testinput1:3228 +--- re: (a|x)*ab +--- s eval: "cab" + + + +=== TEST 866: testinput1:3231 +--- re: (a)*ab +--- s eval: "cab" + + + +=== TEST 867: testinput1:3344 +--- re: (?:c|d)(?:)(?:a(?:)(?:b)(?:b(?:))(?:b(?:)(?:b))) +--- s eval: "cabbbb" + + + +=== TEST 868: testinput1:3347 +--- re: (?:c|d)(?:)(?:aaaaaaaa(?:)(?:bbbbbbbb)(?:bbbbbbbb(?:))(?:bbbbbbbb(?:)(?:bbbbbbbb))) +--- s eval: "caaaaaaaabbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + + + +=== TEST 869: testinput1:3354 +--- re: foo\w*\d{4}baz +--- s eval: "foobar1234baz" + + + +=== TEST 870: testinput1:3357 +--- re: x(~~)*(?:(?:F)?)? +--- s eval: "x~~" + + + +=== TEST 871: testinput1:3382 +--- re: ^(?:a?b?)*$ +--- s eval: "" + + + +=== TEST 872: testinput1:3383 +--- re: ^(?:a?b?)*$ +--- s eval: "a" + + + +=== TEST 873: testinput1:3384 +--- re: ^(?:a?b?)*$ +--- s eval: "ab" + + + +=== TEST 874: testinput1:3385 +--- re: ^(?:a?b?)*$ +--- s eval: "aaa " + + + +=== TEST 875: testinput1:3386 +--- re: ^(?:a?b?)*$ +--- s eval: "*** Failers" + + + +=== TEST 876: testinput1:3387 +--- re: ^(?:a?b?)*$ +--- s eval: "dbcb" + + + +=== TEST 877: testinput1:3388 +--- re: ^(?:a?b?)*$ +--- s eval: "a--" + + + +=== TEST 878: testinput1:3389 +--- re: ^(?:a?b?)*$ +--- s eval: "aa-- " + + + +=== TEST 879: testinput1:3420 +--- re: ()^b +--- s eval: "*** Failers" + + + +=== TEST 880: testinput1:3421 +--- re: ()^b +--- s eval: "a\nb\nc\n" + + + +=== TEST 881: testinput1:3477 +--- re: (\w+:)+ +--- s eval: "one:" + + + +=== TEST 882: testinput1:3491 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd" + + + +=== TEST 883: testinput1:3492 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "xy:z:::abcd" + + + +=== TEST 884: testinput1:3495 +--- re: ^[^bcd]*(c+) +--- s eval: "aexycd" + + + +=== TEST 885: testinput1:3498 +--- re: (a*)b+ +--- s eval: "caab" + + + +=== TEST 886: testinput1:3503 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "*** Failers" + + + +=== TEST 887: testinput1:3504 +--- re: ([\w:]+::)?(\w+)$ +--- s eval: "abcd:" + + + +=== TEST 888: testinput1:3516 +--- re: ([[:]+) +--- s eval: "a:[b]:" + + + +=== TEST 889: testinput1:3519 +--- re: ([[=]+) +--- s eval: "a=[b]=" + + + +=== TEST 890: testinput1:3522 +--- re: ([[.]+) +--- s eval: "a.[b]." + + + +=== TEST 891: testinput1:3547 +--- re: b\z +--- s eval: "a\nb" + + + +=== TEST 892: testinput1:3548 +--- re: b\z +--- s eval: "*** Failers" + + + +=== TEST 893: testinput1:3640 +--- re: ((Z)+|A)* +--- s eval: "ZABCDEFG" + + + +=== TEST 894: testinput1:3643 +--- re: (Z()|A)* +--- s eval: "ZABCDEFG" + + + +=== TEST 895: testinput1:3646 +--- re: (Z(())|A)* +--- s eval: "ZABCDEFG" + + + +=== TEST 896: testinput1:3655 +--- re: a* +--- s eval: "abbab" + + + +=== TEST 897: testinput1:3658 +--- re: ^[a-\d] +--- s eval: "abcde" + + + +=== TEST 898: testinput1:3659 +--- re: ^[a-\d] +--- s eval: "-things" + + + +=== TEST 899: testinput1:3660 +--- re: ^[a-\d] +--- s eval: "0digit" + + + +=== TEST 900: testinput1:3661 +--- re: ^[a-\d] +--- s eval: "*** Failers" + + + +=== TEST 901: testinput1:3662 +--- re: ^[a-\d] +--- s eval: "bcdef " + + + +=== TEST 902: testinput1:3665 +--- re: ^[\d-a] +--- s eval: "abcde" + + + +=== TEST 903: testinput1:3666 +--- re: ^[\d-a] +--- s eval: "-things" + + + +=== TEST 904: testinput1:3667 +--- re: ^[\d-a] +--- s eval: "0digit" + + + +=== TEST 905: testinput1:3668 +--- re: ^[\d-a] +--- s eval: "*** Failers" + + + +=== TEST 906: testinput1:3669 +--- re: ^[\d-a] +--- s eval: "bcdef " + + + +=== TEST 907: testinput1:3678 +--- re: [\s]+ +--- s eval: "> \x09\x0a\x0c\x0d\x0b<" +--- cap: (1, 6) + + + +=== TEST 908: testinput1:3681 +--- re: \s+ +--- s eval: "> \x09\x0a\x0c\x0d\x0b<" +--- cap: (1, 6) + + + +=== TEST 909: testinput1:3684 +--- re: a b +--- s eval: "ab" + + + +=== TEST 910: testinput1:3739 +--- re: abc. +--- s eval: "abc1abc2xyzabc3 " + + + +=== TEST 911: testinput1:3819 +--- re: \M +--- s eval: "M " + + + +=== TEST 912: testinput1:3822 +--- re: (a+)*b +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa " + + + +=== TEST 913: testinput1:3831 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 914: testinput1:3832 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 915: testinput1:3833 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 916: testinput1:3834 +--- re: [--]+ +--- s eval: "" + + + +=== TEST 917: testinput1:3863 +--- re: ^ +--- s eval: "a\nb\nc\n" + + + +=== TEST 918: testinput1:3864 +--- re: ^ +--- s eval: "\ " + + + +=== TEST 919: testinput1:3880 +--- re: [[,abc,]+] +--- s eval: "abc]" + + + +=== TEST 920: testinput1:3881 +--- re: [[,abc,]+] +--- s eval: "a,b]" + + + +=== TEST 921: testinput1:3882 +--- re: [[,abc,]+] +--- s eval: "[a,b,c] " + + + +=== TEST 922: testinput1:3899 +--- re: a*b*\w +--- s eval: "aaabbbb" + + + +=== TEST 923: testinput1:3900 +--- re: a*b*\w +--- s eval: "aaaa" + + + +=== TEST 924: testinput1:3901 +--- re: a*b*\w +--- s eval: "a" + + + +=== TEST 925: testinput1:3904 +--- re: a*b?\w +--- s eval: "aaabbbb" + + + +=== TEST 926: testinput1:3905 +--- re: a*b?\w +--- s eval: "aaaa" + + + +=== TEST 927: testinput1:3906 +--- re: a*b?\w +--- s eval: "a" + + + +=== TEST 928: testinput1:3909 +--- re: a*b{0,4}\w +--- s eval: "aaabbbb" + + + +=== TEST 929: testinput1:3910 +--- re: a*b{0,4}\w +--- s eval: "aaaa" + + + +=== TEST 930: testinput1:3911 +--- re: a*b{0,4}\w +--- s eval: "a" + + + +=== TEST 931: testinput1:3914 +--- re: a*b{0,}\w +--- s eval: "aaabbbb" + + + +=== TEST 932: testinput1:3915 +--- re: a*b{0,}\w +--- s eval: "aaaa" + + + +=== TEST 933: testinput1:3916 +--- re: a*b{0,}\w +--- s eval: "a" + + + +=== TEST 934: testinput1:3919 +--- re: a*\d*\w +--- s eval: "0a" + + + +=== TEST 935: testinput1:3920 +--- re: a*\d*\w +--- s eval: "a " + + + +=== TEST 936: testinput1:3923 +--- re: a*b *\w +--- s eval: "a " + + + +=== TEST 937: testinput1:3930 +--- re: a* b *\w +--- s eval: "a " + + + +=== TEST 938: testinput1:3933 +--- re: ^\w+=.*(\\\n.*)* +--- s eval: "abc=xyz\\\npqr" + + + +=== TEST 939: testinput1:3976 +--- re: ^(a()*)* +--- s eval: "aaaa" + + + +=== TEST 940: testinput1:3979 +--- re: ^(?:a(?:(?:))*)* +--- s eval: "aaaa" + + + +=== TEST 941: testinput1:3982 +--- re: ^(a()+)+ +--- s eval: "aaaa" + + + +=== TEST 942: testinput1:3985 +--- re: ^(?:a(?:(?:))+)+ +--- s eval: "aaaa" + + + +=== TEST 943: testinput1:3993 +--- re: (a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 944: testinput1:3994 +--- re: (a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4" +--- cap: (0, 61) (59, 60) + + + +=== TEST 945: testinput1:4001 +--- re: (?:a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + + + +=== TEST 946: testinput1:4002 +--- re: (?:a|)*\d +--- s eval: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4" + + + +=== TEST 947: testinput1:4020 +--- re: (.*(.)?)* +--- s eval: "abcd" +--- cap: (0, 4) (0, 4) + + + +=== TEST 948: testinput1:4032 +--- re: [[:abcd:xyz]] +--- s eval: "a]" + + + +=== TEST 949: testinput1:4033 +--- re: [[:abcd:xyz]] +--- s eval: ":] " + + + +=== TEST 950: testinput1:4036 +--- re: [abc[:x\]pqr] +--- s eval: "a" + + + +=== TEST 951: testinput1:4037 +--- re: [abc[:x\]pqr] +--- s eval: "[" + + + +=== TEST 952: testinput1:4038 +--- re: [abc[:x\]pqr] +--- s eval: ":" + + + +=== TEST 953: testinput1:4039 +--- re: [abc[:x\]pqr] +--- s eval: "]" + + + +=== TEST 954: testinput1:4040 +--- re: [abc[:x\]pqr] +--- s eval: "p " + + + +=== TEST 955: testinput1:4043 +--- re: .*[op][xyz] +--- s eval: "fooabcfoo" + + + +=== TEST 956: testinput1:4078 +--- re: [\x00-\xff\s]+ +--- s eval: "\x0a\x0b\x0c\x0d" + + + +=== TEST 957: testinput1:4090 +--- re: [^a]* +--- s eval: "12abc" +--- flags: i + + + +=== TEST 958: testinput1:4091 +--- re: [^a]* +--- s eval: "12ABC" +--- flags: i + + + +=== TEST 959: testinput1:4098 +--- re: [^a]*?X +--- s eval: "** Failers" +--- flags: i + + + +=== TEST 960: testinput1:4099 +--- re: [^a]*?X +--- s eval: "12abc" +--- flags: i + + + +=== TEST 961: testinput1:4100 +--- re: [^a]*?X +--- s eval: "12ABC" +--- flags: i + + + +=== TEST 962: testinput1:4103 +--- re: [^a]+?X +--- s eval: "** Failers" +--- flags: i + + + +=== TEST 963: testinput1:4104 +--- re: [^a]+?X +--- s eval: "12abc" +--- flags: i + + + +=== TEST 964: testinput1:4105 +--- re: [^a]+?X +--- s eval: "12ABC" +--- flags: i + + + +=== TEST 965: testinput1:4108 +--- re: [^a]?X +--- s eval: "12aXbcX" +--- flags: i + + + +=== TEST 966: testinput1:4109 +--- re: [^a]?X +--- s eval: "12AXBCX" +--- flags: i + + + +=== TEST 967: testinput1:4110 +--- re: [^a]?X +--- s eval: "BCX " +--- flags: i + + + +=== TEST 968: testinput1:4113 +--- re: [^a]??X +--- s eval: "12aXbcX" +--- flags: i + + + +=== TEST 969: testinput1:4114 +--- re: [^a]??X +--- s eval: "12AXBCX" +--- flags: i + + + +=== TEST 970: testinput1:4115 +--- re: [^a]??X +--- s eval: "BCX" +--- flags: i + + + +=== TEST 971: testinput1:4123 +--- re: [^a]{2,3} +--- s eval: "abcdef" +--- flags: i + + + +=== TEST 972: testinput1:4124 +--- re: [^a]{2,3} +--- s eval: "ABCDEF " +--- flags: i + + + +=== TEST 973: testinput1:4127 +--- re: [^a]{2,3}? +--- s eval: "abcdef" +--- flags: i + + + +=== TEST 974: testinput1:4128 +--- re: [^a]{2,3}? +--- s eval: "ABCDEF " +--- flags: i + + + +=== TEST 975: testinput1:4135 +--- re: ((a|)+)+Z +--- s eval: "Z" + + + +=== TEST 976: testinput1:4138 +--- re: (a)b|(a)c +--- s eval: "ac" + + + +=== TEST 977: testinput1:4177 +--- re: (?:a+|ab)+c +--- s eval: "aabc" + + + +=== TEST 978: testinput1:4192 +--- re: ^(?:a|ab)+c +--- s eval: "aaaabc" + + + +=== TEST 979: testinput1:4253 +--- re: [:a]xxx[b:] +--- s eval: ":xxx:" + + + +=== TEST 980: testinput1:4323 +--- re: \H\h\V\v +--- s eval: "X X\x0a" + + + +=== TEST 981: testinput1:4324 +--- re: \H\h\V\v +--- s eval: "X\x09X\x0b" + + + +=== TEST 982: testinput1:4325 +--- re: \H\h\V\v +--- s eval: "** Failers" + + + +=== TEST 983: testinput1:4326 +--- re: \H\h\V\v +--- s eval: "\xa0 X\x0a " + + + +=== TEST 984: testinput1:4329 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0X\x0a\x0b\x0c\x0d\x0a" + + + +=== TEST 985: testinput1:4330 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0\x0a\x0b\x0c\x0d\x0a" + + + +=== TEST 986: testinput1:4331 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0\x0a\x0b\x0c" + + + +=== TEST 987: testinput1:4332 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "** Failers " + + + +=== TEST 988: testinput1:4333 +--- re: \H*\h+\V?\v{3,4} +--- s eval: "\x09\x20\xa0\x0a\x0b" + + + +=== TEST 989: testinput1:4336 +--- re: \H{3,4} +--- s eval: "XY ABCDE" + + + +=== TEST 990: testinput1:4337 +--- re: \H{3,4} +--- s eval: "XY PQR ST " + + + +=== TEST 991: testinput1:4340 +--- re: .\h{3,4}. +--- s eval: "XY AB PQRS" + + + +=== TEST 992: testinput1:4343 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: ">XNNNYZ" + + + +=== TEST 993: testinput1:4344 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: "> X NYQZ" + + + +=== TEST 994: testinput1:4345 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: "** Failers" + + + +=== TEST 995: testinput1:4346 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: ">XYZ " + + + +=== TEST 996: testinput1:4347 +--- re: \h*X\h?\H+Y\H?Z +--- s eval: "> X NY Z" + + + +=== TEST 997: testinput1:4350 +--- re: \v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c +--- s eval: ">XY\x0aZ\x0aA\x0bNN\x0c" + + + +=== TEST 998: testinput1:4351 +--- re: \v*X\v?Y\v+Z\V*\x0a\V+\x0b\V{2,3}\x0c +--- s eval: ">\x0a\x0dX\x0aY\x0a\x0bZZZ\x0aAAA\x0bNNN\x0c" + + + +=== TEST 999: testinput1:4906 +--- re: \A.*?(?:a|bc) +--- s eval: "ba" + + + +=== TEST 1000: testinput1:4912 +--- re: \A.*?(a|bc) +--- s eval: "ba" + + + +=== TEST 1001: testinput1:4930 +--- re: \A.*?(?:a|bc|d) +--- s eval: "ba" + + + +=== TEST 1002: testinput1:4954 +--- re: ^\N+ +--- s eval: "abc\ndef" + + + +=== TEST 1003: testinput1:5260 +--- re: ((?:a?)*)*c +--- s eval: "aac " +--- cap: (0, 3) (0, 2) + diff --git a/lib/sregex/t/04-multi.t b/lib/sregex/t/04-multi.t new file mode 100644 index 0000000..ab133d9 --- /dev/null +++ b/lib/sregex/t/04-multi.t @@ -0,0 +1,122 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: +--- re eval: ["a", "ab"] +--- s: bah +--- cap: (1, 2) +--- match_id: 0 + + + +=== TEST 2: +--- re eval: ["a", "ab"] +--- s: bab +--- cap: (1, 2) +--- match_id: 0 + + + +=== TEST 3: +--- re eval: ["c", "ab"] +--- s: babc +--- cap: (1, 3) +--- match_id: 1 + + + +=== TEST 4: submatches +--- re eval: ["a(bc)", "e(f)"] +--- s: babc +--- cap: (1, 4) (2, 4) +--- match_id: 0 + + + +=== TEST 5: submatches +--- re eval: ["a(bc)", "e(f)", "gh"] +--- s: bef +--- cap: (1, 3) (2, 3) +--- match_id: 1 + + + +=== TEST 6: submatches +--- re eval: ["a(bc)", "e(f)", "gh"] +--- s: gh +--- cap eval: qr/^\(0, 2\)/ +--- match_id: 2 + + + +=== TEST 7: submatches +--- re eval: ["A", "A"] +--- s: ga +--- cap: (1, 2) +--- flags eval: " i" +--- match_id: 1 + + + +=== TEST 8: submatches +--- re eval: ["A", "A"] +--- s: ga +--- cap: (1, 2) +--- flags eval: "i i" +--- match_id: 0 + + + +=== TEST 9: not matched +--- re eval: ["a", "b"] +--- s: cde +--- flags eval: "i i" +--- no_match + + + +=== TEST 10: temp captures +--- re eval: ['BLAH', '\s+'] +--- s eval: "abc \t\n\f\rd" +--- cap: (3, 8) +--- match_id: 1 +--- temp_cap chop +[(1, -1)] [(2, -1)] [(3, -1)] [(3, -1)](3, 4) [(3, -1)](3, 5) [(3, -1)](3, 6) [(3, -1)](3, 7) [(3, -1)](3, 8) + + + +=== TEST 11: syntax error at 2nd regex +--- re eval: ['BLAH', '(ab'] +--- s eval: "abc \t\n\f\rd" +--- err +[error] regex 1: syntax error at pos 3 + + + +=== TEST 12: syntax error at 1st regex +--- re eval: ['(abc', 'BLAH'] +--- s eval: "abc \t\n\f\rd" +--- err +[error] regex 0: syntax error at pos 4 + + + +=== TEST 13: ambiguity patterns (1st matched) +--- re eval: ['abcd', 'bc'] +--- s eval: "abcd" +--- cap: (0, 4) +--- temp_cap: [(0, -1)] [(0, -1)] [(0, -1)](1, 3) + + + +=== TEST 14: ambiguity patterns (2nd matched) +--- re eval: ['abcd', 'bc'] +--- s eval: "abce" +--- cap: (1, 3) +--- temp_cap: [(0, -1)] [(0, -1)] [(0, -1)](1, 3) + diff --git a/lib/sregex/t/05-bugs.t b/lib/sregex/t/05-bugs.t new file mode 100644 index 0000000..d39d4e9 --- /dev/null +++ b/lib/sregex/t/05-bugs.t @@ -0,0 +1,46 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +=== TEST 1: integer overflow in \ddd +--- re: \777 +--- s eval: "\377" +--- err +[error] syntax error at pos 0 + + + +=== TEST 2: integer overflow in \ddd (char class) +--- re: [\777] +--- s eval: "\377" +--- err +[error] syntax error at pos 0 + + + +=== TEST 3: integer overflow in \o{ddd} +--- re: \o{777} +--- s eval: "\377" +--- err +[error] syntax error at pos 0 + + + +=== TEST 4: integer overflow in \o{ddd} (char class) +--- re: [\o{777}] +--- s eval: "\377" +--- err +[error] syntax error at pos 0 + + + +=== TEST 5: integer overflow in \x{ddd} +--- re: \x{100} +--- s eval: "\377" +--- err +[error] syntax error at pos 0 + diff --git a/lib/sregex/t/SRegex.pm b/lib/sregex/t/SRegex.pm new file mode 100644 index 0000000..977fc98 --- /dev/null +++ b/lib/sregex/t/SRegex.pm @@ -0,0 +1,467 @@ +package t::SRegex; + + +use 5.016002; +use bytes; +use Test::Base -Base; +use IPC::Run3; +use Cwd; +use Test::LongString; + + +sub run_test ($); +sub parse_res ($); +sub fmt_cap ($$); + + +our @EXPORT = qw( run_tests ); + +our $UseValgrind = $ENV{TEST_SREGEX_USE_VALGRIND}; +our $ForceMultiRegexes = $ENV{TEST_SREGEX_FORCE_MULTI_REGEXES}; + +sub run_tests { + for my $block (blocks()) { + run_test($block); + } +} + + +sub run_test ($) { + my $block = shift; + #print $json_xs->pretty->encode(\@new_rows); + #my $res = #print $json_xs->pretty->encode($res); + my $name = $block->name; + + my $s = $block->s; + if (!defined $s) { + die "No --- s specified for test $name\n"; + } + + my $re = $block->re; + if (!defined $re) { + die "No --- re specified for test $name\n"; + } + + if (!ref $re && $ForceMultiRegexes) { + $re = ['^章亦春$', $re]; + } + + my $flags = $block->flags; + + #warn "flags: $flags\n"; + + my ($prefix, @opts); + if ($flags) { + $prefix = "(?$flags)"; + #warn "prefix: $prefix\n"; + push @opts, "--flags", $flags; + + } else { + $prefix = ""; + } + + if (ref $re) { + push @opts, "-n", scalar @$re; + + if ($flags && @$re == 2 && $re->[0] eq '^章亦春$') { + push @opts, "--flags", " $flags"; + } + } + + my ($res, $err); + + my $stdin = bytes::length($s) . "\n$s"; + + my @cmd = ("./sregex-cli", "--stdin", @opts, ref $re ? @$re : $re); + + if ($UseValgrind) { + warn "$name\n"; + @cmd = ('valgrind', '--gen-suppressions=all', + '--suppressions=valgrind.suppress', + '--show-possibly-lost=no', '-q', '--leak-check=full', @cmd); + } + + run3 \@cmd, \$stdin, \$res, \$err; + + #warn "res:$res\nerr:$err\n"; + + if (defined $block->err) { + $err =~ /\[error\] .*\n/; + $err = $&; + + if (ref $re && @$re == 2 && $re->[0] eq '^章亦春$') { + $err =~ s/regex \d+:\s+//; + } + + is $err, $block->err, "$name - err expected (regex: \"$re\")"; + + } elsif (defined $block->err_like) { + $err =~ /\[error\] .*\n/; + $err = $&; + + if (ref $re && @$re == 2 && $re->[0] eq '^章亦春$') { + $err =~ s/regex \d+:\s+//; + } + + my $re = $block->err_like; + like $err, qr/$re/, "$name - err_like expected (regex: \"$re\")"; + + } elsif ($?) { + if (defined $block->fatal) { + pass("failed as expected"); + + } else { + fail("failed to execute --- re for test $name: $err\n"); + return; + } + + } else { + if ($err) { + if (!defined $block->err) { + warn "$err\n"; + + } else { + is $err, $block->err, "$name - err ok"; + } + } + + #is $res, $block->out, "$name - output ok"; + if (!defined $res) { + is_string $res, $block->out, "$name - output ok"; + + } else { + + my ($thompson_match, $jitted_thompson_match, $splitted_jitted_thompson_match, + $splitted_thompson_match, $pike_match, $pike_cap, + $splitted_pike_match, $splitted_pike_cap, $splitted_pike_temp_cap, + $pike_re_id, $splitted_pike_re_id) + = parse_res($res); + + if ($ENV{TEST_SREGEX_VERBOSE}) { + my $cap = $pike_cap; + if (!defined $cap) { + $cap = ''; + } + if (!defined $pike_match) { + $pike_match = ''; + } + warn "$name - thompson: $thompson_match, pike: $pike_match, cap: $cap\n"; + warn $res; + } + + if (ref $re && @$re == 2 && $re->[0] eq '^章亦春$') { + $re = pop @$re; + } + + no warnings 'regexp'; + no warnings 'syntax'; + no warnings 'deprecated'; + + if (!ref $re && !defined $block->no_match && !defined $block->cap) { + eval { + $s =~ m/$prefix$re/sm; + }; + + if ($@) { + fail("$name - bad regex: $re: $@"); + return; + } + } + + if (defined $block->cap || defined $block->no_match) { + my $expected_cap = $block->cap; + + if (defined $block->no_match) { + ok(!$thompson_match, "$name - thompson vm should not match"); + + } else { + ok($thompson_match, "$name - thompson vm should match"); + } + + SKIP: { + skip "Thompson JIT disabled", 1 if $jitted_thompson_match == -1; + if (defined $block->no_match) { + ok(!$jitted_thompson_match, "$name - jitted thompson vm should not match"); + } else { + ok($jitted_thompson_match, "$name - jitted thompson vm should match"); + } + } + + SKIP: { + skip "Thompson JIT disabled", 1 if $splitted_jitted_thompson_match == -1; + if (defined $block->no_match) { + ok(!$splitted_jitted_thompson_match, "$name - splitted jitted thompson vm should not match"); + + } else { + ok($splitted_jitted_thompson_match, "$name - splitted jitted thompson vm should match"); + } + } + + if (defined $block->no_match) { + ok(!$splitted_thompson_match, "$name - splitted thompson vm should not match"); + ok(!$pike_match, "$name - pike vm should not match"); + } else { + ok($splitted_thompson_match, "$name - splitted thompson vm should match"); + ok($pike_match, "$name - pike vm should match"); + } + + if (defined $block->match_id) { + is $pike_re_id, $block->match_id, "$name - pike match id ok"; + } + + if (defined $expected_cap) { + if (ref $expected_cap) { + like($pike_cap, $expected_cap, "$name - pike vm capture ok"); + + } else { + is($pike_cap, $expected_cap, "$name - pike vm capture ok"); + } + } + + if (defined $block->no_match) { + ok(!$splitted_pike_match, "$name - splitted pike vm should not match"); + } else { + ok($splitted_pike_match, "$name - splitted pike vm should match"); + } + + if (defined $block->match_id) { + is $splitted_pike_re_id, $block->match_id, "$name - splitted pike match id ok"; + } + + if (ref $expected_cap) { + like($pike_cap, $expected_cap, "$name - pike vm capture ok"); + + } else { + is($splitted_pike_cap, $expected_cap, "$name - splitted pike vm capture ok"); + } + + if (defined $block->temp_cap) { + is($splitted_pike_temp_cap, $block->temp_cap, "$name - splitted pike vm temporary capture ok"); + } + + } elsif ($s =~ m/$prefix$re/sm) { + my $expected_cap = fmt_cap(\@-, \@+); + + #warn "regex: $prefix$re"; + + ok($thompson_match, "$name - thompson vm should match"); + + SKIP: { + skip "Thompson JIT disabled", 1 if $jitted_thompson_match == -1; + ok($jitted_thompson_match, "$name - jitted thompson vm should match"); + } + + SKIP: { + skip "Thompson JIT disabled", 1 if $splitted_jitted_thompson_match == -1; + ok($splitted_jitted_thompson_match, "$name - splitted jitted thompson vm should match"); + } + + ok($splitted_thompson_match, "$name - splitted thompson vm should match"); + + ok($pike_match, "$name - pike vm should match"); + is($pike_cap, $expected_cap, "$name - pike vm capture ok"); + + ok($splitted_pike_match, "$name - splitted pike vm should match"); + is($splitted_pike_cap, $expected_cap, "$name - splitted pike vm capture ok"); + + if (defined $block->temp_cap) { + is($splitted_pike_temp_cap, $block->temp_cap, "$name - splitted pike vm temporary capture ok"); + } + + } else { + ok(!$thompson_match, "$name - thompson vm should not match"); + + SKIP: { + skip "Thompson JIT disabled", 1 if $jitted_thompson_match == -1; + ok(!$jitted_thompson_match, "$name - jitted thompson vm should not match"); + } + + SKIP: { + skip "Thompson JIT disabled", 1 if $splitted_jitted_thompson_match == -1; + ok(!$splitted_jitted_thompson_match, "$name - splitted jitted thompson vm should not match"); + } + + ok(!$splitted_thompson_match, "$name - splitted thompson vm should not match"); + ok(!$pike_match, "$name - pike vm should not match"); + ok(!$splitted_pike_match, "$name - splitted pike vm should not match"); + } + } + } +} + + +sub parse_res ($) { + my $res = shift; + open my $in, '<', \$res or die $!; + + my ($thompson_match, $jitted_thompson_match, $splitted_jitted_thompson_match, + $splitted_thompson_match, $pike_match, $pike_cap, + $splitted_pike_match, $splitted_pike_cap, $splitted_pike_temp_cap, + $pike_re_id, $splitted_pike_re_id); + + while (<$in>) { + if (/^thompson (.+)/) { + my $res = $1; + + if (defined $thompson_match) { + warn "duplicate thompson result: $_"; + next; + } + + if ($res eq 'match') { + $thompson_match = 1; + + } elsif ($res eq 'no match') { + $thompson_match = 0; + + } else { + warn "unknown thompson result: $res\n"; + $thompson_match = 0; + } + + } elsif (/^jitted thompson (.+)/) { + my $res = $1; + + if (defined $jitted_thompson_match) { + warn "duplicate jitted thompson result: $_"; + next; + } + + if ($res eq 'match') { + $jitted_thompson_match = 1; + + } elsif ($res eq 'no match') { + $jitted_thompson_match = 0; + + } elsif ($res eq 'disabled') { + $jitted_thompson_match = -1; + + } else { + warn "unknown jitted thompson result: $res\n"; + $jitted_thompson_match = 0; + } + + } elsif (/^splitted jitted thompson (.+)/) { + my $res = $1; + + if (defined $splitted_jitted_thompson_match) { + warn "duplicate splitted jitted thompson result: $_"; + next; + } + + if ($res eq 'match') { + $splitted_jitted_thompson_match = 1; + + } elsif ($res eq 'no match') { + $splitted_jitted_thompson_match = 0; + + } elsif ($res eq 'disabled') { + $splitted_jitted_thompson_match = -1; + + } else { + warn "unknown splitted jitted thompson result: $res\n"; + $splitted_jitted_thompson_match = 0; + } + + } elsif (/^splitted thompson (.+)/) { + my $res = $1; + + if (defined $splitted_thompson_match) { + warn "duplicate splitted thompson result: $_"; + next; + } + + if ($res eq 'match') { + $splitted_thompson_match = 1; + + } elsif ($res eq 'no match') { + $splitted_thompson_match = 0; + + } else { + warn "unknown splitted thompson result: $res\n"; + $splitted_thompson_match = 0; + } + + } elsif (/^pike (.+)/) { + my $res = $1; + + if (defined $pike_match) { + warn "duplicate pike result: $_"; + next; + } + + if ($res eq 'no match') { + $pike_match = 0; + + } elsif ($res =~ /^match (\d+) (.+)/) { + $pike_re_id = $1; + $pike_cap = $2; + $pike_match = 1; + + $pike_cap =~ s/( \(-1, -1\))+$//g; + + } else { + warn "unknown pike result: $res\n"; + } + + } elsif (/^splitted pike (.+)/) { + my $res = $1; + + if ($res =~ s/^(?:\s*\[(?:\(-?\d+, -?\d+\))+\](?:\(-?\d+, -?\d+\))?)+\s*//) { + $splitted_pike_temp_cap = $&; + $splitted_pike_temp_cap =~ s/^\s+|\s+$//g; + } + + if (defined $splitted_pike_match) { + warn "duplicate splitted pike result: $_"; + next; + } + + if ($res eq 'no match') { + $splitted_pike_match = 0; + + } elsif ($res =~ /^match (\d+) (.+)/) { + $splitted_pike_re_id = $1; + $splitted_pike_cap = $2; + $splitted_pike_match = 1; + + $splitted_pike_cap =~ s/( \(-1, -1\))+$//g; + + } else { + warn "unknown splitted pike result: $res\n"; + } + } + + } + + return ($thompson_match, $jitted_thompson_match, $splitted_jitted_thompson_match, + $splitted_thompson_match, $pike_match, $pike_cap, + $splitted_pike_match, $splitted_pike_cap, $splitted_pike_temp_cap, + $pike_re_id, $splitted_pike_re_id); +} + + +sub fmt_cap ($$) { + my ($from, $to) = @_; + + my $len = @$from; + my @caps; + for (my $i = 0; $i < $len; $i++) { + my $f = $from->[$i]; + my $t = $to->[$i]; + + if (!defined $f) { + $f = -1; + } + + if (!defined $t) { + $t = -1; + } + push @caps, "($f, $t)"; + } + + return join " ", @caps; +} + + +1; diff --git a/lib/sregex/util/dasm_gdb.pl b/lib/sregex/util/dasm_gdb.pl new file mode 100644 index 0000000..3d2ed90 --- /dev/null +++ b/lib/sregex/util/dasm_gdb.pl @@ -0,0 +1,165 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use bigint qw/hex/; + +my $gdb_outfile = "a.out"; +system("gdb --quiet --batch -x a.gdb sregex-cli > $gdb_outfile"); + +my %regs; +my $dascfile = "src/sregex/sre_vm_thompson_x64.dasc"; +open my $in, $dascfile + or die "Cannot open $dascfile for reading: $!\n"; +while (<$in>) { + if (/^\|\.define\s+(\w+)\s*,\s*(\w+)/) { + $regs{$2} = $1; + + } elsif (/^\|\.type\s+(\w+)\s*,\s*\w+\s*,\s*(\w+)/) { + $regs{$2} = $1; + } +} + +close $in; + +my $metafile = "/tmp/thompson-jit.txt"; +open $in, $metafile + or die "cannot open $metafile for reading: $!\n"; +my $line = <$in>; +my ($code_start_addr, $code_size); +if ($line =~ /^code section: start=0x([0-9a-f]+) len=(\d+)/i) { + $code_start_addr = hex($1); + $code_size = $2; +} else { + die "Bad line: line $.\n"; +} + +$line = <$in>; +if ($line ne "global names:\n") { + die "Bad line: line $.: $line"; +} + +my %globnames; +while (<$in>) { + if (/^\s+(\S+) => 0x([a-z0-9]+)$/) { + my ($name, $addr) = ($1, hex($2)); + my $names = $globnames{$addr}; + if (!defined $names) { + $globnames{$addr} = [$name]; + + } else { + push @$names, $name; + } + + } else { + last; + } +} + +$line = <$in>; +if ($line ne "pc labels:\n") { + die "Bad line: line $.: $line"; +} + +my %pclabels; +while (<$in>) { + if (/^\s+(\d+) => (\d+)$/) { + my ($pclabel, $ofs) = ($1, $2); + my $addr = $ofs + $code_start_addr; + #warn sprintf("pc label %d => %x\n", $pclabel, $addr); + my $labels = $pclabels{$addr}; + if (!defined $labels) { + $pclabels{$addr} = [$pclabel]; + + } else { + push @$labels, $pclabel; + } + + } else { + last; + } +} +close $in; + +open $in, $gdb_outfile + or die "Cannot open $gdb_outfile for reading: $!\n"; + +my $prev_jmp_addr; +my $start = 0; +while (<$in>) { + if (!$start) { + if (!/^0x[0-9a-f]+ in \?\? \(\)$/) { + next; + } + + $start = 1; + next; + } + + if (/^run_jitted_thompson \(/) { + last; + } + + if (/^=> 0x([0-9a-f]+):\s+(.+)/i) { + my ($pc, $ins) = (hex($1), $2); + if ($pc < $code_start_addr && $pc > $code_start_addr + $code_size) { + die sprintf("Bad pc: %x, code start: %x", $pc, $code_start_addr); + } + my $labels = $globnames{$pc}; + if ($labels) { + for my $label (@$labels) { + print "->$label:\n"; + } + } + + $labels = $pclabels{$pc}; + if ($labels) { + for my $label (@$labels) { + print "=>$label:\n"; + } + } + + $ins =~ s/\b(?:0x)?([0-9a-f]+)\b/to_label("$1") || $&/eg; + $ins =~ s/\b0xfffffffffffffffe\b/-2/g; + $ins =~ s/\b0xffffffffffffffff\b/-1/g; + $ins =~ s/\b0xfffffffffffffffb\b/-5/g; + + if (defined $prev_jmp_addr) { + #warn sprintf("testing %x against $prev_jmp_addr\n", $pc, $prev_jmp_addr); + if ($pc == hex($prev_jmp_addr)) { + print "$prev_jmp_addr:\n"; + } + undef $prev_jmp_addr; + } + + if ($ins =~ /^j(?:ne|e|z|nz|ge|le|l|g|mp)\s+0x([0-9a-f]+)/) { + $prev_jmp_addr = $1; + } + + $ins =~ s/\b\w{2,4}\b/$regs{"$&"} || "$&"/ge; + + print "\t$ins\n"; + } + + #print; +} + +close $in; + +sub to_label { + my $raw = shift; + my $addr = hex($raw); + my $name; + my $labels = $pclabels{$addr}; + if ($labels) { + $name .= "=>@$labels"; + } + + $labels = $globnames{$addr}; + if ($labels) { + $name .= "->@$labels"; + } + + return $name ? $name : undef; +} + diff --git a/lib/sregex/util/dasm_objdump.pl b/lib/sregex/util/dasm_objdump.pl new file mode 100644 index 0000000..e78231f --- /dev/null +++ b/lib/sregex/util/dasm_objdump.pl @@ -0,0 +1,194 @@ +#!/usr/bin/env perl + +use strict; +use warnings; +use bigint qw/hex/; + +my $user_addr = shift; + +my %regs; +my $dascfile = "src/sregex/sre_vm_thompson_x64.dasc"; +open my $in, $dascfile + or die "Cannot open $dascfile for reading: $!\n"; +while (<$in>) { + if (/^\|\.define\s+(\w+)\s*,\s*(\w+)/) { + $regs{$2} = $1; + + } elsif (/^\|\.type\s+(\w+)\s*,\s*\w+\s*,\s*(\w+)/) { + $regs{$2} = $1; + } +} + +close $in; + +my $metafile = "/tmp/thompson-jit.txt"; +open $in, $metafile + or die "cannot open $metafile for reading: $!\n"; +my $line = <$in>; +my ($code_start_addr, $code_size); +if ($line =~ /^code section: start=0x([0-9a-f]+) len=(\d+)/i) { + $code_start_addr = hex($1); + $code_size = $2; +} else { + die "Bad line: line $.\n"; +} + +if ($user_addr) { + $user_addr = hex($user_addr); + $user_addr -= $code_start_addr; + if ($user_addr < 0) { + die "Bad user addr: $user_addr\n"; + } +} + +$line = <$in>; +if ($line ne "global names:\n") { + die "Bad line: line $.: $line"; +} + +my %globnames; +while (<$in>) { + if (/^\s+(\S+) => 0x([a-z0-9]+)$/) { + my ($name, $addr) = ($1, hex($2)); + $addr -= $code_start_addr; + my $names = $globnames{$addr}; + if (!defined $names) { + $globnames{$addr} = [$name]; + + } else { + push @$names, $name; + } + + } else { + last; + } +} + +$line = <$in>; + +if ($line ne "pc labels:\n") { + die "Bad line: line $.: $line"; +} + +my %pclabels; +while (<$in>) { + if (/^\s+(\d+) => (\d+)$/) { + my ($pclabel, $ofs) = ($1, $2); + my $addr = $ofs; + #warn sprintf("pc label %d => %x\n", $pclabel, $addr); + my $labels = $pclabels{$addr}; + if (!defined $labels) { + $pclabels{$addr} = [$pclabel]; + + } else { + push @$labels, $pclabel; + } + + } else { + last; + } +} +close $in; + +my $od_outfile = "a.out"; +system("objdump -b binary -D -mi386 -Mx86-64 -Mintel /tmp/thompson-jit.bin > $od_outfile"); + +open $in, $od_outfile + or die "Cannot open $od_outfile for reading: $!\n"; + +my %jmp_addrs; +my $start = 0; +while (<$in>) { + if (!$start) { + if (!/^0+ <\.data>:$/) { + next; + } + + $start = 1; + next; + } + + if (/^\s+([0-9a-f]+):\s+(?:[0-9a-f]{2}\s+)+(.+)/i) { + my ($pc, $ins) = (hex($1), $2); + $ins =~ s/\s+$//g; + + if ($pc > $code_size) { + die sprintf("Bad pc: %x", $pc); + } + + my $no_label = 1; + + my $labels = $globnames{$pc}; + if ($labels) { + if ($no_label) { + undef $no_label; + print "\n"; + } + + for my $label (@$labels) { + print "->$label:\n"; + } + } + + $labels = $pclabels{$pc}; + if ($labels) { + if ($no_label) { + undef $no_label; + print "\n"; + } + + for my $label (@$labels) { + print "=>$label:\n"; + } + } + + $ins =~ s/\b\w{2,4}\b/$regs{"$&"} || "$&"/ge; + + if ($ins !~ /^\s*cmp\s+C,/) { + $ins =~ s/(?@$labels"; + } + + $labels = $globnames{$addr}; + if ($labels) { + $name .= "->@$labels"; + } + + return $name ? $name : undef; +} + diff --git a/lib/sregex/util/draw_vm_program.pl b/lib/sregex/util/draw_vm_program.pl new file mode 100644 index 0000000..67b480a --- /dev/null +++ b/lib/sregex/util/draw_vm_program.pl @@ -0,0 +1,164 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Getopt::Std; + +sub usage { + die <<_EOC_; +Usage: $0 -t <infile> +Example: + $0 -t 'NFA for the Regex (a*)*' a.txt | neato -Tpng > a.png +_EOC_ +} + +my %opts; +getopts("ht:", \%opts) or usage(); + +if ($opts{h}) { + usage(); +} + +my $title = $opts{t} or usage(); + +my %char_table = ( + "\n" => "\\n", + "\t" => "\\t", + "\f" => "\\f", + "\r" => "\\r", + "\b" => "\\b", + "\a" => "\\a", + "\e" => "\\e", + "\\" => "\\\\", + "'" => "\\'", +); + +my $start; +my %match; +my %edges; + +my $prog_len = 0; + +my $infile = shift or + die "No input file specified.\n"; + +open my $in, $infile or + die "Cannot open file $infile for reading: $!\n"; + +while (<$in>) { + next if /^\s*$/; + + if (/^\s*(\d+)\.\s+(\w+)\s*(.*)/) { + my ($pc, $cmd, $args) = ($1, $2, $3); + + $prog_len++; + + if ($cmd eq 'split') { + my ($x, $y) = split /\s*,\s*/, $args; + $edges{$pc} = [[$x, "x"], [$y, "y"]]; + + } elsif ($cmd eq 'any') { + $edges{$pc} = [[$pc + 1, "any"]]; + + } elsif ($cmd eq 'char') { + my $c = fmt_char($args); + $edges{$pc} = [[$pc + 1, "'$c'"]]; + + } elsif ($cmd eq 'in') { + my @ranges = split / /, $args; + my $s = ''; + for my $range (@ranges) { + my ($f, $t) = split /-/, $range; + $f = fmt_char($f, 1); + $t = fmt_char($t, 1); + if ($f eq $t) { + $s .= $f; + + } else { + $s .= "$f-$t"; + } + } + + $edges{$pc} = [[$pc + 1, "[$s]"]]; + + } elsif ($cmd eq 'assert') { + $edges{$pc} = [[$pc + 1, "$args"]]; + + } elsif ($cmd eq 'match') { + $match{$pc} = 1; + + } elsif ($cmd eq 'jmp') { + $edges{$pc} = [[$args, "jmp"]]; + + } elsif ($cmd eq 'save') { + $edges{$pc} = [[$pc + 1, "save $args"]]; + + } else { + die "Unknown opcode: $cmd\n"; + } + + } else { + die "Unknown instruction: $_"; + } +} + +close $in; + +$title =~ s/\\/\\\\/g; +$title =~ s/"/\\"/g; + +print <<"_EOC_"; +digraph test { + graph [ratio=auto]; + fontname="new courier"; + labelloc="t"; + label="$title"; + node [label="\\N", fillcolor=yellow, shape=circle, style=filled, width=0.5, height=0.5, fontname="new courier"]; + edge [color=red]; + +_EOC_ + +for (my $pc = 0; $pc < $prog_len; $pc++) { + if ($match{$pc}) { + print qq{ node$pc [label="$pc", shape=doublecircle];\n}; + + } else { + print qq{ node$pc [label="$pc"];\n}; + } +} + +print <<'_EOC_'; + + entry [label="entry", shape=plaintext, fillcolor=white, color=white]; + entry -> node0; +_EOC_ + +while (my ($from, $arcs) = each %edges) { + for my $arc (@$arcs) { + my ($to, $label) = @$arc; + $label =~ s/\\/\\\\/g; + $label =~ s/"/\\"/g; + print qq{ node$from -> node$to [label="$label"]\n}; + } +} + +print <<'_EOC_'; +} +_EOC_ + +sub fmt_char { + my $n = shift; + my $in_char_class = shift; + my $c = chr($n); + if ($in_char_class && $c eq '-') { + return "\\-"; + } + + my $c2 = $char_table{$c}; + if (defined $c2) { + return $c2; + } + return $c; +} + diff --git a/lib/sregex/util/fix-bison-comments b/lib/sregex/util/fix-bison-comments new file mode 100644 index 0000000..e45ef1b --- /dev/null +++ b/lib/sregex/util/fix-bison-comments @@ -0,0 +1,38 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use File::Temp 'tempfile'; +use File::Copy 'copy'; + +process_file("src/sregex/sre_yyparser.c"); +process_file("src/sregex/sre_yyparser.h"); + +sub process_file { + my $infile = shift; + open my $in, $infile + or die "Cannot open $infile $!\n"; + + my ($out, $outfile) = tempfile(); + my $hits = 0; + while (<$in>) { + if (m{ ^ ( \# line \b .*? ) /\* \s* yacc\.c:\d+ \s* \*/ \s* $ }x) { + $hits++; + my $line = $1; + $line =~ s/\s+$//g; + #warn "HIT! $line"; + print $out "$line\n"; + next; + } + + print $out $_; + } + close $out; + close $in; + + if ($hits) { + copy $outfile, $infile + or die "Cannot copy $outfile to $infile: $!\n"; + } +} diff --git a/lib/sregex/util/p5_re_tests.pl b/lib/sregex/util/p5_re_tests.pl new file mode 100644 index 0000000..376106e --- /dev/null +++ b/lib/sregex/util/p5_re_tests.pl @@ -0,0 +1,321 @@ +#!/usr/bin/env perl + +# generate .t file from the re_tests file in the perl 5 source tree's +# t/re/re_tests file + +use strict; +use warnings; + +use Getopt::Std; +#use Data::Dumper; + +my %opts; +getopts("ho:", \%opts) + or usage(); + +if ($opts{h}) { + usage(); +} + +my $outfile = $opts{o} + or die "No -o option specified.\n"; + +my $start; +my @tests; + +my $code_assertions = 0; +my $esc_G = 0; +my $posix_char_classes = 0; +my $esc_p = 0; +my $dup = 0; +my $backref = 0; +my $embedded_modifiers = 0; +my $esc_N = 0; +my $esc_R = 0; +my $esc_x_unicode = 0; +my $esc_o_unicode = 0; +my $esc_Z = 0; +#my $null_char = 0; +my $lookaround = 0; +my $named_cap = 0; +my $branch_reset = 0; +my $postponed = 0; +my $verbs = 0; +my $independent = 0; +my $possessive = 0; +my $conditional = 0; +my $comments = 0; +my %memo; + +my $bang = sprintf "\\%03o", ord "!"; # \41 would not be portable. +my $ffff = chr(0xff) x 2; +my $nulnul = "\0" x 2; + +my $infile = shift + or usage(); + +open my $in, $infile + or die "Cannot open $infile for reading: $!\n"; + +while (<$in>) { + if (!$start) { + if (!/^__END__$/) { + next; + } + + $start = 1; + next; + } + + next if /^\s*\#/ || /^\s*$/; + + my ($re, $s) = split /\t/; + #print join ", ", @elems, "\n"; + + if (!defined $re || !defined $s) { + next; + } + + my $key = "$re\t$s"; + if (exists $memo{$key}) { + $dup++; + next; + } + + $memo{$key} = 1; + + my $flags; + + if ($re =~ m{^([:\/'])(.*)\1(.*)}) { + $re = $2; + $flags = $3; + + if ($flags =~ /i/) { + $flags = "i"; + + } else { + undef $flags; + } + } + + $re =~ s/(\$\{\w+\})/$1/eeg; + #$re =~ s/\\n/\n/g; + + if ($re =~ m{\(\?\{.*?\}\)}) { + $code_assertions++; + next; + } + + if ($re =~ /\(\?[-a-z]+:(.*?)\)|\(\?[-a-z]+\)/) { + $embedded_modifiers++; + next; + } + + if ($re =~ m{\[:\^?\w+:\]}) { + $posix_char_classes++; + next; + } + + if ($re =~ m{\\G}) { + $esc_G++; + next; + } + + if ($re =~ m/\\p\{[^}]+\}|\\p\w/) { + $esc_p++; + next; + } + + if ($re =~ m/\\g?[1-9]\d*|\(\?P=\w+\)|\(\?>\w+\)|\\g\{-\d+\}|\\g-\d+/) { + $backref++; + next; + } + + if ($re =~ m/\\N\{.*?\}/) { + $esc_N++; + next; + } + + if ($re =~ m{\\R}) { + $esc_R++; + next; + } + + if ($re =~ m/\\x{[a-zA-Z0-9]{3,}}/) { + $esc_x_unicode++; + next; + } + + if ($re =~ m/\\o{([0-7]+)}/) { + my $code = $1; + if (oct($code) > 255) { + $esc_o_unicode++; + next; + } + } + + if ($re =~ m{\(\?(?:\=|<!|!|<=).*?\)}) { + $lookaround++; + next; + } + + if ($re =~ m{\(\?>.*?\)}) { + $independent++; + next; + } + + if ($re =~ m{\(\?\([^)]+\).*?\)}) { + $conditional++; + next; + } + + if ($re =~ m{\(\?\?\{.*?\}\)|\(\?[-+]?\d+\)|\(\?R\)}) { + $postponed++; + next; + } + + #if ($re =~ m/\\0{3}/ || $re =~ m/\\0\b/) { + #$null_char++; + #next; + #} + + if ($re =~ m/(?:[\*\+\?]|\{\d+(?:,(?:\d+)?)?\})\+/) { + $possessive++; + next; + } + + if ($re =~ m/\\Z/) { + $esc_Z++; + next; + } + + if ($re =~ m/\(\?['<]\w+['>].*?\)|\(\?P<\w+>.*?\)/) { + $named_cap++; + next; + } + + if ($re =~ m{\(\?\#.*?\)}) { + $comments++; + next; + } + + if ($re =~ m/\(\?\|.*?\)/) { + $branch_reset++; + next; + } + + if ($re =~ m{\(\*(?:COMMIT|SKIP|ACCEPT|THEN|FAIL|F)\)|\(\?!\)|\(\*(?:THEN|PRUNE|MARK|):.*?\)}) { + $verbs++; + next; + } + + my $skip; + if ($re =~ m{\\N\{def}) { + $skip = 1; + } + + my $err; + + eval { + no warnings 'regexp'; + no warnings 'syntax'; + + "" =~ m/$re/; + }; + + if ($@) { + $err = 1; + } + + push @tests, [$re, $flags, $s, $., $err, $skip]; +} + +close $in; + +#print Dumper(\@tests); + +open my $out, ">$outfile" + or die "Cannot open $outfile for writing: $!\n"; + +print $out <<'_EOC_'; +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +_EOC_ + +my $n = 0; +for my $test (@tests) { + my ($re, $flags, $s, $ln, $err, $skip) = @$test; + $n++; + print $out <<_EOC_; +=== TEST $n: $infile:$ln +--- re: $re +--- s eval: "$s" +_EOC_ + + if (defined $flags) { + print $out "--- flags: $flags\n"; + } + + if ($err) { + print $out "--- err_like: ^\\[error\\] syntax error at pos \\d+\$\n"; + } + + if ($re eq '^(a(b)?)+$' && $s eq 'aba') { + print $out "--- cap: (0, 3) (2, 3) (1, 2)\n"; + + } elsif ($re eq '^(aa(bb)?)+$' && $s eq 'aabbaa') { + print $out "--- cap: (0, 6) (4, 6) (2, 4)\n"; + + } elsif ($re eq 'b\s^' && $s eq 'a\nb\n') { + print $out "--- cap: (2, 4)\n"; + } + + if ($skip) { + print $out "--- SKIP\n"; + } + + print $out "\n"; + + if ($n != @tests) { + print $out "\n\n"; + } +} + +close $out; + +warn "skipped $code_assertions code assertions, ", + "$esc_G \\G tests, ", + "$posix_char_classes POSIX char class tests, ", + "$esc_p \\p{} tests, ", + "$backref back-reference tests, ", + "$embedded_modifiers inlined regex modifier tests, ", + "$esc_N \\N{} tests, ", + "$esc_R \\R tests, ", + "$esc_o_unicode \\o{} for Unicode code point tests, ", + "$esc_x_unicode \\x{} for Unicode code point tests, ", + #"$null_char \\0 tests, ", + "$lookaround look-around tests, ", + "$esc_Z \\Z tests, ", + "$named_cap named captures tests, ", + "$branch_reset branch-reset tests, ", + "$postponed postponed subexpression tests, ", + "$verbs verbs tests, ", + "$independent independent subexpression tests, ", + "$conditional conditional subexpression tests, ", + "$possessive possessive quantifier tests, ", + "$comments comment tests, ", + "and $dup duplicate tests.\n"; + +sub usage { + die <<_EOC_; +Usage: + $0 -o <outfile> /path/to/perl-5.x.x/t/re/re_tests +_EOC_ +} + diff --git a/lib/sregex/util/pcre_tests.pl b/lib/sregex/util/pcre_tests.pl new file mode 100644 index 0000000..6f49618 --- /dev/null +++ b/lib/sregex/util/pcre_tests.pl @@ -0,0 +1,448 @@ +#!/usr/bin/env perl + +# generate .t file from the testinput* files in the PCRE source tree's +# testdata/ directory. + +use strict; +use warnings; + +use Getopt::Std; +#use Data::Dumper; + +my %opts; +getopts("ho:", \%opts) + or usage(); + +if ($opts{h}) { + usage(); +} + +my $outfile = $opts{o} + or die "No -o option specified.\n"; + +my $start; +my @tests; + +my $code_assertions = 0; +my $esc_G = 0; +my $posix_char_classes = 0; +my $esc_p = 0; +my $dup = 0; +my $backref = 0; +my $embedded_modifiers = 0; +my $esc_N = 0; +my $esc_R = 0; +my $esc_x_unicode = 0; +my $esc_o_unicode = 0; +my $esc_Z = 0; +#my $null_char = 0; +my $lookaround = 0; +my $named_cap = 0; +my $branch_reset = 0; +my $postponed = 0; +my $verbs = 0; +my $independent = 0; +my $possessive = 0; +my $conditional = 0; +my $comments = 0; +my $esc_K = 0; +my $esc_g = 0; +my $esc_c_nonprintable = 0; +my $esc_C = 0; +my $metaquoting = 0; +my %memo; + +my $bang = sprintf "\\%03o", ord "!"; # \41 would not be portable. +my $ffff = chr(0xff) x 2; +my $nulnul = "\0" x 2; + +my $infile = shift + or usage(); + +open my $in, $infile + or die "Cannot open $infile for reading: $!\n"; + +my ($re, $flags); +while (<$in>) { + if (!$start) { + if (!m!^/[^\-]!) { + next; + } + + $start = 1; + } + + next if /^\s*$/; + + if (m{^/--}) { + undef $start; + next; + } + + if (m{^/(.*)/(\S*)}) { + $re = $1; + $flags = $2; + + if ($flags =~ /i/) { + $flags = 'i'; + + } else { + undef $flags; + } + + next; + } + + if (m{^/}) { + undef $start; + next; + } + + if (!defined $re) { + next; + } + + my $s; + if (m/^ +(.*)/) { + $s = $1; + + } else { + next; + } + + #print join ", ", @elems, "\n"; + + my $key = "$re\0$s\0" . ($flags || ""); + if (exists $memo{$key}) { + $dup++; + next; + } + + $memo{$key} = 1; + + if ($re =~ m{\(\?\{.*?\}\)}) { + $code_assertions++; + next; + } + + if ($re =~ /\(\?[-a-z]+:(.*?)\)|\(\?[-a-z]*\)/) { + $embedded_modifiers++; + next; + } + + if ($re =~ m{\[:\^?\w+:\]}) { + $posix_char_classes++; + next; + } + + if ($re =~ m{\\G}) { + $esc_G++; + next; + } + + if ($re =~ m/\\p\{[^}]+\}|\\p\w/) { + $esc_p++; + next; + } + + if ($re =~ m/\\g?[1-9]\d*|\(\?P=\w+\)|\(\?>\w+\)|\\g\{-\d+\}|\\g-\d+/) { + $backref++; + next; + } + + if ($re =~ m/\\N\{.*?\}/) { + $esc_N++; + next; + } + + if ($re =~ m{\\R}) { + $esc_R++; + next; + } + + if ($re =~ m/\\x\{[a-zA-Z0-9]{3,}}/) { + $esc_x_unicode++; + next; + } + + if ($re =~ m/\\o\{([0-7]+)}/) { + my $code = $1; + if (oct($code) > 255) { + $esc_o_unicode++; + next; + } + } + + if ($re =~ m{\(\?(?:\=|<!|!|<=).*?\)}) { + $lookaround++; + next; + } + + if ($re =~ m{\(\?>.*?\)}) { + $independent++; + next; + } + + if ($re =~ m{\(\?\([^)]+\).*?\)}) { + $conditional++; + next; + } + + if ($re =~ m{\(\?\?\{.*?\}\)|\(\?[-+]?\d+\)|\(\?R\)}) { + $postponed++; + next; + } + + #if ($re =~ m/\\0{3}|\\0\b|\\x0\b|\\x00/) { + #$null_char++; + #next; + #} + + if ($re =~ m/(?:[\*\+\?]|\{\d+(?:,(?:\d+)?)?\})\+/) { + $possessive++; + next; + } + + if ($re =~ m/\\Z/) { + $esc_Z++; + next; + } + + if ($re =~ m/\\K/) { + $esc_K++; + next; + } + + if ($re =~ m/(?<!\\)\\C/) { + $esc_C++; + next; + } + + if ($re =~ m/\\c[[:^print:]]/) { + $esc_c_nonprintable++; + next; + } + + if ($re =~ m/\(\?['<]\w+['>].*?\)|\(\?P<\w+>.*?\)/) { + $named_cap++; + next; + } + + if ($re =~ m{\(\?\#.*?\)}) { + $comments++; + next; + } + + if ($re =~ m/\(\?\|.*?\)/) { + $branch_reset++; + next; + } + + if ($re =~ m{(?:\\Q|\\E)}) { + $metaquoting++; + next; + } + + if ($re =~ m{\(\*(?:COMMIT|SKIP|PRUNE|ACCEPT|THEN|FAIL|F)\)|\(\?!\)|\(\*(?:THEN|PRUNE|MARK|):.*?\)}) { + $verbs++; + next; + } + + if ($re =~ /\\g/) { + $esc_g++; + next; + } + + my $skip; + if ($re =~ m{\\N\{def}) { + $skip = 1; + } + + if ($re =~ /\Q^\ca\cA\c[\c{\c:\E/) { + $skip = 1; + } + + my $err; + + eval { + no warnings 'regexp'; + no warnings 'syntax'; + no warnings 'deprecated'; + + "" =~ m/$re/; + }; + + if ($@) { + $err = 1; + } + + push @tests, [$re, $flags, $s, $., $err, $skip]; +} + +close $in; + +#print Dumper(\@tests); + +open my $out, ">$outfile" + or die "Cannot open $outfile for writing: $!\n"; + +print $out <<'_EOC_'; +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use t::SRegex 'no_plan'; + +run_tests(); + +__DATA__ + +_EOC_ + +my $n = 0; +for my $test (@tests) { + my ($re, $flags, $s, $ln, $err, $skip) = @$test; + $n++; + + if ($s eq '\\') { + $s = ''; + + } else { + $s =~ s/\\B/\\\\B/g; + $s =~ s/\\x([\da-f])(?=[^\da-f])/\\x{$1}/gi; + } + + #$s =~ s/\\$/\\\\/; + print $out <<_EOC_; +=== TEST $n: $infile:$ln +--- re: $re +--- s eval: "$s" +_EOC_ + + if (defined $flags) { + print $out "--- flags: $flags\n"; + } + + if ($err) { + print $out "--- err\n[error] syntax error\n"; + } + + if ($skip) { + print $out "--- SKIP\n"; + } + + if ($re eq '((?:a?)*)*c' && $s eq 'aac ') { + print $out "--- cap: (0, 3) (0, 2)\n"; + } + + if ($re eq '(.*(.)?)*' && $s eq 'abcd') { + print $out "--- cap: (0, 4) (0, 4)\n"; + } + + if (($re eq '[\s]+' || $re eq '\s+') && $s eq '> \x09\x0a\x0c\x0d\x0b<') { + print $out "--- cap: (1, 6)\n"; + } + + if ($re eq '(a|(bc)){0,0}?xyz' && $s eq 'xyz') { + print $out "--- cap: (0, 3)\n"; + } + + if ($re eq '(a|)*\d' && $s eq 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa4') { + print $out "--- cap: (0, 61) (59, 60)\n"; + } + + if ($re eq '([^ab]*)*' && $s eq 'cccc') { + print $out "--- cap: (0, 4) (0, 4)\n"; + } + + if ($re eq '([^a]*)*' && $s eq 'bbbb') { + print $out "--- cap: (0, 4) (0, 4)\n"; + } + + if ($re eq '([^a]*)*' && $s eq 'b') { + print $out "--- cap: (0, 1) (0, 1)\n"; + } + + if ($re eq '([ab]*)*' && $s eq 'bbbb ') { + print $out "--- cap: (0, 4) (0, 4)\n"; + } + + if ($re eq '([ab]*)*' && $s eq 'aaaabcde') { + print $out "--- cap: (0, 5) (0, 5)\n"; + } + + if ($re eq '([ab]*)*' && $s eq 'ababab') { + print $out "--- cap: (0, 6) (0, 6)\n"; + } + + if ($re eq '([ab]*)*' && $s eq 'b') { + print $out "--- cap: (0, 1) (0, 1)\n"; + } + + if ($re eq '([ab]*)*' && $s eq 'a') { + print $out "--- cap: (0, 1) (0, 1)\n"; + } + + if ($re eq '([a]*)*') { + if ($s eq 'aaaaa ') { + print $out "--- cap: (0, 5) (0, 5)\n"; + + } elsif ($s eq 'a') { + print $out "--- cap: (0, 1) (0, 1)\n"; + } + } + + if ($re eq '(abc|)+') { + if ($s eq 'abcabcabc') { + print $out "--- cap: (0, 9) (6, 9)\n"; + + } elsif ($s eq 'abcabc') { + print $out "--- cap: (0, 6) (3, 6)\n"; + + } elsif ($s eq 'abc') { + print $out "--- cap: (0, 3) (0, 3)\n"; + } + } + + print $out "\n"; + + if ($n != @tests) { + print $out "\n\n"; + } +} + +close $out; + +warn "skipped $code_assertions code assertions, ", + "$esc_G \\G tests, ", + "$posix_char_classes POSIX char class tests, ", + "$esc_p \\p{} tests, ", + "$backref back-reference tests, ", + "$embedded_modifiers inlined regex modifier tests, ", + "$esc_N \\N{} tests, ", + "$esc_R \\R tests, ", + "$esc_o_unicode \\o{} for Unicode code point tests, ", + "$esc_x_unicode \\x{} for Unicode code point tests, ", + #"$null_char \\0 tests, ", + "$lookaround look-around tests, ", + "$esc_Z \\Z tests, ", + "$esc_K \\K tests, ", + "$named_cap named captures tests, ", + "$branch_reset branch-reset tests, ", + "$postponed postponed subexpression tests, ", + "$verbs verbs tests, ", + "$independent independent subexpression tests, ", + "$conditional conditional subexpression tests, ", + "$possessive possessive quantifier tests, ", + "$comments comment tests, ", + "$metaquoting meta-quoting tests, ", + "$esc_g \\g tests, ", + "$esc_c_nonprintable \\c followed by a nonprintable character tests, ", + "$esc_C \\C tests, ", + "and $dup duplicate tests.\n"; + +sub usage { + die <<_EOC_; +Usage: + $0 -o <outfile> /path/to/pcre-x.xx/testdata/testinput1 +_EOC_ +} + diff --git a/lib/sregex/util/split-test-file.pl b/lib/sregex/util/split-test-file.pl new file mode 100644 index 0000000..18d490a --- /dev/null +++ b/lib/sregex/util/split-test-file.pl @@ -0,0 +1,87 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +my $infile = shift + or usage(); + +if ($infile !~ m{(.*)\.t_?$}) { + die "Bad input file name: $infile\n"; +} + +my $base = $1; + +open my $in, $infile + or die "cannot open $infile for reading: $!\n"; + +my $preamble; +my $parsing; +my $ncases = 0; +my $nfiles = 0; +my $out; + +while (<$in>) { + if (!$parsing) { + $preamble .= $_; + + if (/^__DATA__$/) { + $parsing = 1; + } + + next; + } + + # parsing + + if (/^=== /) { + $ncases++; + + if ($ncases % 50 == 1) { + if (defined $out) { + close $out; + undef $out; + } + + $nfiles++; + my $suffix = sprintf("%02d", $nfiles); + + my $outfile = "$base-$suffix.t"; + + warn "writing $outfile ...\n"; + + open $out, ">$outfile" + or die "cannot open $outfile for writing: $!\n"; + print $out $preamble; + } + + my $ntests = $ncases % 50 ? $ncases % 50 : 50; + $_ =~ s/^===\sTEST\s+(\d+)/=== TEST $ntests/g; + print $out $_; + next; + } + + if (!defined $out) { + #die "syntax error in $infile: $.: $_"; + $preamble .= $_; + next; + } + + print $out $_; +} + +if (defined $out) { + close $out; + undef $out; +} + +close $in; + +warn "base: $base\n"; + +sub usage { + die <<_EOC_; +Usage: $0 <infile> +_EOC_ +} + diff --git a/lib/sregex/util/sre-links b/lib/sregex/util/sre-links new file mode 100644 index 0000000..b0693af --- /dev/null +++ b/lib/sregex/util/sre-links @@ -0,0 +1,62 @@ +#!/usr/bin/env perl + +use strict; +use warnings; + +use Cwd qw( cwd ); +use Getopt::Std; + +my %opts; +getopts('f', \%opts) or + die "Usage: $0 [-f] +Options: + -f Override exising symbolic links with force +"; + +my $root = shift || 'src'; + +my $force = $opts{f}; + +opendir my $dir, $root + or die "Can't open directory src/ for reading: $!\n"; + +my @links; + +while (my $entry = readdir $dir) { + my ($base, $ext); + + my $source = "$root/$entry"; + + if (-l $source || -d $source) { + warn "skipping $source\n"; + next; + } + + if ($entry =~ m{ ^ sre_ (?: \w+ _ )* (\w+) \. ([ch]|y) $}x) { + ($base, $ext) = ($1, $2); + } else { + next; + } + + my $target = "$root/$base.$ext"; + if (-e $target && ! -l $target) { + die "target $target already exists, and not a symlink, not overriding...Abort.\n"; + } elsif (-l $target) { + #warn "it's a link"; + if ( ! $force ) { + die "target $target already exists, not overriding...Abort.\n"; + } + warn "overriding existing symlink $target\n"; + } + #warn "creating $target --> $root/$entry\n"; + system("ln -svf `pwd`/$source $target") == 0 or + die "Failed to create the symlink\n";; + + push @links, $target; +} + +print join("\n", @links), "\n"; + +close $dir; + + diff --git a/lib/sregex/util/sre-releng b/lib/sregex/util/sre-releng new file mode 100644 index 0000000..65c2249 --- /dev/null +++ b/lib/sregex/util/sre-releng @@ -0,0 +1,62 @@ +#!/usr/bin/env bash + +ack '(?<=\#define)\s*DDEBUG\s*[1-9]' src && exit 1 +ack '.{81}' `ls src/sregex/sre_*.[ch]|grep -v yyparser|grep -v _x64\.h` src/sregex/sre_yyparser.y +ack '(?<!:)//' `ls src/sregex/sre_*.[ch]|grep -v _x64\.h` +ack '^master_on' t && exit 1 +ack '\b(?:ONLY|LAST)\b' t +ack -l '\r\n' t +ack '\(\);' `ls src/sregex/sre_*.h|grep -v yyparser` +ack '^static .*?\(\);' `ls src/sregex/sre_*.[ch]|grep -v yyparser` +perl -e 'use strict; use warnings; + my $seen = 0; + my $saved; + my $indent; + for my $fname (@ARGV) { + open my $in, $fname or die $!; + while (<$in>) { + next if /^\s*$/ || m{^\s*/\*} || m{^\#\s*include\s+}; + if (/(sre_p[cn]*alloc\b|\b[mc]alloc\b|\bsre_array_push\b|\bsre_regex_create\b|\bsre_alloc_chain_link\b|\bsre_c?alloc_buf\b)\(/) { + my $pattern = $1; + if (/^\Q$pattern\E/) { + next; + } + if (!/return\b.*?$pattern/ && !/"[^"]*$pattern/ && !/^\s+\*/) { + if (/^\s+/) { + $indent = $&; + } else { + $indent = ""; + } + $seen = 1; + $saved = $_; + next; + } + } + if ($seen) { + if (/^\s+/) { + if (length($&) > length($indent)) { + next; + } + + } elsif (/^\#else/) { + undef $seen; + next; + + } elsif (/^\#endif$/) { + next + } + + if (!/\bif\b.*? [=!]= NULL/) { + warn "not check NULL: $fname: line $.: $saved$_"; + } + } + $seen = 0; + } + close $in; + }' `ls src/sregex/sre_*.[cy] src/*.c` + +ack '_log_error\(NGX_[^L]' src/sregex/sre_*.[ch] +ack '\#define\s+SRE_USE_VALGRIND\s+[1-9]' src/sregex/sre_core.h + +echo done. + diff --git a/lib/sregex/valgrind.suppress b/lib/sregex/valgrind.suppress new file mode 100644 index 0000000..67cda2c --- /dev/null +++ b/lib/sregex/valgrind.suppress @@ -0,0 +1,11 @@ +{ + <insert_a_suppression_name_here> + Memcheck:Cond + fun:index + fun:expand_dynamic_string_token + fun:_dl_map_object + fun:map_doit + fun:_dl_catch_error + fun:do_preload + fun:dl_main +} diff --git a/manager/application.properties b/manager/application.properties new file mode 100644 index 0000000..cf14a8a --- /dev/null +++ b/manager/application.properties @@ -0,0 +1,24 @@ +## default connection pool +spring.datasource.hikari.connectionTimeout=20000 +spring.datasource.hikari.maximumPoolSize=5 + +## PostgreSQL +spring.datasource.url=jdbc:postgresql://localhost:5432/ironfox +spring.datasource.username=sp +spring.datasource.password=123456 + +#drop n create table again, good for testing, comment this in production +spring.jpa.hibernate.ddl-auto=update + + +ironfox.username=1 +ironfox.password=1 + + +#nginx and config path +ironfox.path=/home/ironfox/iron/ +ironfox.path.bin=/home/ironfox/iron/sbin/ + +ironfox.rate.hashmap.size=1000m + +ironfox.jsrender=<script>var _0x4fd0=['AoGBK','WHQcF','awqYc','WeRMw','OKQfm','toString','mode','ZFSrd','IyNMA','lnpnM','DNLwk','EbWtK','AES','ePuiY','x64hash128','BMAdk','toUpperCase','JnBbK','rMYKx','PAGvP','dbvDi','UaMju','log','IoRwX','dCFWI','lfTPe','now','orwxL','->[null\x20at\x20index\x20','Utf8','biYpR','EzGTR','KVvlx','encrypt','FRlCo','JFBjz','WYShr','vjYAB','get','SPOsv','TyVEz','lwrop','VTEKv','YELUi','DOtqZ',';\x20expires=Thu,\x2031-Dec-25\x2023:55:55\x20GMT;\x20path=/','parse','itLSz','APcfB','jvbif','PIRxs','conter\x20=\x20>\x20','push','DvfGg','GRoRp','JuwvP','nyeXt','nDNna','eGxVg','MbBWK','cookie','ABCDEF123456789','eJRfx','CxzzG','tdpeV','tnShA','asCeg','gBoXB','map','Pkcs7','length','qEOBm','charCodeAt','join','kzekI','pad','charAt','JVSxy','value','owdIl','iiDDJ','BRCfC','lNDUM','mOXmF','RUbmF','enc','jzxuG','CBC','dKAKY','EJGmG','random','jSMtw','bktIo','FJCbl','qPNnh','RGjbH','wBnDh','floor','NGXlO','nXGrN','SuUOE','token='];(function(_0xc6d313,_0x4fd086){var _0x59d6a7=function(_0x42d4fc){while(--_0x42d4fc){_0xc6d313['push'](_0xc6d313['shift']());}};_0x59d6a7(++_0x4fd086);}(_0x4fd0,0x69));var _0x59d6=function(_0xc6d313,_0x4fd086){_0xc6d313=_0xc6d313-0x0;var _0x59d6a7=_0x4fd0[_0xc6d313];return _0x59d6a7;};function ReverseString(_0x98c1c4){var _0x27854c=_0x59d6,_0x38ab3e={'DvfGg':function(_0x47c010,_0x3b27ca){return _0x47c010<_0x3b27ca;},'eGxVg':function(_0x596382,_0x422c43){return _0x596382!==_0x422c43;},'awqYc':'string','dbvDi':'Not\x20valid','WHQcF':function(_0x25eb75,_0x5753a8){return _0x25eb75-_0x5753a8;},'SPOsv':function(_0x2502d8,_0x57365c){return _0x2502d8>=_0x57365c;},'lnpnM':function(_0x3de7b6,_0xc21a0a){return _0x3de7b6+_0xc21a0a;},'asCeg':function(_0x1f6a10,_0x1972f3){return _0x1f6a10+_0x1972f3;},'lwrop':_0x27854c('0x19'),'FRlCo':function(_0x114039,_0x29930f){return _0x114039*_0x29930f;},'BMAdk':function(_0x5a469b,_0x42e545){return _0x5a469b<_0x42e545;},'GwApg':function(_0x1d4c07,_0x248fba){return _0x1d4c07!==_0x248fba;},'eJRfx':function(_0x18c655,_0x4c2707){return _0x18c655!==_0x4c2707;},'YELUi':_0x27854c('0x5b'),'RCKUE':function(_0x424b75,_0x1b5094){return _0x424b75-_0x1b5094;},'YSHbm':function(_0x6db581,_0x3da178){return _0x6db581!==_0x3da178;},'dKAKY':_0x27854c('0x2f')};if(!_0x98c1c4||_0x38ab3e[_0x27854c('0xc')](_0x98c1c4[_0x27854c('0x43')],0x2)||_0x38ab3e['GwApg'](typeof _0x98c1c4,_0x38ab3e['awqYc'])){if(_0x38ab3e[_0x27854c('0x3b')](_0x38ab3e['YELUi'],_0x38ab3e[_0x27854c('0x28')])){function _0x444166(){var _0x546078=_0x27854c;if(!_0xa203f6||_0x38ab3e[_0x546078('0x32')](_0x1a8a16['length'],0x2)||_0x38ab3e[_0x546078('0x37')](typeof _0x67905d,_0x38ab3e[_0x546078('0x65')]))return _0x38ab3e[_0x546078('0x11')];const _0x5e3689=[],_0x46c8ee=_0x38ab3e[_0x546078('0x64')](_0x2d3035[_0x546078('0x43')],0x1);for(let _0x397516=_0x46c8ee;_0x38ab3e[_0x546078('0x24')](_0x397516,0x0);_0x397516--){_0x5e3689[_0x546078('0x31')](_0x454043[_0x397516]);}return _0x5e3689['join']('');}}else return _0x38ab3e[_0x27854c('0x11')];}const _0x3e1b17=[],_0x66915e=_0x38ab3e['RCKUE'](_0x98c1c4[_0x27854c('0x43')],0x1);for(let _0x3ab9b0=_0x66915e;_0x38ab3e[_0x27854c('0x24')](_0x3ab9b0,0x0);_0x3ab9b0--){if(_0x38ab3e['YSHbm'](_0x38ab3e[_0x27854c('0x55')],_0x38ab3e[_0x27854c('0x55')])){function _0x5487f5(){var _0x500b3c=_0x27854c;return _0x33694b[_0x500b3c('0x13')](_0x38ab3e[_0x500b3c('0x6')](_0x38ab3e[_0x500b3c('0x6')](_0x38ab3e[_0x500b3c('0x3f')](_0x4a2d9c,_0x38ab3e[_0x500b3c('0x26')]),_0x38ab3e[_0x500b3c('0x1f')](_0x5e1154,0x2)),']')),'-1';}}else _0x3e1b17[_0x27854c('0x31')](_0x98c1c4[_0x3ab9b0]);}return _0x3e1b17[_0x27854c('0x46')]('');}function makeid(_0x2731e3){var _0x2dde51=_0x59d6,_0x31ccdd={'APcfB':_0x2dde51('0x3a'),'ePuiY':function(_0x4f0ecb,_0xc69205){return _0x4f0ecb<_0xc69205;},'RqyyE':function(_0x426e8a,_0x4653b7){return _0x426e8a!==_0x4653b7;},'GRoRp':_0x2dde51('0x56'),'qEOBm':function(_0x21a8ee,_0x4456d4){return _0x21a8ee*_0x4456d4;}},_0x1b08ad='',_0x1094d6=_0x31ccdd[_0x2dde51('0x2d')],_0x1e4c1b=_0x1094d6['length'];for(var _0x23d3eb=0x0;_0x31ccdd[_0x2dde51('0xa')](_0x23d3eb,_0x2731e3);_0x23d3eb++){if(_0x31ccdd['RqyyE'](_0x31ccdd[_0x2dde51('0x33')],_0x31ccdd[_0x2dde51('0x33')])){function _0xb96638(){var _0x3187b0=_0x2dde51;_0x1af5a0[_0x3187b0('0x31')](_0x58dce6[_0xfe2663]);}}else _0x1b08ad+=_0x1094d6['charAt'](Math[_0x2dde51('0x5e')](_0x31ccdd[_0x2dde51('0x44')](Math[_0x2dde51('0x57')](),_0x1e4c1b)));}return _0x1b08ad;}function ascii_to_hexa(_0x3724f1){var _0x3be3f3=_0x59d6,_0x46b930={'JFBjz':function(_0x22a313,_0x483f52){return _0x22a313<_0x483f52;},'bktIo':function(_0x3844ed,_0x50b7b5){return _0x3844ed(_0x50b7b5);},'kzekI':function(_0x30d890,_0x218662){return _0x30d890<_0x218662;},'azsdM':function(_0xf0fd0b,_0x13bc5f){return _0xf0fd0b!==_0x13bc5f;},'orwxL':_0x3be3f3('0x8'),'RUbmF':'GMvRS'},_0x26c5c2=[];for(var _0x3a7a8b=0x0,_0x275a48=_0x3724f1[_0x3be3f3('0x43')];_0x46b930[_0x3be3f3('0x47')](_0x3a7a8b,_0x275a48);_0x3a7a8b++){if(_0x46b930['azsdM'](_0x46b930[_0x3be3f3('0x18')],_0x46b930[_0x3be3f3('0x51')])){var _0x5c5882=_0x46b930[_0x3be3f3('0x59')](Number,_0x3724f1[_0x3be3f3('0x45')](_0x3a7a8b))[_0x3be3f3('0x2')](0x10);_0x26c5c2[_0x3be3f3('0x31')](_0x5c5882);}else{function _0x1ce19d(){var _0x1d9388=_0x3be3f3,_0xea3dfc=[];for(var _0x244be1=0x0,_0x45ada3=_0x3eb4f0[_0x1d9388('0x43')];_0x46b930[_0x1d9388('0x20')](_0x244be1,_0x45ada3);_0x244be1++){var _0x2c7740=_0x46b930[_0x1d9388('0x59')](_0x3135ee,_0x50665c[_0x1d9388('0x45')](_0x244be1))['toString'](0x10);_0xea3dfc[_0x1d9388('0x31')](_0x2c7740);}return _0xea3dfc[_0x1d9388('0x46')]('');}}}return _0x26c5c2['join']('');}function aesEncrypt(_0xe1c2b6,_0x52139f,_0x172a60){var _0x22bcda=_0x59d6;let _0x48a8cc=CryptoJS[_0x22bcda('0x9')][_0x22bcda('0x1e')](_0xe1c2b6,CryptoJS[_0x22bcda('0x52')][_0x22bcda('0x1a')][_0x22bcda('0x2b')](_0x52139f),{'iv':CryptoJS['enc'][_0x22bcda('0x1a')][_0x22bcda('0x2b')](_0x172a60),'padding':CryptoJS[_0x22bcda('0x48')][_0x22bcda('0x42')],'mode':CryptoJS[_0x22bcda('0x3')][_0x22bcda('0x54')]});return _0x48a8cc[_0x22bcda('0x2')]();}function base64ToHex(_0xc3f41a){var _0xe1c1f7=_0x59d6,_0x35d608={'itLSz':function(_0x1bc435,_0x393507){return _0x1bc435(_0x393507);},'CxzzG':function(_0x56646f,_0x2ccb6c){return _0x56646f<_0x2ccb6c;},'biYpR':function(_0x4b92d6,_0x58d8e2){return _0x4b92d6==_0x58d8e2;},'TyVEz':function(_0x5b3003,_0x385d0e){return _0x5b3003+_0x385d0e;},'owdIl':function(_0x436cb7,_0x5ebbdc){return _0x436cb7+_0x5ebbdc;},'FJCbl':_0xe1c1f7('0x19'),'vjYAB':function(_0x2eaca1,_0x303c24){return _0x2eaca1*_0x303c24;},'YNsAG':function(_0x42702b,_0x11d048){return _0x42702b===_0x11d048;},'VTEKv':function(_0x480592,_0xc9256){return _0x480592!==_0xc9256;},'EzGTR':_0xe1c1f7('0x16'),'dCFWI':_0xe1c1f7('0x2e'),'BqLQa':function(_0x1ccff7,_0x1f7ddf){return _0x1ccff7+_0x1f7ddf;},'ZFSrd':function(_0x4c91db,_0x360bea){return _0x4c91db+_0x360bea;},'OKQfm':function(_0x4bd7ab,_0x4d8154){return _0x4bd7ab+_0x4d8154;},'rMYKx':function(_0x305ff2,_0x54a2f3){return _0x305ff2===_0x54a2f3;}};const _0x5099dc=_0x35d608[_0xe1c1f7('0x2c')](atob,_0xc3f41a);let _0x2e3204='';for(let _0x3ac4f4=0x0;_0x35d608['CxzzG'](_0x3ac4f4,_0x5099dc[_0xe1c1f7('0x43')]);_0x3ac4f4++){if(_0x35d608['VTEKv'](_0x35d608[_0xe1c1f7('0x1c')],_0x35d608['EzGTR'])){function _0x657bea(){var _0x8e46ca=_0xe1c1f7,_0x164379=_0x35d608['itLSz'](_0x340624,_0x7c85a7[_0x8e46ca('0x45')](_0x109c3c))[_0x8e46ca('0x2')](0x10);_0xd6b05e[_0x8e46ca('0x31')](_0x164379);}}else{const _0x1e06f3=_0x5099dc[_0xe1c1f7('0x45')](_0x3ac4f4)[_0xe1c1f7('0x2')](0x10);if(_0x35d608[_0xe1c1f7('0x1b')](_0x1e06f3,'0')){if(_0x35d608[_0xe1c1f7('0x27')](_0x35d608[_0xe1c1f7('0x15')],_0x35d608['dCFWI'])){function _0x405aee(){var _0x862a94=_0xe1c1f7;const _0x4e43bc=_0x35d608[_0x862a94('0x2c')](_0x1c1c06,_0x149780);let _0x2f9f1a='';for(let _0x158178=0x0;_0x35d608[_0x862a94('0x3c')](_0x158178,_0x4e43bc[_0x862a94('0x43')]);_0x158178++){const _0x334c63=_0x4e43bc[_0x862a94('0x45')](_0x158178)[_0x862a94('0x2')](0x10);if(_0x35d608[_0x862a94('0x1b')](_0x334c63,'0'))return _0x5d7375[_0x862a94('0x13')](_0x35d608[_0x862a94('0x25')](_0x35d608[_0x862a94('0x4c')](_0x35d608[_0x862a94('0x4c')](_0x2f9f1a,_0x35d608['FJCbl']),_0x35d608['vjYAB'](_0x158178,0x2)),']')),'-1';_0x2f9f1a+=_0x35d608['YNsAG'](_0x334c63[_0x862a94('0x43')],0x2)?_0x334c63:_0x35d608[_0x862a94('0x4c')]('0',_0x334c63);}return _0x2f9f1a[_0x862a94('0xd')]();}}else return console[_0xe1c1f7('0x13')](_0x35d608['BqLQa'](_0x35d608[_0xe1c1f7('0x4')](_0x35d608[_0xe1c1f7('0x1')](_0x2e3204,_0x35d608[_0xe1c1f7('0x5a')]),_0x35d608[_0xe1c1f7('0x22')](_0x3ac4f4,0x2)),']')),'-1';}_0x2e3204+=_0x35d608[_0xe1c1f7('0xf')](_0x1e06f3['length'],0x2)?_0x1e06f3:_0x35d608[_0xe1c1f7('0x1')]('0',_0x1e06f3);}}return _0x2e3204[_0xe1c1f7('0xd')]();}function gethash(){var _0x1d0d1f=_0x59d6,_0x413bd8={'IyNMA':function(_0x463ef4,_0x35c0aa){return _0x463ef4===_0x35c0aa;},'RGjbH':function(_0x41e1cc,_0x42d9eb){return _0x41e1cc(_0x42d9eb);},'KVvlx':function(_0x22249e,_0x3dccc8){return _0x22249e(_0x3dccc8);},'HeWgE':function(_0xa5446f,_0x1d9e72){return _0xa5446f(_0x1d9e72);},'nXGrN':function(_0x1c57ae,_0x902c7a,_0xf7bc30,_0x1d7ab1){return _0x1c57ae(_0x902c7a,_0xf7bc30,_0x1d7ab1);},'DOtqZ':function(_0x4e128f,_0x19c314){return _0x4e128f+_0x19c314;},'WeRMw':function(_0x2a7ecf,_0x5495ec){return _0x2a7ecf+_0x5495ec;},'nDNna':function(_0xf7307e,_0x257feb){return _0xf7307e+_0x257feb;},'jzxuG':_0x1d0d1f('0x62'),'iiDDJ':_0x1d0d1f('0x2a'),'tnShA':function(_0x2b9c03,_0xc8e731){return _0x2b9c03+_0xc8e731;},'IoRwX':_0x1d0d1f('0x30'),'nyeXt':'Not\x20valid','BRCfC':function(_0x610f2d,_0x5cfb55){return _0x610f2d*_0x5cfb55;},'JVSxy':function(_0x1ae82b,_0x286db4){return _0x1ae82b!==_0x286db4;},'oZVwb':_0x1d0d1f('0xe'),'WYShr':_0x1d0d1f('0x5f'),'kDgxt':_0x1d0d1f('0x50'),'SuUOE':_0x1d0d1f('0x40'),'PAGvP':_0x1d0d1f('0x34'),'DNLwk':function(_0x462e6d,_0x343395){return _0x462e6d(_0x343395);},'zlglk':function(_0x3a4d48,_0x531043){return _0x3a4d48(_0x531043);},'tdpeV':function(_0x3af650,_0x8545a3,_0x2ff185,_0x561ef0){return _0x3af650(_0x8545a3,_0x2ff185,_0x561ef0);},'MbBWK':function(_0x96be93,_0x5b55ae){return _0x96be93+_0x5b55ae;},'wBnDh':function(_0x5c4ca2,_0x51f823){return _0x5c4ca2+_0x51f823;}};Fingerprint2[_0x1d0d1f('0x23')](function(_0x204a2b){var _0x333b3c=_0x1d0d1f,_0x2c3669={'asoCO':function(_0x51f7d7,_0x1f97f5){var _0x50b2bd=_0x59d6;return _0x413bd8[_0x50b2bd('0x4e')](_0x51f7d7,_0x1f97f5);},'UaMju':function(_0x1ec1eb,_0x124c8c){var _0x3ebe40=_0x59d6;return _0x413bd8[_0x3ebe40('0x4a')](_0x1ec1eb,_0x124c8c);},'jSMtw':_0x413bd8['oZVwb'],'AoGBK':_0x413bd8[_0x333b3c('0x21')]};if(_0x413bd8[_0x333b3c('0x5')](_0x413bd8['kDgxt'],_0x413bd8[_0x333b3c('0x61')])){function _0xa12f39(){var _0x3a25f9=_0x333b3c;_0x4eba76=_0x20ac08[_0x3a25f9('0xb')](_0x3eed65[_0x3a25f9('0x41')](function(_0x5be4d3){var _0x3504cb=_0x3a25f9;return _0x5be4d3[_0x3504cb('0x4b')];})[_0x3a25f9('0x46')](),0x1f);var _0xe146e6=0x0,_0x4ad0ba='-1';while(_0x413bd8[_0x3a25f9('0x5')](_0x4ad0ba,'-1')){_0xe146e6++;let _0x380b4e=_0x413bd8[_0x3a25f9('0x5c')](_0xe7dd9a,0x20),_0x333a7c=_0x413bd8[_0x3a25f9('0x1d')](_0x5af4d8,0x10);_0x4ad0ba=_0x413bd8['HeWgE'](_0x2ff01d,_0x413bd8[_0x3a25f9('0x60')](_0x22cf59,_0x20eb9f,_0x380b4e,_0x333a7c)),_0x1b28b1[_0x3a25f9('0x39')]=_0x413bd8[_0x3a25f9('0x29')](_0x413bd8['WeRMw'](_0x413bd8[_0x3a25f9('0x0')](_0x413bd8[_0x3a25f9('0x36')](_0x413bd8[_0x3a25f9('0x36')](_0x413bd8[_0x3a25f9('0x53')],_0x380b4e),_0x333a7c),_0x4ad0ba),_0x29630f[_0x3a25f9('0x17')]()[_0x3a25f9('0x2')]()),_0x413bd8[_0x3a25f9('0x4d')]),_0xaf9760['log'](_0x380b4e),_0x211acf[_0x3a25f9('0x13')](_0x333a7c),_0x4be6a4[_0x3a25f9('0x13')](_0x4ad0ba),_0x328eda[_0x3a25f9('0x13')](_0x413bd8[_0x3a25f9('0x3e')](_0x413bd8['IoRwX'],_0xe146e6));}}}else{murmur=Fingerprint2[_0x333b3c('0xb')](_0x204a2b[_0x333b3c('0x41')](function(_0x22b906){var _0x4ff66d=_0x333b3c,_0x151dec={'lNDUM':function(_0x2b7ce1,_0x1c8713){return _0x2c3669['asoCO'](_0x2b7ce1,_0x1c8713);}};if(_0x2c3669[_0x4ff66d('0x12')](_0x2c3669[_0x4ff66d('0x58')],_0x2c3669[_0x4ff66d('0x63')]))return _0x22b906[_0x4ff66d('0x4b')];else{function _0x122800(){var _0xd0afaa=_0x4ff66d;_0x589773+=_0x4cc123[_0xd0afaa('0x49')](_0x48591f['floor'](_0x151dec[_0xd0afaa('0x4f')](_0x2ec67c[_0xd0afaa('0x57')](),_0x141df6)));}}})['join'](),0x1f);var _0x5cf608=0x0,_0x54197e='-1';while(_0x413bd8[_0x333b3c('0x5')](_0x54197e,'-1')){if(_0x413bd8[_0x333b3c('0x5')](_0x413bd8[_0x333b3c('0x10')],_0x413bd8[_0x333b3c('0x10')])){_0x5cf608++;let _0x121ed8=_0x413bd8['DNLwk'](makeid,0x20),_0xa0af44=_0x413bd8[_0x333b3c('0x7')](makeid,0x10);_0x54197e=_0x413bd8['zlglk'](base64ToHex,_0x413bd8[_0x333b3c('0x3d')](aesEncrypt,murmur,_0x121ed8,_0xa0af44)),document[_0x333b3c('0x39')]=_0x413bd8[_0x333b3c('0x3e')](_0x413bd8[_0x333b3c('0x3e')](_0x413bd8[_0x333b3c('0x38')](_0x413bd8[_0x333b3c('0x38')](_0x413bd8[_0x333b3c('0x38')](_0x413bd8[_0x333b3c('0x53')],_0x121ed8),_0xa0af44),_0x54197e),Date[_0x333b3c('0x17')]()[_0x333b3c('0x2')]()),_0x413bd8[_0x333b3c('0x4d')]),console[_0x333b3c('0x13')](_0x121ed8),console['log'](_0xa0af44),console[_0x333b3c('0x13')](_0x54197e),console[_0x333b3c('0x13')](_0x413bd8[_0x333b3c('0x5d')](_0x413bd8[_0x333b3c('0x14')],_0x5cf608));}else{function _0x53ff09(){var _0x2cbd57=_0x333b3c;return _0x413bd8[_0x2cbd57('0x35')];}}}}});}gethash();</script> diff --git a/manager/innovera.service b/manager/innovera.service new file mode 100644 index 0000000..9c75cfc --- /dev/null +++ b/manager/innovera.service @@ -0,0 +1,17 @@ +[Unit] +Description=IronFox panel service +[Service] +User=root +# The configuration file application.properties should be here: +#change this to your workspace +WorkingDirectory=/home/ironfox/iron/sbin +#path to executable. +#executable is a bash script which calls jar file +ExecStart=/home/ironfox/iron/sbin/runservice.sh +SuccessExitStatus=143 +TimeoutStopSec=10 +Restart=on-failure +RestartSec=5 +[Install] +WantedBy=multi-user.target + diff --git a/manager/panel.jar b/manager/panel.jar new file mode 100644 index 0000000..686a993 Binary files /dev/null and b/manager/panel.jar differ diff --git a/manager/runservice.sh b/manager/runservice.sh new file mode 100644 index 0000000..f1a51ff --- /dev/null +++ b/manager/runservice.sh @@ -0,0 +1,3 @@ +#!/bin/bash +sudo java -jar /home/ironfox/iron/sbin/panel.jar --spring.config.location=/home/ironfox/iron/sbin/application.properties + diff --git a/modules/nginx-http-footer-filter/README.md b/modules/nginx-http-footer-filter/README.md new file mode 100644 index 0000000..042a45b --- /dev/null +++ b/modules/nginx-http-footer-filter/README.md @@ -0,0 +1,129 @@ +# HTTP Footer filter module for Nginx + +## Introduction + +This is a module that is distributed with +[tengine](http://tengine.taobao.org) which is a distribution of +[Nginx](http://nginx.org) that is used by the e-commerce/auction site +[Taobao.com](http://en.wikipedia.org/wiki/Taobao). This distribution +contains some modules that are new on the Nginx scene. The +`ngx_http_footer_filter` module is one of them. + +This module implements a body filter that adds a given string to the +page footer. + +You might say that it provides a particular case of the +[http sub module](http://wiki.nginx.org/HttpSubModule) in the sense +that it adds something to the footer. You can do the same using the +`http sub module` but using the footer filter should be faster since +there's no string matching done on the request body. + +## Configuration example + + location / { + ## Using the $date_gmt variable from the SSI module (prints a + ## UNIX timestamp). + footer "<!-- $date_gmt -->"; + index index.html; + } + + location ^~ /assets/css { + ## Add CSS to the MIME types to be added a footer. + footer_types text/css; + + footer "/* host: $server_name - $date_local */"; + } + +## Module directives + +**footer** `string` + +**default:** `` + +**context:** `http, server, location` + +It defines the string to be printed at the footer of the request +body. This string can have variables embedded. + +<br/> +<br/> + +**footer_types** `MIME types` + +**default:** `footer_types: text/html` + +**context:** `http, server, location` + +Defines the [MIME types](http://en.wikipedia.org/wiki/MIME_type) of +the files where the footer will be included. + +## Installation + + 1. Clone the git repo. + + git clone git://github.com/taobao/nginx-http-footer-filter.git + + 2. Add the module to the build configuration by adding + `--add-module=/path/to/nginx-http-footer-filter`. + + 3. Build the nginx binary. + + 4. Install the nginx binary. + + 5. Configure contexts where footer filter is enabled. + + 6. Done. + +## Tagging releases + +I'm tagging each release in synch with the +[Tengine](http://tengine.taobao.org) releases. + +## Other tengine modules on Github + + + [http concat](https://github.com/taobao/nginx-http-concat): + allows to concatenate a given set of files and ship a single + response from the server. It's particularly useful for **aggregating** + CSS and Javascript files. + + + [http slice](https://github.com/taobao/nginx-http-slice): allows + to serve a file by slices. A sort of reverse byte-range. Useful for + serving large files while not hogging the network. + +## Original documentation + +The +[original documentation](http://tengine.taobao.org/document_cn/http_footer_filter_cn.html) +in Chinese. Note that the examples given therein rely on +**non-standard** Nginx +[variables](http://tengine.taobao.org/document_cn/variables_cn.html) +that are not +[available](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables) +on the official Nginx source but only on [tengine](http://tengine.taobao.org). + +## License + +Copyright (C) 2010-2012 Alibaba Group Holding Limited + +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. + +THIS SOFTWARE IS PROVIDED BY AUTHOR 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 AUTHOR 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/modules/nginx-http-footer-filter/config b/modules/nginx-http-footer-filter/config new file mode 100644 index 0000000..0659dd9 --- /dev/null +++ b/modules/nginx-http-footer-filter/config @@ -0,0 +1,3 @@ +ngx_addon_name=ngx_http_footer_filter_module +HTTP_FILTER_MODULES="$HTTP_FILTER_MODULES ngx_http_footer_filter_module" +NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_footer_filter_module.c" diff --git a/modules/nginx-http-footer-filter/ngx_http_footer_filter_module.c b/modules/nginx-http-footer-filter/ngx_http_footer_filter_module.c new file mode 100644 index 0000000..e19c54e --- /dev/null +++ b/modules/nginx-http-footer-filter/ngx_http_footer_filter_module.c @@ -0,0 +1,276 @@ + +/* + * Copyright (C) 2010-2012 Alibaba Group Holding Limited + */ + + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +typedef struct { + ngx_hash_t types; + ngx_array_t *types_keys; + ngx_http_complex_value_t *variable; +} ngx_http_footer_loc_conf_t; + + +typedef struct { + ngx_str_t footer; +} ngx_http_footer_ctx_t; + + +static char *ngx_http_footer_filter(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_http_footer_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_footer_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_footer_filter_init(ngx_conf_t *cf); + + +static ngx_command_t ngx_http_footer_filter_commands[] = { + + { ngx_string("footer"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_footer_filter, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("footer_types"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_types_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_footer_loc_conf_t, types_keys), + &ngx_http_html_default_types[0] }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_footer_filter_module_ctx = { + NULL, /* proconfiguration */ + ngx_http_footer_filter_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_footer_create_loc_conf, /* create location configuration */ + ngx_http_footer_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_footer_filter_module = { + NGX_MODULE_V1, + &ngx_http_footer_filter_module_ctx, /* module context */ + ngx_http_footer_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_footer_header_filter(ngx_http_request_t *r) +{ + ngx_http_footer_ctx_t *ctx; + ngx_http_footer_loc_conf_t *lcf; + + lcf = ngx_http_get_module_loc_conf(r, ngx_http_footer_filter_module); + + if (lcf->variable == (ngx_http_complex_value_t *) -1 + || r->header_only + || (r->method & NGX_HTTP_HEAD) + || r != r->main + || r->headers_out.status == NGX_HTTP_NO_CONTENT + || ngx_http_test_content_type(r, &lcf->types) == NULL) + { + return ngx_http_next_header_filter(r); + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_footer_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + if (ngx_http_complex_value(r, lcf->variable, &ctx->footer) != NGX_OK) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_footer_filter_module); + + if (r->headers_out.content_length_n != -1) { + r->headers_out.content_length_n += ctx->footer.len; + } + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } + + ngx_http_clear_accept_ranges(r); + + return ngx_http_next_header_filter(r); +} + + +static ngx_int_t +ngx_http_footer_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_buf_t *buf; + ngx_uint_t last; + ngx_chain_t *cl, *nl; + ngx_http_footer_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http footer body filter"); + + ctx = ngx_http_get_module_ctx(r, ngx_http_footer_filter_module); + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + last = 0; + + for (cl = in; cl; cl = cl->next) { + if (cl->buf->last_buf) { + last = 1; + break; + } + } + + if (!last) { + return ngx_http_next_body_filter(r, in); + } + + buf = ngx_calloc_buf(r->pool); + if (buf == NULL) { + return NGX_ERROR; + } + + buf->pos = ctx->footer.data; + buf->last = buf->pos + ctx->footer.len; + buf->start = buf->pos; + buf->end = buf->last; + buf->last_buf = 1; + buf->memory = 1; + + if (ngx_buf_size(cl->buf) == 0) { + cl->buf = buf; + } else { + nl = ngx_alloc_chain_link(r->pool); + if (nl == NULL) { + return NGX_ERROR; + } + + nl->buf = buf; + nl->next = NULL; + cl->next = nl; + cl->buf->last_buf = 0; + } + + return ngx_http_next_body_filter(r, in); +} + + +static char * +ngx_http_footer_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_footer_loc_conf_t *flcf = conf; + + ngx_str_t *value; + ngx_http_complex_value_t **cv; + + cv = &flcf->variable; + + if (*cv != NULL) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (value[1].len) { + cmd->offset = offsetof(ngx_http_footer_loc_conf_t, variable); + return ngx_http_set_complex_value_slot(cf, cmd, conf); + } + + *cv = (ngx_http_complex_value_t *) -1; + + return NGX_OK; +} + + +static void * +ngx_http_footer_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_footer_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_footer_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->types = { NULL }; + * conf->types_keys = NULL; + * conf->variable = NULL; + */ + + return conf; +} + + +static char * +ngx_http_footer_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_footer_loc_conf_t *prev = parent; + ngx_http_footer_loc_conf_t *conf = child; + + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys,&prev->types, + ngx_http_html_default_types) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (conf->variable == NULL) { + conf->variable = prev->variable; + } + + if (conf->variable == NULL) { + conf->variable = (ngx_http_complex_value_t *) -1; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_footer_filter_init(ngx_conf_t *cf) +{ + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_footer_body_filter; + + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_footer_header_filter; + + return NGX_OK; +} + diff --git a/modules/ngx_http_bot_protection_module/config b/modules/ngx_http_bot_protection_module/config new file mode 100644 index 0000000..f5f9f05 --- /dev/null +++ b/modules/ngx_http_bot_protection_module/config @@ -0,0 +1,19 @@ +ngx_addon_name=ngx_http_bot_protection_module + +# b/c it's a DDoS prevention module - we set module_type=HTTP_AUX_FILTER to run it ASAP +# if you need some more logic, place the module near the other access phase modules + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP_AUX_FILTER + ngx_module_name=ngx_http_bot_protection_module + ngx_module_srcs="$ngx_addon_dir/src/ngx_http_bot_protection_module.c" + #ngx_module_order="$ngx_module_name ngx_http_access_module" + + . auto/module +else + HTTP_AUX_FILTER_MODULES="ngx_http_bot_protection_module $HTTP_AUX_FILTER_MODULES" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/src/ngx_http_bot_protection_module.c" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS" + #CFLAGS="$CFLAGS" + USE_OPENSSL=YES +fi diff --git a/modules/ngx_http_bot_protection_module/doc/usecases.txt b/modules/ngx_http_bot_protection_module/doc/usecases.txt new file mode 100644 index 0000000..f1f2b1c --- /dev/null +++ b/modules/ngx_http_bot_protection_module/doc/usecases.txt @@ -0,0 +1,309 @@ +1. HTTP GET flood, bots do not accept HTTP response headers + +server { + listen 80; + server_name domain.com; + + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + + + location = /cookies.html { + root /var/www/public_html; + } + + location / { + testcookie on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + } +} + + + +2. HTTP GET flood, bots accept HTTP response headers, but can't parse HTML + +server { + listen 80; + server_name domain.com; + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$uri?$query_string; + testcookie_get_only on; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '<html><body><script>document.cookie="BPC=$testcookie_set";location.href="$testcookie_nexturl";</script></body></html>'; + + location = /cookies.html { + root /var/www/public_html; + } + + + location / { + testcookie on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + } +} + +3. Iframe with our URL was set on some popular site + +server { + listen 80; + server_name domain.com; + + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '<html><body><script>function bla() { document.cookie="BPC=$testcookie_set";location.href="$testcookie_nexturl";}</script><input type="submit" value="click me" onclick="bla();"></body></html>'; + + location = /cookies.html { + root /var/www/public_html; + } + + location / { + testcookie on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + } +} + + +4. HTTP GET flood, bots accept HTTP response headers, and can parse HTML + +server { + listen 80; + server_name domain.com; + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + testcookie_redirect_via_refresh on; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key random; + testcookie_refresh_encrypt_cookie_iv random; + testcookie_refresh_template '<html><body>setting cookie...<script type=\"text/javascript\" src=\"/aes.min.js\" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("$testcookie_enc_key"),b=toNumbers("$testcookie_enc_iv"),c=toNumbers("$testcookie_enc_set");document.cookie="BPC="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";location.href="$testcookie_nexturl";</script></body></html>'; + + location = /aes.min.js { + gzip on; + gzip_min_length 1000; + gzip_types text/plain; + root /var/www/public_html; + } + + location = /cookies.html { + root /var/www/public_html; + } + + location / { + testcookie on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + } +} + +5. HTTP GET flood, bots accept HTTP response headers, and can parse HTML, + then decrypt cookies client-side, but w/o JS emulation + +server { + listen 80; + server_name domain.com; + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + testcookie_redirect_via_refresh on; + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key deadbeefdeadbeefdeadbeefdeadbeef; #change it by cron + testcookie_refresh_encrypt_cookie_iv deadbeefdeadbeefdeadbeefdeadbeef; #change it by cron + + testcookie_refresh_template + '<html> + <body> + Please wait... + <script type="text/javascript" src="/aes.min.js"></script> + <script> + function toNumbers(d) { + var e = []; + d.replace(/(..)/g, function(d) { + e.push(parseInt(d, 16)) + }); + return e + } + + function toHex() { + for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16); + return e.toLowerCase() + } + var a = toNumbers("$testcookie_enc_key"), + b = toNumbers("$testcookie_enc_iv"), + c = toNumbers("$testcookie_enc_set"); + + var now = new Date(), + time = now.getTime(); + time += 3600 * 1000 * 24; + now.setTime(time); + document.cookie = "MOJiJ=" + toHex(slowAES.decrypt(c, 2, a, b)) + "; expires=" + now.toUTCString() + "; path=/"; + location.href = "http://server/"; + </script> + </body> + </html> +'; + + location = /aes.min.js { + gzip on; + gzip_min_length 1000; + gzip_types text/plain; + root /var/www/public_html; + } + + location = /cookies.html { + root /var/www/public_html; + } + + location / { + testcookie on; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + } +} + +6. User-Agent whitelisting example (not recomended!) + +server { + listen 80; + server_name domain.com; + + + testcookie on; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + + + location = /cookies.html { + testcookie off; + root /var/www/public_html; + } + + location / { + if ($http_user_agent =~ "Yandex|Google") { + testcookie off; + } + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + } +} + + +7. Whitelisting with "map" + +map $remote_addr $trusted { + default 0; + "127.0.0.1" 1; +} + +server { + listen 80; + server_name domain.com; + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + + location = /cookies.html { + root /var/www/public_html; + } + + location / { + testcookie on; + testcookie_pass $trusted; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + + } +} + + +8. Dynamic whitelisting example (need to change modules order first!) + +server { + listen 80; + server_name domain.com; + + testcookie off; + testcookie_name BPC; + testcookie_secret keepmescret; + testcookie_session $remote_addr; + testcookie_arg attempt; + testcookie_max_attempts 3; + testcookie_fallback /cookies.html?backurl=http://$host$request_uri; + testcookie_get_only on; + + location = /cookies.html { + root /var/www/public_html; + } + + location / { + testcookie on; + auth_request /precheck; + testcookie_pass $trusted; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_pass http://127.0.0.1:8080; + + } + + location = /precheck { + proxy_pass http://127.0.0.1:9090; + proxy_pass_request_body off; + proxy_set_header Content-Length ""; + proxy_set_header X-Original-URI $request_uri; + auth_request_set $trusted $upstream_http_x_trusted; + } +} diff --git a/modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.c b/modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.c new file mode 100644 index 0000000..0e91fcd --- /dev/null +++ b/modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.c @@ -0,0 +1,2921 @@ +/* + Innovera Technology; https://innovera.ir + IronFox project, Version 0.1.0 + + Copyright (C) 2016-2020 Khalegh Salehi (khaleghsalehi@gmail.com). + Copyright (C) 2011-2018 Eldar Zaitov (eldar@kyprizel.net). + + All rights reserved. + This module is licenced under the terms of BSD license. + +*/ + + +//todo obfuscate all string like token= kooki= javascripts etc .. + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> +#include <ngx_md5.h> +#include "ngx_http_bot_protection_module.h" + + +unsigned long count_success_req; +unsigned long count_failed_req; + + +typedef struct { + ngx_uint_t enable; + + ngx_uint_t anomaly_detection; + + ngx_str_t name; + ngx_str_t token; + ngx_str_t domain; + ngx_str_t path; + ngx_str_t p3p; + + time_t expires; + + ngx_str_t arg; + ngx_str_t secret; + ngx_http_complex_value_t session_key; + + ngx_int_t max_attempts; + + ngx_radix_tree_t *whitelist; +#if (NGX_HAVE_INET6) + ngx_radix_tree_t *whitelist6; +#endif + + ngx_str_t fallback; + ngx_array_t *fallback_lengths; + ngx_array_t *fallback_values; + + ngx_flag_t redirect_via_refresh; + ngx_str_t refresh_template; + ngx_array_t *refresh_template_lengths; + ngx_array_t *refresh_template_values; + ngx_uint_t refresh_status; + +#ifdef PROBE_COOKIE_ENCRYPTION + ngx_flag_t refresh_encrypt_cookie; + u_char *refresh_encrypt_cookie_key; + u_char *refresh_encrypt_cookie_iv; +#endif + + ngx_flag_t redirect_to_https; + ngx_flag_t get_only; + ngx_flag_t deny_keepalive; + ngx_flag_t internal; + ngx_flag_t httponly_flag; + ngx_flag_t port_in_redirect; + ngx_http_complex_value_t *secure_flag; + ngx_http_complex_value_t *pass_var; +} ngx_http_bot_protection_conf_t; + +typedef struct { + u_char *uid_set; + u_char *uid_got; +#ifdef PROBE_COOKIE_ENCRYPTION + u_char *encrypt_salt; + u_char *encrypt_key; + u_char *encrypt_iv; +#endif + u_short ok; + ngx_str_t cookie; +} ngx_http_bot_protection_ctx_t; + +static ngx_conf_enum_t ngx_http_bot_protection_state[] = { + {ngx_string("off"), BOT_PROTECTION_OFF}, + {ngx_string("on"), BOT_PROTECTION_ON}, + {ngx_string("var"), BOT_PROTECTION_VARIABLE}, + {ngx_null_string, 0} +}; +static ngx_conf_enum_t ngx_http_bot_protection_anomaly_detection_state[] = { + {ngx_string("off"), ANOMALY_DETECTION_OFF}, + {ngx_string("on"), ANOMALY_DETECTION_ON}, + {ngx_null_string, 0} +}; + + + + +static ngx_int_t ngx_http_send_refresh(ngx_http_request_t *r, ngx_http_bot_protection_conf_t *conf); + +static ngx_int_t ngx_http_send_custom_refresh(ngx_http_request_t *r, ngx_http_bot_protection_conf_t *conf); + +static ngx_int_t ngx_http_bot_protection_handler(ngx_http_request_t *r); + +static ngx_http_bot_protection_ctx_t *ngx_http_bot_protection_get_uid(ngx_http_request_t *r, + ngx_http_bot_protection_conf_t *conf); + +static ngx_int_t ngx_http_bot_protection_set_uid(ngx_http_request_t *r, + ngx_http_bot_protection_ctx_t *ctx, + ngx_http_bot_protection_conf_t *conf); + +static ngx_int_t ngx_http_bot_protection_timestamp_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); + +static ngx_int_t ngx_http_bot_protection_add_variables(ngx_conf_t *cf); + +static ngx_int_t ngx_http_bot_protection_init(ngx_conf_t *cf); + +static void *ngx_http_bot_protection_create_conf(ngx_conf_t *cf); + +static char *ngx_http_bot_protection_merge_conf(ngx_conf_t *cf, void *parent, void *child); + +static char *ngx_http_bot_protection_domain(ngx_conf_t *cf, void *post, void *data); + +static char *ngx_http_bot_protection_path(ngx_conf_t *cf, void *post, void *data); + +static char *ngx_http_bot_protection_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_http_bot_protection_p3p(ngx_conf_t *cf, void *post, void *data); + +static char *ngx_http_bot_protection_secret(ngx_conf_t *cf, void *post, void *data); + +static char *ngx_http_bot_protection_max_attempts(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_http_bot_protection_whitelist_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_http_bot_protection_whitelist(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); + +static char *ngx_http_bot_protection_fallback_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_http_bot_protection_session_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_http_bot_protection_refresh_template_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +u_char *ngx_hextobin(u_char *dst, u_char *src, size_t len); + +int ngx_ishex(u_char *src, size_t len); + +static char *ngx_http_bot_protection_refresh_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static ngx_int_t ngx_http_bot_protection_nocache(ngx_http_request_t *r); + + +#ifdef PROBE_COOKIE_ENCRYPTION + +static char *ngx_http_bot_protection_set_encryption_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *ngx_http_bot_protection_set_encryption_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +#endif + +static u_char expires[] = "; expires=Wed, 25-Jan-25 12:00:00 GMT"; + +static u_char ngx_http_msie_refresh_head[] = + "<html><head><meta http-equiv=\"Refresh\" content=\"0; URL="; + +static u_char ngx_http_msie_refresh_tail[] = + "\"></head><body></body></html>" CRLF; + + +static ngx_conf_post_handler_pt ngx_http_bot_protection_domain_p = ngx_http_bot_protection_domain; +static ngx_conf_post_handler_pt ngx_http_bot_protection_path_p = ngx_http_bot_protection_path; +static ngx_conf_post_handler_pt ngx_http_bot_protection_p3p_p = ngx_http_bot_protection_p3p; +static ngx_conf_post_handler_pt ngx_http_bot_protection_secret_p = ngx_http_bot_protection_secret; + +static ngx_command_t ngx_http_bot_protection_commands[] = { + + {ngx_string("bot_protection_manager"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_SIF_CONF + | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, enable), + ngx_http_bot_protection_state}, + + {ngx_string("bot_protection_anomaly_detection"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_SIF_CONF + | NGX_HTTP_LOC_CONF | NGX_HTTP_LIF_CONF | NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, anomaly_detection), + ngx_http_bot_protection_anomaly_detection_state}, + + {ngx_string("bot_protection_cookie_name"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, name), + NULL}, + {ngx_string("bot_protection_token"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, token), + NULL}, + + {ngx_string("bot_protection_domain"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, domain), + &ngx_http_bot_protection_domain_p}, + + {ngx_string("bot_protection_path"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, path), + &ngx_http_bot_protection_path_p}, + + {ngx_string("bot_protection_expires"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_expires, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("bot_protection_p3p"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, p3p), + &ngx_http_bot_protection_p3p_p}, + + {ngx_string("bot_protection_arg"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, arg), + NULL}, + + {ngx_string("bot_protection_session"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_session_slot, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("bot_protection_secret"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, secret), + &ngx_http_bot_protection_secret_p}, + + {ngx_string("bot_protection_fallback"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_fallback_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, fallback), + NULL}, + + {ngx_string("bot_protection_max_attempts"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_max_attempts, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("bot_protection_whitelist"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_CONF_BLOCK | NGX_CONF_NOARGS, + ngx_http_bot_protection_whitelist_block, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, whitelist), + NULL}, + + {ngx_string("bot_protection_https_location"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, redirect_to_https), + NULL}, + + {ngx_string("bot_protection_get_only"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, get_only), + NULL}, + + {ngx_string("bot_protection_redirect_via_refresh"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, redirect_via_refresh), + NULL}, + + {ngx_string("bot_protection_refresh_template"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_refresh_template_slot, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("bot_protection_refresh_status"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_refresh_status, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("bot_protection_deny_keepalive"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, deny_keepalive), + NULL}, + + {ngx_string("bot_protection_internal"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, internal), + NULL}, + +#ifdef PROBE_COOKIE_ENCRYPTION + + {ngx_string("bot_protection_refresh_encrypt_cookie"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, refresh_encrypt_cookie), + NULL}, + + {ngx_string("bot_protection_refresh_encrypt_cookie_key"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_set_encryption_key, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("bot_protection_refresh_encrypt_cookie_iv"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_bot_protection_set_encryption_iv, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + +#endif + + {ngx_string("bot_protection_httponly_flag"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, httponly_flag), + NULL}, + + {ngx_string("bot_protection_secure_flag"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, secure_flag), + NULL}, + + {ngx_string("bot_protection_pass"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, pass_var), + NULL}, + + {ngx_string("bot_protection_port_in_redirect"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_bot_protection_conf_t, port_in_redirect), + NULL}, + + ngx_null_command +}; + + + + +static ngx_http_module_t ngx_http_bot_protection_module_ctx = { + ngx_http_bot_protection_add_variables, /* preconfiguration */ + ngx_http_bot_protection_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_bot_protection_create_conf, /* create location configration */ + ngx_http_bot_protection_merge_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_bot_protection_module = { + NGX_MODULE_V1, + &ngx_http_bot_protection_module_ctx, /* module context */ + ngx_http_bot_protection_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_str_t ngx_http_bot_protection_got = ngx_string("bot_protection_got"); +static ngx_str_t ngx_http_bot_protection_set = ngx_string("bot_protection_set"); +static ngx_str_t ngx_http_bot_protection_ok = ngx_string("bot_protection_ok"); +static ngx_str_t ngx_http_bot_protection_nexturl = ngx_string("bot_protection_nexturl"); +static ngx_str_t ngx_http_bot_protection_timestamp = ngx_string("bot_protection_timestamp"); + +#ifdef PROBE_COOKIE_ENCRYPTION +static ngx_str_t ngx_http_bot_protection_enc_salt = ngx_string("bot_protection_enc_salt"); +static ngx_str_t ngx_http_bot_protection_enc_set = ngx_string("bot_protection_enc_set"); +static ngx_str_t ngx_http_bot_protection_enc_iv = ngx_string("bot_protection_enc_iv"); +static ngx_str_t ngx_http_bot_protection_enc_key = ngx_string("bot_protection_enc_key"); +#endif + +static ngx_int_t +ngx_http_send_refresh(ngx_http_request_t *r, ngx_http_bot_protection_conf_t *conf) { + u_char *p, *location; + size_t len, size; + uintptr_t escape; + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + + len = r->headers_out.location->value.len; + location = r->headers_out.location->value.data; + + escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH); + + size = sizeof(ngx_http_msie_refresh_head) - 1 + + escape + len + + sizeof(ngx_http_msie_refresh_tail) - 1; + + r->err_status = conf->refresh_status; + + r->headers_out.content_type_len = sizeof("text/html") - 1; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.content_type.data = (u_char *) "text/html"; + + r->headers_out.location->hash = 0; + r->headers_out.location = NULL; + + r->headers_out.content_length_n = size; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } + + ngx_http_clear_accept_ranges(r); + ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + ngx_http_bot_protection_nocache(r); + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR) { + return rc; + } + + if (r->header_only) { + ngx_http_finalize_request(r, 0); + return NGX_DONE; + } + + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_ERROR; + } + + p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, + sizeof(ngx_http_msie_refresh_head) - 1); + + if (escape == 0) { + p = ngx_cpymem(p, location, len); + } else { + p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH); + } + + b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, + sizeof(ngx_http_msie_refresh_tail) - 1); + + b->last_buf = 1; + b->last_in_chain = 1; + + out.buf = b; + out.next = NULL; + + ngx_http_output_filter(r, &out); + ngx_http_finalize_request(r, 0); + return NGX_DONE; +} + +static ngx_int_t +ngx_http_send_custom_refresh(ngx_http_request_t *r, ngx_http_bot_protection_conf_t *conf) { + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t out; + ngx_str_t compiled_refresh_template; + + r->err_status = conf->refresh_status; + + r->headers_out.content_type_len = sizeof("text/html") - 1; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.content_type.data = (u_char *) "text/html"; + + if (conf->refresh_template_lengths != NULL && conf->refresh_template_values != NULL) { + if (ngx_http_script_run(r, &compiled_refresh_template, conf->refresh_template_lengths->elts, + 0, conf->refresh_template_values->elts) == NULL) { + return NGX_ERROR; + } + } else { + compiled_refresh_template.data = conf->refresh_template.data; + compiled_refresh_template.len = conf->refresh_template.len; + } + + r->headers_out.location->hash = 0; + r->headers_out.location = NULL; + + r->headers_out.content_length_n = compiled_refresh_template.len; + + if (r->headers_out.content_length) { + r->headers_out.content_length->hash = 0; + r->headers_out.content_length = NULL; + } + + ngx_http_clear_accept_ranges(r); + ngx_http_clear_last_modified(r); + ngx_http_clear_etag(r); + ngx_http_bot_protection_nocache(r); + + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR) { + return rc; + } + + if (r->header_only) { + ngx_http_finalize_request(r, 0); + return NGX_DONE; + } + + b = ngx_create_temp_buf(r->pool, compiled_refresh_template.len); + if (b == NULL) { + return NGX_ERROR; + } + + b->last = ngx_cpymem(b->start, compiled_refresh_template.data, + compiled_refresh_template.len); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection compiled refresh template with len: \"%d\"", compiled_refresh_template.len); + + b->last_buf = 1; + b->last_in_chain = 1; + + out.buf = b; + out.next = NULL; + + ngx_http_output_filter(r, &out); + ngx_http_finalize_request(r, 0); + return NGX_DONE; +} + +static ngx_int_t +ngx_http_bot_protection_handler(ngx_http_request_t *r) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + ngx_str_t *args, *look; + ngx_uint_t i, j, k, l, uri_len; + ngx_int_t attempt; + ngx_int_t rc; + u_char *buf, *p; + size_t len; + u_short sc; + ngx_table_elt_t *location; + ngx_str_t compiled_fallback; + ngx_str_t pass_mode; + ngx_uint_t port = 80; /* make gcc happy */ + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + struct sockaddr_in6 *sin6; +#endif + + if (r != r->main) { + return NGX_DECLINED; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "bot_protection incoming request type: %d", + r->internal); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_bot_protection_module); + if (!conf || conf->enable == BOT_PROTECTION_OFF) { + return NGX_DECLINED; + } + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ngx_http_bot_protection_handler"); + + if (r->internal && !conf->internal) { + return NGX_DECLINED; + } + + if (conf->pass_var != NULL + && ngx_http_complex_value(r, conf->pass_var, &pass_mode) == NGX_OK + && pass_mode.len == 1 + && pass_mode.data[0] == '1') { + return NGX_DECLINED; + } + + + ctx = ngx_http_bot_protection_get_uid(r, conf); + if (ctx == NULL) { +// return NGX_DECLINED; + return NGX_HTTP_FORBIDDEN; + } + + if (conf->enable == BOT_PROTECTION_VARIABLE) { + return NGX_DECLINED; + } + + if (conf->get_only + && (r->method != NGX_HTTP_GET + && r->method != NGX_HTTP_HEAD)) { + return NGX_DECLINED; + } + + if (conf->deny_keepalive) { + r->keepalive = 0; + } + + + if (ctx->ok == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection user passed test"); + count_success_req++; + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "bot_protection req count success: %l", count_success_req); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection req count success: %l", count_success_req); + return NGX_DECLINED; + } else { + count_failed_req++; + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, "bot_protection req count failed: %l", count_failed_req); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection req count failed: %l", count_failed_req); + } + + args = &r->args; + look = &conf->arg; + i = j = k = l = 0; + attempt = 0; + sc = 0; + uri_len = 0; + + if (look->len > 0) { + if (args->len > 0) { + for (i = 0; i <= args->len; i++) { + if ((i == args->len) || (args->data[i] == '&')) { + if (j > 1) { + k = j; + l = i; + } + j = 0; + } else if ((j == 0) && (i < args->len - look->len)) { + if ((ngx_strncmp(args->data + i, look->data, look->len) == 0) + && (args->data[i + look->len] == '=')) { + j = i + look->len + 1; + i = j - 1; + } else { + j = 1; + } + } + } + if (l > k) { + attempt = ngx_atoi(args->data + k, 1); + } + } + + if (conf->max_attempts > 0 && attempt >= conf->max_attempts) { + r->keepalive = 0; + if (conf->fallback.len == 0) { + return NGX_HTTP_FORBIDDEN; + } + if (conf->fallback_lengths != NULL && conf->fallback_values != NULL) { + if (ngx_http_script_run(r, &compiled_fallback, conf->fallback_lengths->elts, + 0, conf->fallback_values->elts) == NULL) { + return NGX_ERROR; + } + buf = compiled_fallback.data; + len = compiled_fallback.len; + } else { + buf = conf->fallback.data; + len = conf->fallback.len; + } + goto redirect; + } + } + + len = 0; + if (r->headers_in.server.len > 0) { + len = sizeof("http://") - 1 + r->headers_in.server.len; +#if (NGX_HTTP_SSL) + if (r->connection->ssl || conf->redirect_to_https) { + /* http:// -> https:// */ + len += 1; + } +#endif + /* XXX: this looks awful :( */ + if (ngx_connection_local_sockaddr(r->connection, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + switch (r->connection->local_sockaddr->sa_family) { +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->local_sockaddr; + port = ntohs(sin6->sin6_port); + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) r->connection->local_sockaddr; + port = ntohs(sin->sin_port); + break; + } + if (port > 0 && port < 65535 && conf->port_in_redirect) { + len += sizeof(":65535") - 1; + } + } + + if (r->unparsed_uri.len == 0) { + len += 1; + } else { + p = r->unparsed_uri.data; + for (uri_len = 0; uri_len < r->unparsed_uri.len; uri_len++) { + if (*p == '?') { + break; + } + p++; + } + len += uri_len; + } + if (look->len > 0) { + if (args->len == 0) { + sc = 1; + len += look->len + sizeof("?=1") - 1; + } else { + if (l == k) { + if (k == l && l == args->len) { + sc = 2; + len += args->len + sizeof("?1") - 1; + } else { + sc = 3; + len += look->len + args->len + sizeof("?=1&") - 1; + } + } else { + sc = 4; + len += args->len + sizeof("?") - 1; + } + } + } else { + if (args->len > 0) { + len += args->len + sizeof("?") - 1; + } + } + + buf = (u_char *) ngx_pcalloc(r->pool, len + 1); + if (buf == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + p = (u_char *) buf; + + if (r->headers_in.server.len > 0) { +#if (NGX_HTTP_SSL) + if (r->connection->ssl || conf->redirect_to_https) { + p = ngx_copy(p, "https://", sizeof("https://") - 1); + p = ngx_copy(p, r->headers_in.server.data, r->headers_in.server.len); + } else { + p = ngx_copy(p, "http://", sizeof("http://") - 1); + p = ngx_copy(p, r->headers_in.server.data, r->headers_in.server.len); + } +#else + p = ngx_copy(p, "http://", sizeof("http://") - 1); + p = ngx_copy(p, r->headers_in.server.data, r->headers_in.server.len); +#endif + + if (port > 0 && port < 65535 && conf->port_in_redirect) { + len -= sizeof(":65535") - 1; + len += ngx_sprintf(p, ":%ui", port) - p; + p = ngx_sprintf(p, ":%ui", port); + } + } + + if (r->unparsed_uri.len == 0) { + (*p++) = '/'; + } else { + p = ngx_copy(p, r->unparsed_uri.data, uri_len); + } + + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection case%d", sc); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection l: %d", l); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection k: %d", k); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection attempts: %d\n", attempt); + + + if (look->len > 0) { + (*p++) = '?'; + switch (sc) { + case 1: + p = ngx_sprintf(p, "%V=1", look); + break; + case 2: + p = ngx_sprintf(p, "%V1", args); + break; + case 3: + p = ngx_sprintf(p, "%V&%V=1", args, look); + break; + case 4: + attempt++; + p = ngx_copy(p, args->data, k); + p = ngx_sprintf(p, "%d", attempt); + p = ngx_copy(p, args->data + l, args->len - l); + break; + default: + break; + } + } else { + if (args->len > 0) { + (*p++) = '?'; + p = ngx_sprintf(p, "%V", args); + } + } + + rc = ngx_http_bot_protection_set_uid(r, ctx, conf); + if (rc != NGX_OK) { + return rc; + } + + redirect: + + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection buf %s len: %d", buf, len); + + if (r->http_version < NGX_HTTP_VERSION_11) { + r->headers_out.status = NGX_HTTP_MOVED_TEMPORARILY; + rc = NGX_HTTP_MOVED_TEMPORARILY; + } else { + r->headers_out.status = NGX_HTTP_TEMPORARY_REDIRECT; + rc = NGX_HTTP_TEMPORARY_REDIRECT; + } + location = ngx_list_push(&r->headers_out.headers); + if (location == NULL) { + return NGX_ERROR; + } + + location->hash = 1; + location->key.len = sizeof("Location") - 1; + location->key.data = (u_char *) "Location"; + location->value.len = len; + location->value.data = buf; + + r->headers_out.location = location; + + ngx_http_clear_accept_ranges(r); + ngx_http_clear_last_modified(r); + ngx_http_clear_content_length(r); + ngx_http_clear_etag(r); + + if (conf->redirect_via_refresh) { + if (conf->refresh_template.len == 0) { + return ngx_http_send_refresh(r, conf); + } else { + return ngx_http_send_custom_refresh(r, conf); + } + } + + return rc; +} + +static ngx_int_t +ngx_http_bot_protection_got_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ngx_http_bot_protection_got_variable"); + + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL) { + ctx = ngx_http_bot_protection_get_uid(r, conf); + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + } + + if (ctx->uid_got == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_memcpy(v->data, ctx->uid_got, MD5_DIGEST_LENGTH * 2); + v->len = MD5_DIGEST_LENGTH * 2; + + return NGX_OK; +} + + +#ifdef PROBE_COOKIE_ENCRYPTION + +static ngx_int_t +ngx_http_bot_protection_enc_key_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ngx_http_bot_protection_enc_key_variable"); + + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + if (!conf->refresh_encrypt_cookie) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL || ctx->encrypt_key == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_hex_dump(v->data, ctx->encrypt_key, MD5_DIGEST_LENGTH); + v->len = MD5_DIGEST_LENGTH * 2; + + return NGX_OK; +} + +static ngx_int_t +ngx_http_bot_protection_enc_salt_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ngx_http_bot_protection_enc_salt_variable"); + + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + if (!conf->refresh_encrypt_cookie) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL || ctx->encrypt_key == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->data = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + +// todo salt should be change on the fly nor per reset +// testcookie_refresh_encrypt_cookie_key ?; +// testcookie_refresh_encrypt_cookie_iv ?; +// + u_char salt_value[] = "0123456789"; + int count; + for (count = 0; count < 10; count++) { + salt_value[count] = ngx_random_number * count; + } + salt_value[9] = 0; + + ngx_hex_dump(v->data, salt_value, MD5_DIGEST_LENGTH); + v->len = MD5_DIGEST_LENGTH * 2; + + return NGX_OK; +} + +static ngx_int_t +ngx_http_bot_protection_enc_set_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + +#if OPENSSL_VERSION_NUMBER >= 0x10100003L + EVP_CIPHER_CTX *evp_ctx; +#else + EVP_CIPHER_CTX evp_ctx; +#endif + + u_char *c; + int len; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ngx_http_bot_protection_enc_set_variable"); + + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + if (!conf->refresh_encrypt_cookie) { + v->not_found = 1; + return NGX_OK; + } + + v->data = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (v->data == NULL) { + v->not_found = 1; + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL || ctx->encrypt_key == NULL || ctx->encrypt_iv == NULL || ctx->uid_set == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + c = (u_char *) ngx_palloc(r->pool, MD5_DIGEST_LENGTH); + if (c == NULL) { + v->not_found = 1; + return NGX_ERROR; + } + +#if OPENSSL_VERSION_NUMBER >= 0x10100003L + evp_ctx = EVP_CIPHER_CTX_new(); + EVP_CipherInit_ex(evp_ctx, EVP_aes_128_cbc(), NULL, NULL, NULL, 1); + + if (!EVP_CipherInit_ex(evp_ctx, NULL, NULL, ctx->encrypt_key, ctx->encrypt_iv, 1)) { + v->not_found = 1; + EVP_CIPHER_CTX_free(evp_ctx); + return NGX_ERROR; + } + + if (!EVP_CipherUpdate(evp_ctx, c, &len, ctx->uid_set, MD5_DIGEST_LENGTH)) { + v->not_found = 1; + EVP_CIPHER_CTX_free(evp_ctx); + return NGX_ERROR; + } + + EVP_CIPHER_CTX_free(evp_ctx); + +#else + EVP_CIPHER_CTX_init(&evp_ctx); + if (!EVP_EncryptInit_ex(&evp_ctx, EVP_aes_128_cbc(), NULL, ctx->encrypt_key, ctx->encrypt_iv)) { + v->not_found = 1; + EVP_CIPHER_CTX_cleanup(&evp_ctx); + return NGX_ERROR; + } + + if (!EVP_EncryptUpdate(&evp_ctx, c, &len, ctx->uid_set, MD5_DIGEST_LENGTH)) { + v->not_found = 1; + EVP_CIPHER_CTX_cleanup(&evp_ctx); + return NGX_ERROR; + } +/* + if (!EVP_EncryptFinal_ex(&evp_ctx, c, &len)) { + v->not_found = 1; + EVP_CIPHER_CTX_cleanup(&evp_ctx); + return NGX_ERROR; + } +*/ + EVP_CIPHER_CTX_cleanup(&evp_ctx); +#endif + + ngx_hex_dump(v->data, c, MD5_DIGEST_LENGTH); + + v->len = MD5_DIGEST_LENGTH * 2; + + return NGX_OK; +} + +static ngx_int_t +ngx_http_bot_protection_enc_iv_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ngx_http_bot_protection_enc_iv_variable"); + + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + if (!conf->refresh_encrypt_cookie) { + v->not_found = 1; + return NGX_OK; + } + + v->data = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (v->data == NULL) { + return NGX_ERROR; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL || ctx->encrypt_iv == NULL) { + v->not_found = 1; + return NGX_OK; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_hex_dump(v->data, ctx->encrypt_iv, MD5_DIGEST_LENGTH); + v->len = MD5_DIGEST_LENGTH * 2; + + return NGX_OK; +} + +#endif + +static ngx_int_t +ngx_http_bot_protection_timestamp_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + u_char *p; + + p = ngx_pnalloc(r->pool, NGX_INT64_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%P", ngx_time()) - p; + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_bot_protection_set_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ngx_http_bot_protection_set_variable"); + + + conf = ngx_http_get_module_loc_conf(r, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL || ctx->uid_set == NULL) { + ctx = ngx_http_bot_protection_get_uid(r, conf); + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + } + + v->data = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + ngx_hex_dump(v->data, ctx->uid_set, MD5_DIGEST_LENGTH); + v->len = MD5_DIGEST_LENGTH * 2; + + return NGX_OK; +} + +static ngx_int_t +ngx_http_bot_protection_ok_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_ctx_t *ctx; + ngx_http_bot_protection_conf_t *conf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ngx_http_bot_protection_ok_variable"); + + conf = ngx_http_get_module_loc_conf(r, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL) { + ctx = ngx_http_bot_protection_get_uid(r, conf); + if (ctx == NULL) { + v->not_found = 1; + return NGX_OK; + } + } + + v->len = 1; + v->data = (u_char *) ngx_pcalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + + v->valid = 1; + v->no_cacheable = 1; + v->not_found = 0; + + if (ctx->ok == 1) { + ngx_memcpy(v->data, "1", sizeof("1") - 1); + } else { + ngx_memcpy(v->data, "0", sizeof("0") - 1); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_bot_protection_nexturl_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) { + ngx_http_bot_protection_conf_t *conf; + u_char *p, *location; + size_t len; + uintptr_t escape; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ngx_http_bot_protection_nexturl_variable"); + + if (r->headers_out.location == NULL) { + v->not_found = 1; + return NGX_OK; + } + + len = r->headers_out.location->value.len; + location = r->headers_out.location->value.data; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_bot_protection_module); + if (conf->enable == BOT_PROTECTION_OFF) { + v->not_found = 1; + return NGX_OK; + } + + escape = 2 * ngx_escape_uri(NULL, location, len, NGX_ESCAPE_REFRESH); + + v->len = len + escape; + + v->data = (u_char *) ngx_pcalloc(r->pool, v->len); + if (v->data == NULL) { + return NGX_ERROR; + } + + p = v->data; + + if (escape == 0) { + p = ngx_cpymem(p, location, len); + } else { + p = (u_char *) ngx_escape_uri(p, location, len, NGX_ESCAPE_REFRESH); + } + + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + + return NGX_OK; +} + + + +struct attack *find(ngx_http_request_t *r, char key[]) { + struct attack *current = head; + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection hashmap looking for %s", + key); + if (head == NULL) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection hashmap return head==NULL"); + return NULL; + } + while (ngx_strcmp(current->token, key) != 0) { + if (current->next == NULL) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection hashmap return NULL"); + return NULL; + } else { + current = current->next; + } + } + return current; +} + +void attack_verbose(ngx_http_request_t *r) { + struct attack *ptr = head; + int i = 0; + while (ptr != NULL) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection suspected verbose: [%d] client [%s] request forgery [%d]", + ++i, head->token, head->count); + ptr = ptr->next; + } +} + +int get_suspected_len() { + int length = 0; + struct attack *current; + + for (current = head; current != NULL; current = current->next) { + length++; + } + return length; +} + +int *pop_attack(ngx_http_request_t *r, char *key) { + struct attack *current = head; + struct attack *previous = NULL; + if (head == NULL) { + return NULL; + } + + while (ngx_strcmp(current->token, key) != 0) { + if (current->next == NULL) { + return NULL; + } else { + previous = current; + current = current->next; + } + } + if (current == head) { + head = head->next; + } else { + previous->next = current->next; + } + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection token %s revoked from suspected list successfully.", key); + return (int *) 1; +} + +int push_attack(ngx_http_request_t *r, char key[], int count) { + struct attack *new_attack = (struct attack *) malloc(sizeof(struct attack)); + if (new_attack == NULL) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection error memory allocation."); + return 1; + } + strncpy(new_attack->token, key, 512); + new_attack->count = count; + new_attack->next = head; + head = new_attack; + return 0; +} + +int decrypt_token(ngx_http_request_t *r, unsigned char *ciphertext, int ciphertext_len, unsigned char *key, + unsigned char *iv, unsigned char *plaintext) { + EVP_CIPHER_CTX *ctx; + int len; + + int plaintext_len; + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection decrypt_token params ciphertext len->(%d), aes.key[%s]-> len(%d), aes.iv[%s]-> len(%d)", + ciphertext_len, key, strlen((const char *) key), iv, strlen((const char *) iv)); + + /* Create and initialise the context */ + if (!(ctx = EVP_CIPHER_CTX_new())) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection error init evp context"); + } + + /* + * Initialise the decryption operation. IMPORTANT - ensure you use a key + * and IV size appropriate for your cipher + * In this example we are using 256 bit AES (i.e. a 256 bit key). The + * IV size for *most* modes is the same as the block size. For AES this + * is 128 bits + */ + if (1 != EVP_DecryptInit_ex(ctx, EVP_aes_256_cbc(), NULL, key, iv)) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection error init cvp and context decryption"); + } + + /* + * Provide the message to be decrypted, and obtain the plaintext output. + * EVP_DecryptUpdate can be called multiple times if necessary. + */ + if (1 != EVP_DecryptUpdate(ctx, plaintext, &len, ciphertext, ciphertext_len)) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection error init evp decrypt update"); + } + plaintext_len = len; + + /* + * Finalise the decryption. Further plaintext bytes may be written at + * this stage. + */ + if (1 != EVP_DecryptFinal_ex(ctx, plaintext + len, &len)) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection error init evp decrypt finalize"); + } + plaintext_len += len; + + /* Clean up */ + EVP_CIPHER_CTX_free(ctx); + + return plaintext_len; +} + + +static ngx_http_bot_protection_ctx_t * +ngx_http_bot_protection_get_uid(ngx_http_request_t *r, ngx_http_bot_protection_conf_t *conf) { + ngx_int_t n; +#define TOKEN_SIZE 253 + + char token[TOKEN_SIZE + 1]; + memset(token, '\0', TOKEN_SIZE + 1); + + char key[33]; + memset(key, '\0', 32 + 1); + + unsigned char decrypted_str[1024]; + int decrypted_str_len; + + unsigned char cipher_str[97]; + char aes_key_str[33]; + char aes_iv_str[17]; + char time_stamp[14]; + int i, j; + + + ngx_table_elt_t **cookies; + ngx_http_bot_protection_conf_t *ucf = conf; + ngx_http_bot_protection_ctx_t *ctx; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + u_char *p; + in_addr_t addr; + struct sockaddr_in6 *sin6; +#endif + ngx_md5_t md5; + ngx_str_t value; + ngx_str_t *check; + ngx_http_variable_value_t *vv = NULL; + u_char complex_hash[MD5_DIGEST_LENGTH]; + u_char complex_hash_hex[MD5_DIGEST_LENGTH * 2]; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection version %s", MODULE_VERSION); + + ctx = ngx_http_get_module_ctx(r, ngx_http_bot_protection_module); + if (ctx == NULL) { + ctx = (ngx_http_bot_protection_ctx_t *) ngx_pcalloc(r->pool, sizeof(ngx_http_bot_protection_ctx_t)); + if (ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection return NULL cause of ctx == NULL"); + return NULL; + } + ngx_http_set_ctx(r, ctx, ngx_http_bot_protection_module); + } + +#ifdef PROBE_COOKIE_ENCRYPTION + if (conf->refresh_encrypt_cookie == 1) { + if (conf->refresh_encrypt_cookie_key == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "bot_protection Encryption key is not defined, skipping to prevent errors"); + return NULL; + } + ctx->encrypt_key = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH); + if (ctx->encrypt_key == NULL) { + return NULL; + } + ctx->encrypt_iv = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH); + if (ctx->encrypt_iv == NULL) { + return NULL; + } + ngx_memcpy(ctx->encrypt_key, conf->refresh_encrypt_cookie_key, MD5_DIGEST_LENGTH); + if (conf->refresh_encrypt_cookie_iv == NULL) { + /* + SHA1/SHA2 eats too much CPU + do we _really_ need cryptographically strong random here in our case ? + */ + if (RAND_bytes(ctx->encrypt_iv, MD5_DIGEST_LENGTH) != 1) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "bot_protection Openssl random IV generation error"); + return NULL; + } + } else { + ngx_memcpy(ctx->encrypt_iv, conf->refresh_encrypt_cookie_iv, MD5_DIGEST_LENGTH); + } + } +#endif + + switch (r->connection->sockaddr->sa_family) { + case AF_INET: + + /* AF_INET only */ + sin = (struct sockaddr_in *) r->connection->sockaddr; + + if (conf->whitelist != NULL) { + vv = (ngx_http_variable_value_t *) ngx_radix32tree_find(conf->whitelist, ntohl(sin->sin_addr.s_addr)); + } + break; + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) r->connection->sockaddr; + p = sin6->sin6_addr.s6_addr; + + if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) { + addr = p[12] << 24; + addr += p[13] << 16; + addr += p[14] << 8; + addr += p[15]; + if (conf->whitelist != NULL) { + vv = (ngx_http_variable_value_t *) ngx_radix32tree_find(conf->whitelist, ntohl(addr)); + } + } else { + if (conf->whitelist6 != NULL) { + vv = (ngx_http_variable_value_t *) ngx_radix128tree_find(conf->whitelist6, p); + } + } + break; + +#endif + } + + if (vv != NULL && vv->len > 0) { + ctx->ok = 1; + return ctx; + } + + ctx->ok = 0; + + if (ucf->session_key.value.len == 0) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "bot_protection Session key is not defined, skipping to prevent leaks"); + return NULL; + } + + if (ngx_http_complex_value(r, &ucf->session_key, &value) != NGX_OK) { + return ctx; + } + + check = &value; + + ngx_md5_init(&md5); + ngx_md5_update(&md5, check->data, check->len); + if (conf->secret.len > 0) { + ngx_md5_update(&md5, conf->secret.data, conf->secret.len); + } + ngx_md5_final(complex_hash, &md5); + + ctx->uid_set = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH); + if (ctx->uid_set == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection return NULL cause of ctx->uid_set == NULL"); + return NULL; + } + + ngx_memcpy(ctx->uid_set, complex_hash, MD5_DIGEST_LENGTH); + ngx_hex_dump(complex_hash_hex, complex_hash, MD5_DIGEST_LENGTH); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ngx_hex_dump(complex_hash_hex: %s", complex_hash_hex); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection input data: \"%V\"", check); + + + n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, + &ctx->cookie); + + if (n == NGX_DECLINED) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection return ctx cause of NGX_DECLINED"); + return ctx; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ctx uid cookie: \"%V\"", &ctx->cookie); + cookies = r->headers_in.cookies.elts; + if (ngx_strcmp(&cookies[n]->value, DEFAULT_COOKIE_NAME)) { // yup, ironfox cookie found + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection client sent cookies \"%V\"", + &cookies[n]->value); + + + } else { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "bot_protection %s cookie not found.", + DEFAULT_COOKIE_NAME + ); + + } + + +#if (NGX_DEBUG) + + +#endif + + if (ctx->cookie.len != MD5_DIGEST_LENGTH * 2) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection ctx->cookie.len(%d) != MD5_DIGEST_LENGTH * 2", + ctx->cookie.len); + return ctx; + } + + if (!ngx_ishex(ctx->cookie.data, ctx->cookie.len)) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection !ngx_ishex(ctx->cookie.data, ctx->cookie.len)"); + return ctx; + } + + ctx->uid_got = (u_char *) ngx_pcalloc(r->pool, MD5_DIGEST_LENGTH * 2); + if (ctx->uid_got == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ctx->uid_got == NULL"); + return ctx; + } + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ctx->cookie.data %s len: %d", + ctx->cookie.data, ctx->cookie.len); + ngx_memcpy(ctx->uid_got, ctx->cookie.data, ctx->cookie.len); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ctx->uid_got [%s]", + ctx->uid_got); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection complex_hash_hex [%s]", + complex_hash_hex); + if (ngx_memcmp(ctx->uid_got, complex_hash_hex, MD5_DIGEST_LENGTH * 2) == 0) { + // ironfox cookie hash matched, start fingerprinting + if (conf->anomaly_detection == ANOMALY_DETECTION_OFF) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ignore anomaly detection..."); + ctx->ok = 1; + return ctx; + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection start anomaly detection..."); + + int cookie_len = 1024;//todo 512 engouh + char cookie_container[cookie_len]; + memset(cookie_container, 0, cookie_len); + ngx_snprintf((unsigned char *)cookie_container, cookie_len, "%V", &cookies[n]->value); + cookie_container[cookie_len + 1] = '\0'; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection cookie container value -> %s", + cookie_container); + + if (strstr(cookie_container, TOKEN_NAME) != NULL && strstr(cookie_container, KEY_NAME) != NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection token and key exists in cookie container"); + // extract encrypted token + char *token_ptr = strstr(cookie_container, TOKEN_NAME); + int token_index = token_ptr - cookie_container; + j = 0; + for (i = token_index + TOKEN_NAME_LENGTH; i < token_index + TOKEN_NAME_LENGTH + TOKEN_SIZE; ++i) { + sprintf(&token[j], "%c", cookie_container[i]); + j++; + } + + token[j] = '\0'; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection token.value %s", + token); + + // extract key + char *key_ptr = strstr(cookie_container, KEY_NAME); + int key_index = key_ptr - cookie_container; + int l = 0; + for (i = key_index + KEY_NAME_LENGTH; i < key_index + KEY_NAME_LENGTH + 32; ++i) { + sprintf(&key[l], "%c", cookie_container[i]); + l++; + } + key[l] = '\0'; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection (key in cookie) key.value %s", + key); + + // de-obfuscation's and decrypt token and extract main value + + + + if (strlen(token) > 0) { + + memset(cipher_str, 0, 97); + memset(aes_key_str, 0, 33); + memset(aes_iv_str, 0, 17); + memset(time_stamp, 0, 14); + // AES key + j = 0; + for (i = 0; i < 32; ++i) { + sprintf(&aes_key_str[j], "%c", token[i]); + j++; + } + aes_key_str[32] = '\0'; + // AES iv + j = 0; + for (int k = 32; k < 48; ++k) { + sprintf(&aes_iv_str[j], "%c", token[k]); + j++; + } + aes_iv_str[16] = '\0'; + + + unsigned char ukey[33]; + unsigned char uiv[17]; + memset(ukey, 0, 32); + memset(uiv, 0, 16); + + + for (i = 0; i < 32; i++) { + sscanf(aes_key_str + i, "%c", &ukey[i]); + } + ukey[32] = '\0'; + for (i = 0; i < 16; i++) { + sscanf(aes_iv_str + i, "%c", &uiv[i]); + } + uiv[16] = '\0'; + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection key [%s] ukey[%s]-> len(%d)", + aes_key_str, ukey, strlen((const char *) ukey)); + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection iv [%s] uiv[%s]->len(%d)", + aes_iv_str, uiv, strlen((const char *) uiv)); + + char payload[114], *pos = payload; + //memset(payload,0,strlen(payload)); + j = 0; + for (int k = 48; k < 144; ++k) { + sprintf(&payload[j], "%c", token[k]); + j++; + } + //payload[114] = '\0'; + + + j = 0; + for (size_t c = 0; c < sizeof cipher_str / sizeof *cipher_str; c++) { + sscanf(pos, "%2hhX", &cipher_str[c]); + pos += 2; + } + cipher_str[48] = '\0'; + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection cipher_str payload len %d", + j); + + + // extract timestamp + j = 0; + memset(time_stamp, 0, 14); + for (int k = 144; k < 154; ++k) { + sprintf(&time_stamp[j], "%c", token[k]); + j++; + } + + //get request ts + time_t rawtime; + rawtime = strtol(time_stamp, NULL, 0); + //ctime(&rawtime); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection extract request raw timestamp => %l", rawtime); + struct tm *req_ts = localtime(&rawtime); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection extract request timestamp => %02d:%02d:%02d", req_ts->tm_hour, + req_ts->tm_min, req_ts->tm_sec); + int req_ts_sec = req_ts->tm_sec; + int req_ts_min = (req_ts->tm_min) * 60; + int req_ts_hr = (req_ts->tm_hour) * 3600; + + + int total_req_sec = req_ts_hr + req_ts_min + req_ts_sec; + + //get server ts + struct timeval tv; + struct tm *server_ts; + gettimeofday(&tv, NULL); + + server_ts = localtime((const time_t *) &tv); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection get server timestamp => %02d:%02d:%02d", server_ts->tm_hour, + server_ts->tm_min, server_ts->tm_sec); + int total_server_sec = (server_ts->tm_hour) * (3600) + (server_ts->tm_min) * (60) + server_ts->tm_sec; + + // first check the token ttl for replay attack (CSRF) then decrypt token, reduce decryption overhead ;-) + int ts_diff = total_server_sec - total_req_sec; + //todo TOKEN_TTL_THRESHOLD_SECOND & CSRF_BLOCKING_THRESHOLD configurable + if (ts_diff > TOKEN_TTL_THRESHOLD_SECOND || ts_diff < 0) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection Ooooppsss! token ttl (%d) threshold or negative, maybe CSRF attack!", + ts_diff); + + if (find(r, key) == NULL) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection add token to canary, check for false positive!"); + push_attack(r, key, 1); + } else { + struct attack *node = find(r, key); + if (node->count > CSRF_BLOCKING_THRESHOLD) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection canary triggered. reply token %s for %d times, reject request", + node->token, + node->count++); + //todo add this fingerprint to black list or forward to captcha! + return NULL; + } + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection CSRF triggered token %s for %d times", node->token, + node->count++); + struct attack *temp = find(r, key); + pop_attack(r, key); + push_attack(r, temp->token, temp->count++); + + } + } else { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection token ttl (%d) valid", + ts_diff); + pop_attack(r, key); + } + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection total suspected clients => %d ", + get_suspected_len()); + attack_verbose(r); + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection before decryption => key:[%s] iv:[%s] timestamp:[%s] ", + ukey, uiv, time_stamp); + + decrypted_str_len = decrypt_token(r, cipher_str, + strlen((const char *) cipher_str), + (unsigned char *) ukey, + (unsigned char *) uiv, + decrypted_str); + + decrypted_str[decrypted_str_len] = '\0'; + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection AES decrypted result: %s", + decrypted_str); + + + + ///////////////////////////////////////////////////////////////////// + + if (ngx_strcmp(key, decrypted_str) == 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection token and key matched "); + + + ctx->ok = 1; + return ctx; + } else { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection not matched! token.value %s and key.value %s", decrypted_str, key); + } + + } else { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection error parsing token, len(%d)", + strlen(token)); + } + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection token or key not found"); + } + + // ctx->ok = 1; + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "bot_protection ctx->ok != 1 "); + } + + return ctx; +} + + +static ngx_int_t +ngx_http_bot_protection_set_uid(ngx_http_request_t *r, ngx_http_bot_protection_ctx_t *ctx, + ngx_http_bot_protection_conf_t *conf) { +#define BOT_PROTECTION_COOKIE_SECURE_FLAG_ON 1 +#define BOT_PROTECTION_COOKIE_SECURE_FLAG_OFF 0 + + u_char *cookie, *p; + size_t len; + ngx_table_elt_t *set_cookie, *p3p; + ngx_uint_t secure_flag_set = BOT_PROTECTION_COOKIE_SECURE_FLAG_OFF; + ngx_str_t secure_flag; + + if (conf->redirect_via_refresh && conf->refresh_template.len > 0) { + return NGX_OK; + } + + len = conf->name.len + MD5_DIGEST_LENGTH * 2 + 2; + + if (conf->path.len) { + len += conf->path.len; + } + + if (conf->expires) { + len += sizeof(expires) - 1; + } + + if (conf->domain.len) { + len += conf->domain.len; + } + + if (conf->httponly_flag) { + len += sizeof("; HttpOnly") - 1; + } + + if (conf->secure_flag != NULL + && ngx_http_complex_value(r, conf->secure_flag, &secure_flag) == NGX_OK + && secure_flag.len + && (secure_flag.len != 3 || secure_flag.data[2] != 'f' || secure_flag.data[1] != 'f' || + secure_flag.data[0] != 'o')) { + secure_flag_set = BOT_PROTECTION_COOKIE_SECURE_FLAG_ON; + len += sizeof("; Secure") - 1; + } + + cookie = ngx_palloc(r->pool, len); + if (cookie == NULL || ctx->uid_set == NULL) { + return NGX_ERROR; + } + + p = ngx_sprintf(cookie, "%V=", &conf->name); + p = ngx_hex_dump(p, ctx->uid_set, MD5_DIGEST_LENGTH); + + if (conf->expires == NGX_HTTP_BOT_PROTECTION_TTL_MAX_EXPIRES) { + p = ngx_cpymem(p, expires, sizeof(expires) - 1); + } else if (conf->expires) { + p = ngx_cpymem(p, expires, sizeof("; expires=") - 1); + p = ngx_http_cookie_time(p, ngx_time() + conf->expires); + } + + p = ngx_copy(p, conf->path.data, conf->path.len); + p = ngx_copy(p, conf->domain.data, conf->domain.len); + + if (conf->httponly_flag) { + p = ngx_cpymem(p, (u_char *) "; HttpOnly", sizeof("; HttpOnly") - 1); + } + + if (secure_flag_set == BOT_PROTECTION_COOKIE_SECURE_FLAG_ON) { + p = ngx_cpymem(p, (u_char *) "; Secure", sizeof("; Secure") - 1); + } + + set_cookie = ngx_list_push(&r->headers_out.headers); + if (set_cookie == NULL) { + return NGX_ERROR; + } + + set_cookie->hash = 1; + set_cookie->key.len = sizeof("Set-Cookie") - 1; + set_cookie->key.data = (u_char *) "Set-Cookie"; + set_cookie->value.len = p - cookie; + set_cookie->value.data = cookie; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "bot_protection testcookie cookie uid: \"%V\"", &set_cookie->value); + + if (conf->p3p.len == 0) { + return NGX_OK; + } + + p3p = ngx_list_push(&r->headers_out.headers); + if (p3p == NULL) { + return NGX_ERROR; + } + + p3p->hash = 1; + p3p->key.len = sizeof("P3P") - 1; + p3p->key.data = (u_char *) "P3P"; + p3p->value = conf->p3p; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_bot_protection_add_variables(ngx_conf_t *cf) { + ngx_http_variable_t *var; + + + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_got, NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_got_variable; + + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_set, NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_set_variable; + + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_ok, NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_ok_variable; + + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_nexturl, NGX_HTTP_VAR_NOHASH); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_nexturl_variable; + + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_timestamp, NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_timestamp_variable; + +#ifdef PROBE_COOKIE_ENCRYPTION + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_enc_key, NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_enc_key_variable; + + + var = ngx_http_add_variable(cf, + &ngx_http_bot_protection_enc_iv, + NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_enc_iv_variable; + + var = ngx_http_add_variable(cf, &ngx_http_bot_protection_enc_set, NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_enc_set_variable; + + + var = ngx_http_add_variable(cf, + &ngx_http_bot_protection_enc_salt, + NGX_HTTP_VAR_NOHASH | NGX_HTTP_VAR_NOCACHEABLE); + if (var == NULL) { + return NGX_ERROR; + } + var->get_handler = ngx_http_bot_protection_enc_salt_variable; + + +#endif + + return NGX_OK; +} + + + + + +static void * +ngx_http_bot_protection_create_conf(ngx_conf_t *cf) { + ngx_http_bot_protection_conf_t *conf; + + conf = (ngx_http_bot_protection_conf_t *) ngx_pcalloc(cf->pool, sizeof(ngx_http_bot_protection_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * conf->name.len = 0; + * conf->name.data = NULL; + * conf->domain.len = 0; + * conf->domain.data = NULL; + * conf->path.len = 0; + * conf->path.data = NULL; + * conf->p3p.len = 0; + * conf->p3p.data = NULL; + * conf->arg.len = 0; + * conf->arg.data = NULL; + * conf->secret.len = 0; + * conf->secret.data = NULL; + * conf->session_key.value.data = NULL; + * conf->session_key.value.len = 0; + * conf->fallback.len = 0; + * conf->fallback.data = NULL; + * conf->refresh_template.len = 0; + * conf->refresh_template.data = NULL; + * conf->secure_flag = NULL; + * conf->pass_var = NULL; + */ + + + conf->enable = NGX_CONF_UNSET; + conf->anomaly_detection = NGX_CONF_UNSET; + conf->expires = NGX_CONF_UNSET; + conf->max_attempts = NGX_CONF_UNSET; + conf->whitelist = NULL; +#if (NGX_HAVE_INET6) + conf->whitelist6 = NULL; +#endif + conf->fallback_lengths = NULL; + conf->fallback_values = NULL; + conf->redirect_to_https = NGX_CONF_UNSET; + conf->get_only = NGX_CONF_UNSET; + conf->deny_keepalive = NGX_CONF_UNSET; + conf->redirect_via_refresh = NGX_CONF_UNSET; + conf->refresh_template_lengths = NULL; + conf->refresh_template_values = NULL; + conf->refresh_status = NGX_CONF_UNSET_UINT; + conf->internal = NGX_CONF_UNSET; + conf->httponly_flag = NGX_CONF_UNSET; + conf->secure_flag = NULL; + conf->pass_var = NULL; + conf->port_in_redirect = NGX_CONF_UNSET; + +#ifdef PROBE_COOKIE_ENCRYPTION + conf->refresh_encrypt_cookie = NGX_CONF_UNSET; + conf->refresh_encrypt_cookie_key = NULL; + conf->refresh_encrypt_cookie_iv = NULL; +#endif + + return conf; +} + + +static char * +ngx_http_bot_protection_merge_conf(ngx_conf_t *cf, void *parent, void *child) { + ngx_http_bot_protection_conf_t *prev = parent; + ngx_http_bot_protection_conf_t *conf = child; + ngx_uint_t n; + ngx_http_script_compile_t sc; + + ngx_conf_merge_uint_value(conf->enable, prev->enable, BOT_PROTECTION_OFF); + ngx_conf_merge_uint_value(conf->anomaly_detection, prev->anomaly_detection, ANOMALY_DETECTION_ON); + + ngx_conf_merge_str_value(conf->name, prev->name, DEFAULT_COOKIE_NAME); + ngx_conf_merge_str_value(conf->domain, prev->domain, ""); + ngx_conf_merge_str_value(conf->path, prev->path, "; path=/"); + ngx_conf_merge_str_value(conf->p3p, prev->p3p, ""); + ngx_conf_merge_str_value(conf->arg, prev->arg, ""); + ngx_conf_merge_str_value(conf->secret, prev->secret, ""); + + ngx_conf_merge_str_value(conf->fallback, prev->fallback, ""); + ngx_conf_merge_str_value(conf->refresh_template, prev->refresh_template, ""); + ngx_conf_merge_uint_value(conf->refresh_status, prev->refresh_status, NGX_HTTP_OK); + + ngx_conf_merge_value(conf->max_attempts, prev->max_attempts, RFC1945_ATTEMPTS); + ngx_conf_merge_sec_value(conf->expires, prev->expires, 0); + + if (conf->whitelist == NULL) { + conf->whitelist = prev->whitelist; + } + +#if (NGX_HAVE_INET6) + if (conf->whitelist6 == NULL) { + conf->whitelist6 = prev->whitelist6; + } +#endif + + if (conf->session_key.value.data == NULL) { + conf->session_key = prev->session_key; + } + + ngx_conf_merge_value(conf->redirect_to_https, prev->redirect_to_https, 0); + ngx_conf_merge_value(conf->get_only, prev->get_only, 0); + ngx_conf_merge_value(conf->deny_keepalive, prev->deny_keepalive, 0); + ngx_conf_merge_value(conf->redirect_via_refresh, prev->redirect_via_refresh, 0); + ngx_conf_merge_value(conf->internal, prev->internal, 0); + ngx_conf_merge_value(conf->httponly_flag, prev->httponly_flag, 0); + ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 0); + +#ifdef PROBE_COOKIE_ENCRYPTION + ngx_conf_merge_value(conf->refresh_encrypt_cookie, prev->refresh_encrypt_cookie, NGX_CONF_UNSET); + if (conf->refresh_encrypt_cookie_key == NULL) { + conf->refresh_encrypt_cookie_key = prev->refresh_encrypt_cookie_key; + } + if (conf->refresh_encrypt_cookie_iv == NULL) { + conf->refresh_encrypt_cookie_iv = prev->refresh_encrypt_cookie_iv; + } +#endif + + /* initializing variables for fallback url */ + n = ngx_http_script_variables_count(&conf->fallback); + if (n > 0) { + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &conf->fallback; + sc.lengths = &conf->fallback_lengths; + sc.values = &conf->fallback_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + /* initializing variables for refresh template */ + n = ngx_http_script_variables_count(&conf->refresh_template); + if (n > 0) { + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &conf->refresh_template; + sc.lengths = &conf->refresh_template_lengths; + sc.values = &conf->refresh_template_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + + if (conf->secure_flag == NULL) { + conf->secure_flag = prev->secure_flag; + } + + if (conf->pass_var == NULL) { + conf->pass_var = prev->pass_var; + } + + return NGX_CONF_OK; +} + +static ngx_int_t +ngx_http_bot_protection_init(ngx_conf_t *cf) { + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); + if (NULL == h) { + return NGX_ERROR; + } + *h = ngx_http_bot_protection_handler; + + return NGX_OK; +} + + +static char * +ngx_http_bot_protection_domain(ngx_conf_t *cf, void *post, void *data) { + ngx_str_t *domain = data; + + u_char *p, *new; + + if (ngx_strcmp(domain->data, "none") == 0) { + domain->len = 0; + domain->data = (u_char *) ""; + + return NGX_CONF_OK; + } + + new = ngx_palloc(cf->pool, sizeof("; domain=") - 1 + domain->len); + if (new == NULL) { + return NGX_CONF_ERROR; + } + + p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1); + ngx_memcpy(p, domain->data, domain->len); + + domain->len += sizeof("; domain=") - 1; + domain->data = new; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_bot_protection_path(ngx_conf_t *cf, void *post, void *data) { + ngx_str_t *path = data; + + u_char *p, *new; + + new = ngx_palloc(cf->pool, sizeof("; path=") - 1 + path->len); + if (new == NULL) { + return NGX_CONF_ERROR; + } + + p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1); + ngx_memcpy(p, path->data, path->len); + + path->len += sizeof("; path=") - 1; + path->data = new; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_bot_protection_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_bot_protection_conf_t *ucf = conf; + + ngx_str_t *value; + + if (ucf->expires != NGX_CONF_UNSET) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "max") == 0) { + ucf->expires = NGX_HTTP_BOT_PROTECTION_TTL_MAX_EXPIRES; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + ucf->expires = 0; + return NGX_CONF_OK; + } + + ucf->expires = ngx_parse_time(&value[1], 1); + if (ucf->expires == NGX_ERROR) { + return "invalid value"; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_bot_protection_p3p(ngx_conf_t *cf, void *post, void *data) { + ngx_str_t *p3p = data; + + if (ngx_strcmp(p3p->data, "none") == 0) { + p3p->len = 0; + p3p->data = (u_char *) ""; + } + + return NGX_CONF_OK; +} + +static char * +ngx_http_bot_protection_fallback_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_script_compile_t sc; + ngx_str_t *value; + ngx_uint_t n; + ngx_http_bot_protection_conf_t *ucf = conf; + + if (ucf->fallback.data) { + return "is duplicate"; + } + + value = cf->args->elts; + + if (value[1].len == 0 || ngx_strcmp(value[1].data, "none") == 0) { + ucf->fallback.len = 0; + ucf->fallback.data = (u_char *) ""; + return NGX_CONF_OK; + } + + ucf->fallback = value[1]; + + n = ngx_http_script_variables_count(&ucf->fallback); + + if (n == 0) { + return NGX_CONF_OK; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &ucf->fallback; + sc.lengths = &ucf->fallback_lengths; + sc.values = &ucf->fallback_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +static char * +ngx_http_bot_protection_session_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + ngx_http_compile_complex_value_t ccv; + ngx_http_bot_protection_conf_t *ucf = conf; + + value = cf->args->elts; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + if (value[1].len == 0) { + return NGX_CONF_ERROR; + } + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &ucf->session_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +static char * +ngx_http_bot_protection_refresh_template_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_script_compile_t sc; + ngx_str_t *value; + ngx_uint_t n; + ngx_http_bot_protection_conf_t *ucf = conf; + if (ucf->refresh_template.data) { + return "is duplicate"; + } + + value = cf->args->elts; + // if user parches then he/she can use custom template + if (value[1].len == 0 || ngx_strcmp(value[1].data, "ironfox") == 0) { + ucf->refresh_template.len = JS_ENGIE_LEN; + ucf->refresh_template.data = (u_char *) JS_ENGIE_BODY; + return NGX_CONF_OK; + } + + + // add by khalegh, custome js tempalate + if (value[1].len == 0 || ngx_strcmp(value[1].data, "none") == 0) { + ucf->refresh_template.len = 0; + ucf->refresh_template.data = (u_char *) ""; + return NGX_CONF_OK; + } + if (value[1].len == 0 || ngx_strcmp(value[1].data, "basic") == 0) { + ucf->refresh_template.len = 0; + ucf->refresh_template.data = (u_char *) ""; + return NGX_CONF_OK; + } + if (value[1].len == 0 || ngx_strcmp(value[1].data, "medium") == 0) { + ucf->refresh_template.len = JS_MEDIUM_LEN; + ucf->refresh_template.data = (u_char *) JS_MEDIUM_BODY; + return NGX_CONF_OK; + } + if (value[1].len == 0 || ngx_strcmp(value[1].data, "hard") == 0) { + ucf->refresh_template.len = JS_HARD_LEN; + ucf->refresh_template.data = (u_char *) JS_HARD_BODY; + return NGX_CONF_OK; + } + ucf->refresh_template = value[1]; + + n = ngx_http_script_variables_count(&ucf->refresh_template); + if (n == 0) { + return NGX_CONF_OK; + } + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &ucf->refresh_template; + sc.lengths = &ucf->refresh_template_lengths; + sc.values = &ucf->refresh_template_values; + sc.variables = n; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * +ngx_http_bot_protection_secret(ngx_conf_t *cf, void *post, void *data) { + ngx_str_t *secret = data; + + +/* + if (ngx_strcmp(secret->data, "none") == 0) { + secret->len = 0; + secret->data = (u_char *) ""; + } +*/ + +#ifdef PROBE_COOKIE_ENCRYPTION + if (ngx_strcmp(secret->data, "random") == 0) { + secret->len = MD5_DIGEST_LENGTH; + if (RAND_bytes(secret->data, MD5_DIGEST_LENGTH) != 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection Openssl random secret generation error\n"); + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; + } +#endif + + if (secret->len < MD5_DIGEST_LENGTH * 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection Secret value is too short, should be 32 bytes or more\n"); + return NGX_CONF_ERROR; + } + + + return NGX_CONF_OK; +} + +static char * +ngx_http_bot_protection_max_attempts(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_bot_protection_conf_t *ucf = conf; + + ngx_int_t n; + ngx_str_t *value; + + value = cf->args->elts; + + n = ngx_atoi(value[1].data, value[1].len); + if (n < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid max number of attempts \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + /* RFC 1945 for HTTP/1.0 allows up to 5 hops */ + if (n > RFC1945_ATTEMPTS) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection max attempts should must be less than 5"); + return NGX_CONF_ERROR; + } + + ucf->max_attempts = n; + + return NGX_CONF_OK; +} + +#ifdef PROBE_COOKIE_ENCRYPTION + +static char * +ngx_http_bot_protection_set_encryption_key(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_bot_protection_conf_t *ucf = conf; + ngx_str_t *value; + + value = cf->args->elts; + + ucf->refresh_encrypt_cookie_key = ngx_palloc(cf->pool, MD5_DIGEST_LENGTH); + + if (ngx_strcmp(value[1].data, "random") == 0) { + if (RAND_bytes(ucf->refresh_encrypt_cookie_key, MD5_DIGEST_LENGTH) != 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection Openssl random key generation error \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; + } + + if (value[1].len != MD5_DIGEST_LENGTH * 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid parameter len, \"%V\" 16 hex bytes required", &value[0]); + return NGX_CONF_ERROR; + } + + if (ngx_hextobin(ucf->refresh_encrypt_cookie_key, value[1].data, value[1].len) == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid parameter len, \"%V\" 16 hex bytes required", &value[0]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +static char * +ngx_http_bot_protection_set_encryption_iv(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_bot_protection_conf_t *ucf = conf; + ngx_str_t *value; + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "random") == 0) { + ucf->refresh_encrypt_cookie_iv = NULL; + return NGX_CONF_OK; + } + + + ucf->refresh_encrypt_cookie_iv = ngx_palloc(cf->pool, MD5_DIGEST_LENGTH); + if (ucf->refresh_encrypt_cookie_iv == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection IV memory allocation error"); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[1].data, "random2") == 0) { + if (RAND_bytes(ucf->refresh_encrypt_cookie_iv, MD5_DIGEST_LENGTH) != 1) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection Openssl random IV generation error"); + return NGX_CONF_ERROR; + } + return NGX_CONF_OK; + } + + if (value[1].len != MD5_DIGEST_LENGTH * 2) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid parameter len, \"%V\" 16 hex bytes required", &value[0]); + return NGX_CONF_ERROR; + } + + if (ngx_hextobin(ucf->refresh_encrypt_cookie_iv, value[1].data, value[1].len) == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid parameter len, \"%V\" 16 hex bytes required", &value[0]); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +#endif + + +static char * +ngx_http_bot_protection_whitelist_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + char *rv; + ngx_conf_t save; + ngx_http_bot_protection_conf_t *ucf = conf; +#if (NGX_HAVE_INET6) + static struct in6_addr zero; +#endif + + ucf->whitelist = ngx_radix_tree_create(cf->pool, -1); + if (ucf->whitelist == NULL) { + return NGX_CONF_ERROR; + } + +#if (NGX_HAVE_INET6) + ucf->whitelist6 = ngx_radix_tree_create(cf->pool, -1); + if (ucf->whitelist6 == NULL) { + return NGX_CONF_ERROR; + } +#endif + + if (ngx_radix32tree_find(ucf->whitelist, 0) != NGX_RADIX_NO_VALUE) { + return NGX_CONF_ERROR; + } + + if (ngx_radix32tree_insert(ucf->whitelist, 0, 0, + (uintptr_t) &ngx_http_variable_null_value) == NGX_ERROR) { + return NGX_CONF_ERROR; + } + +#if (NGX_HAVE_INET6) + if (ngx_radix128tree_insert(ucf->whitelist6, zero.s6_addr, zero.s6_addr, + (uintptr_t) &ngx_http_variable_null_value) == NGX_ERROR) { + return NGX_CONF_ERROR; + } +#endif + + save = *cf; + cf->handler = ngx_http_bot_protection_whitelist; + cf->handler_conf = (char *) ucf; + + rv = ngx_conf_parse(cf, NULL); + + *cf = save; + + return rv; +} + + +static char * +ngx_http_bot_protection_whitelist(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { + ngx_http_variable_value_t *old; + ngx_int_t rc; + ngx_str_t *value, file; + ngx_uint_t i; + ngx_cidr_t cidr; + ngx_http_bot_protection_conf_t *ucf = conf; + + value = cf->args->elts; + + if (ngx_strcmp(value[0].data, "include") == 0) { + file = value[1]; + + if (ngx_conf_full_name(cf->cycle, &file, 1) == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + return ngx_conf_parse(cf, &file); + } + + rc = ngx_ptocidr(&value[0], &cidr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid parameter \"%V\"", &value[0]); + return NGX_CONF_ERROR; + } + + if (rc == NGX_DONE) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "bot_protection low address bits of %V are meaningless", + &value[0]); + } + + switch (cidr.family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + /* fall through */ + + for (i = 2; i; i--) { + rc = ngx_radix128tree_insert(ucf->whitelist6, cidr.u.in6.addr.s6_addr, + cidr.u.in6.mask.s6_addr, + (uintptr_t) &ngx_http_variable_true_value); + + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + /* rc == NGX_BUSY */ + old = (ngx_http_variable_value_t *) + ngx_radix128tree_find(ucf->whitelist6, + cidr.u.in6.addr.s6_addr); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "bot_protection duplicate \"%V\", old value: \"%v\"", &value[0], old); + + rc = ngx_radix128tree_delete(ucf->whitelist6, + cidr.u.in6.addr.s6_addr, + cidr.u.in6.mask.s6_addr); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bot_protection invalid radix tree"); + return NGX_CONF_ERROR; + } + } + +#endif + + /* fall through */ + default: /* AF_INET */ + + cidr.u.in.addr = ntohl(cidr.u.in.addr); + cidr.u.in.mask = ntohl(cidr.u.in.mask); + + for (i = 2; i; i--) { + rc = ngx_radix32tree_insert(ucf->whitelist, cidr.u.in.addr, cidr.u.in.mask, + (uintptr_t) &ngx_http_variable_true_value); + if (rc == NGX_OK) { + return NGX_CONF_OK; + } + + if (rc == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + /* rc == NGX_BUSY */ + old = (ngx_http_variable_value_t *) + ngx_radix32tree_find(ucf->whitelist, cidr.u.in.addr & cidr.u.in.mask); + + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "bot_protection duplicate \"%V\", old value: \"%v\"", &value[0], old); + + rc = ngx_radix32tree_delete(ucf->whitelist, cidr.u.in.addr, cidr.u.in.mask); + + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "bot_protection invalid radix tree"); + return NGX_CONF_ERROR; + } + } + } + + return NGX_CONF_ERROR; +} + +int +ngx_ishex(u_char *src, size_t len) { + u_char c; + + if (len % 2) return 0; + while (len--) { + c = (*src++); + if ((c >= 'A' && c <= 'F') || (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f')) continue; + return 0; + } + + return 1; +} + +u_char * +ngx_hextobin(u_char *dst, u_char *src, size_t len) { +//#define hextobin(c) ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0') + size_t i; + + if (len % 2) return NULL; + for (i = 0; i < len / 2; i++) { + *dst++ = hextobin(src[2 * i + 1]) + hextobin(src[2 * i]) * 16; + } + + return dst; +} + +static ngx_int_t +ngx_http_bot_protection_nocache(ngx_http_request_t *r) { + ngx_uint_t i; + ngx_table_elt_t *e, *cc, **ccp; + + e = r->headers_out.expires; + if (e == NULL) { + + e = ngx_list_push(&r->headers_out.headers); + if (e == NULL) { + return NGX_ERROR; + } + + r->headers_out.expires = e; + + e->hash = 1; + ngx_str_set(&e->key, "Expires"); + } + + e->value.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; + e->value.data = (u_char *) "Thu, 01 Jan 1970 00:00:01 GMT"; + + ccp = r->headers_out.cache_control.elts; + if (ccp == NULL) { + + if (ngx_array_init(&r->headers_out.cache_control, r->pool, + 1, sizeof(ngx_table_elt_t *)) + != NGX_OK) { + return NGX_ERROR; + } + + ccp = ngx_array_push(&r->headers_out.cache_control); + if (ccp == NULL) { + return NGX_ERROR; + } + + cc = ngx_list_push(&r->headers_out.headers); + if (cc == NULL) { + return NGX_ERROR; + } + + cc->hash = 1; + ngx_str_set(&cc->key, "Cache-Control"); + *ccp = cc; + + } else { + for (i = 1; i < r->headers_out.cache_control.nelts; i++) { + ccp[i]->hash = 0; + } + + cc = ccp[0]; + } + + ngx_str_set(&cc->value, "no-cache"); + + return NGX_OK; +} + +static char * +ngx_http_bot_protection_refresh_status(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_bot_protection_conf_t *ucf = conf; + + ngx_int_t n; + ngx_str_t *value; + + value = cf->args->elts; + + n = ngx_atoi(value[1].data, value[1].len); + if (n < 100 || n > 599) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "bot_protection invalid response code \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + ucf->refresh_status = n; + + return NGX_CONF_OK; +} \ No newline at end of file diff --git a/modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.h b/modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.h new file mode 100644 index 0000000..182d19c --- /dev/null +++ b/modules/ngx_http_bot_protection_module/src/ngx_http_bot_protection_module.h @@ -0,0 +1,66 @@ +// +// Created by khalegh on 9/5/20. +// + +#include <ngx_core.h> + +#ifndef IRONFOX_BOT_PROTECTION_H +#define IRONFOX_BOT_PROTECTION_H +struct attack { + int count; + char token[512]; + struct attack *next; +}; +struct attack *head = NULL; + +#define MODULE_VERSION "0.1.0 The Desert Fox" + +//todo review the challenges and model ( also obfuscation) +#define JS_MEDIUM_BODY "<html><head><title>IronFox

IronFox

checking your request, This process is automatic and your browser redicret to your request content shortely.

Please allow up for secondes...

 


 

Powered by IronFox 
 

"; +#define JS_MEDIUM_LEN 1174 + +#define JS_HARD_BODY "IronFox

IronFox

checking your request, This process is automatic and your browser redicret to your request content shortely.

Please allow up for secondes...

 


 

Powered by IronFox 
 

"; +#define JS_HARD_LEN 1694 + +#define JS_ENGIE_BODY "IronFox"; +#define JS_ENGIE_LEN 469 + +#define BOT_PROTECTION_OFF 0 +#define BOT_PROTECTION_ON 1 +#define BOT_PROTECTION_VARIABLE 2 + +// Wednesday, January 1, 2025 12:00:00 AM +#define NGX_HTTP_BOT_PROTECTION_TTL_MAX_EXPIRES 1735689600 + +#define ANOMALY_DETECTION_OFF 0 +#define ANOMALY_DETECTION_ON 1 + +//todo make configurable +#define TOKEN_TTL_THRESHOLD_SECOND 30 // second +#define CSRF_BLOCKING_THRESHOLD 30 // 150 try +#define COOKIE_MAX_LENGTH 1024 + +#define DEFAULT_COOKIE_NAME "kooki" +#define TOKEN_NAME "token=" +#define TOKEN_NAME_LENGTH 6 + +#define KEY_NAME "key=" +#define KEY_NAME_LENGTH 4 + +#ifndef MD5_DIGEST_LENGTH +#define MD5_DIGEST_LENGTH 16 +#endif +#define RFC1945_ATTEMPTS 4 + +#define PROBE_COOKIE_ENCRYPTION + +#ifdef PROBE_COOKIE_ENCRYPTION + +#include +#include + +#endif + +#define hextobin(c) ((c) >= 'A' && (c) <= 'F' ? c - 'A' + 10 : (c) >= 'a' && (c) <= 'f' ? c - 'a' + 10 : c - '0') + +#endif //IRONFOX_BOT_PROTECTION_H diff --git a/modules/ngx_http_bot_protection_module/t/00base.t b/modules/ngx_http_bot_protection_module/t/00base.t new file mode 100644 index 0000000..2880bf7 --- /dev/null +++ b/modules/ngx_http_bot_protection_module/t/00base.t @@ -0,0 +1,271 @@ +#vi:filetype=perl + + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => repeat_each(1) * 3 * blocks() - 7; +no_long_string(); +no_root_location(); +$ENV{TEST_NGINX_SERVROOT} = server_root(); +run_tests(); + +__DATA__ +=== TEST 1: Basic GET request, empty attempt counter +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test HTTP/1.1 +--- response_headers +Location: http://localhost:30001/?a=test&tstc=1 +Set-Cookie: BPC=4cfb861a6a81106e7660f6eab1d10e0b; path=/ +--- error_code: 307 + + +=== TEST 2: Basic GET request, attempt counter 1 +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test&tstc=1 HTTP/1.1 +--- response_headers +Location: http://localhost:30001/?a=test&tstc=2 +Set-Cookie: BPC=4cfb861a6a81106e7660f6eab1d10e0b; path=/ +--- error_code: 307 + + +=== TEST 3: Basic GET request, attempt counter 3 +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test&tstc=3 HTTP/1.1 +--- response_headers +Location: http://google.com/cookies.html?backurl=http://localhost/?a=test&tstc=3 +--- error_code: 307 + +=== TEST 4: Basic GET request, session key user-agent +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test HTTP/1.1 +--- more_headers +User-Agent: Mozilla +--- response_headers +Location: http://localhost:30001/?a=test&tstc=1 +Set-Cookie: BPC=30f59f604967b09bb8f1e21caf869cb3; path=/ +--- error_code: 307 + +=== TEST 5: Basic GET request, META refresh +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; +--- config + testcookie on; +--- request +GET /?a=test +--- more_headers +User-Agent: Mozilla +--- response_headers +Set-Cookie: BPC=30f59f604967b09bb8f1e21caf869cb3; path=/ +--- error_code: 200 + +=== TEST 6: Basic GET request, whitelist +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + + testcookie_whitelist { + 8.8.8.8/32; + 127.0.0.1/32; + } +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +"It works!It works!" + +=== TEST 7: Basic GET request, no config arg name +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test HTTP/1.1 +--- more_headers +User-Agent: Mozilla +--- response_headers +Location: http://localhost:30001/?a=test +Set-Cookie: BPC=30f59f604967b09bb8f1e21caf869cb3; path=/ +--- error_code: 307 + +=== TEST 8: Basic GET request, secret changed +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret anothersecret; + testcookie_arg tstc; + testcookie_session $remote_addr$http_user_agent; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test HTTP/1.1 +--- more_headers +User-Agent: Mozilla +Location: http://localhost:30001/?a=test&tstc=1 +Set-Cookie: BPC=dfdba774f493bc0605000b22132f745a; path=/ +--- error_code: 307 + +=== TEST 9: Basic GET request, custom refresh template +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template 'hello world!'; +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +"hello world!" + +=== TEST 10: Basic GET request, whitelisting +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template 'hello world!'; + testcookie_whitelist { + 127.0.0.1/32; + } +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +"It works!It works!" + +=== TEST 11: Basic GET request, complex rewrite, test internal redirects +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_internal on; +--- config + testcookie on; + rewrite ^/(.*)$ /index.html?$1 last; +--- request +GET /test HTTP/1.1 +--- response_headers +Location: http://localhost:30001/index.html?test&tstc=1 +Set-Cookie: BPC=4cfb861a6a81106e7660f6eab1d10e0b; path=/ +--- error_code: 307 + +=== TEST 12: Basic GET request, test user-agent if condition +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_internal on; +--- config + location / { + if ($http_user_agent = "test") { + testcookie on; + } + } +--- request +GET /?xxx HTTP/1.1 +--- more_headers +User-Agent: test +--- response_headers +Location: http://localhost:30001/?xxx&tstc=1 +Set-Cookie: BPC=c6d90bd3e1bab267f80a4ef605cf61d0; path=/ +--- error_code: 307 + +=== TEST 13: Basic GET request, empty attempt counter, HTTP version 1.0 +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; +--- config + testcookie on; +--- request +GET /?a=test HTTP/1.0 +--- response_headers +Location: http://localhost:30001/?a=test&tstc=1 +Set-Cookie: BPC=4cfb861a6a81106e7660f6eab1d10e0b; path=/ +--- error_code: 302 diff --git a/modules/ngx_http_bot_protection_module/t/01crypto.t b/modules/ngx_http_bot_protection_module/t/01crypto.t new file mode 100644 index 0000000..097d7d4 --- /dev/null +++ b/modules/ngx_http_bot_protection_module/t/01crypto.t @@ -0,0 +1,150 @@ +#vi:filetype=perl + + +use lib 'lib'; +use Test::Nginx::Socket; + +plan tests => repeat_each(1) * blocks() * 2; +no_long_string(); +no_root_location(); +$ENV{TEST_NGINX_SERVROOT} = server_root(); +run_tests(); + +__DATA__ +=== TEST 1: Basic GET request, custom refresh template, encrypted variables, static key +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '$testcookie_enc_set $testcookie_enc_iv $testcookie_enc_key'; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key deadbeefdeadbeefdeadbeefdeadbeef; + testcookie_refresh_encrypt_cookie_iv deadbeefdeadbeefdeadbeefdeadbeef; +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +"cc54797809d466c4dc3a40a83c472ddd deadbeefdeadbeefdeadbeefdeadbeef deadbeefdeadbeefdeadbeefdeadbeef" + +=== TEST 2: Basic GET request, custom refresh template, encrypted variables, random key +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '$testcookie_enc_set $testcookie_enc_iv $testcookie_enc_key'; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key random; + testcookie_refresh_encrypt_cookie_iv deadbeefdeadbeefdeadbeefdeadbeef; +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +'^(\w){32} deadbeefdeadbeefdeadbeefdeadbeef (\w){32}$' + +=== TEST 3: Basic GET request, custom refresh template, encrypted variables, random iv +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '$testcookie_enc_set $testcookie_enc_iv $testcookie_enc_key'; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key deadbeefdeadbeefdeadbeefdeadbeef; + testcookie_refresh_encrypt_cookie_iv random; +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +'^(\w){32} (\w){32} deadbeefdeadbeefdeadbeefdeadbeef$' + +=== TEST 4: Basic GET request, custom refresh template, encrypted variables, random key and iv +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '$testcookie_enc_set $testcookie_enc_iv $testcookie_enc_key'; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key random; + testcookie_refresh_encrypt_cookie_iv random; +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +'^(\w){32} (\w){32} (\w){32}$' + +=== TEST 5: Basic GET request, custom refresh template, encrypted variables, random key and iv, generated once, after server restart +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '$testcookie_enc_set $testcookie_enc_iv $testcookie_enc_key'; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key random; + testcookie_refresh_encrypt_cookie_iv random2; +--- config + testcookie on; +--- request +GET /?a=test +--- error_code: 200 +--- response_body_like eval +'^(\w){32} (\w){32} (\w){32}$' + +=== TEST 6: HEAD request, custom refresh template, encrypted variables, random key and iv, generated once, after server restart +--- http_config + testcookie off; + testcookie_name BPC; + testcookie_secret flagmebla; + testcookie_session $remote_addr$http_user_agent; + testcookie_arg tstc; + testcookie_max_attempts 3; + testcookie_fallback http://google.com/cookies.html?backurl=http://$host$request_uri; + testcookie_redirect_via_refresh on; + testcookie_refresh_template '$testcookie_enc_set $testcookie_enc_iv $testcookie_enc_key'; + + testcookie_refresh_encrypt_cookie on; + testcookie_refresh_encrypt_cookie_key random; + testcookie_refresh_encrypt_cookie_iv random2; +--- config + testcookie on; +--- request +GET /?a=test +--- response_headers +Content-Length: 98 +--- error_code: 200 diff --git a/modules/ngx_http_bot_protection_module/util/Iron.js b/modules/ngx_http_bot_protection_module/util/Iron.js new file mode 100644 index 0000000..fb628db --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/Iron.js @@ -0,0 +1,720 @@ +var ironUtility = { + /* + * START AES SECTION + */ + aes: { + // structure of valid key sizes + keySize: { + SIZE_128: 16, + SIZE_192: 24, + SIZE_256: 32 + }, + + // Rijndael S-box + sbox: [ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 + ], + + // Rijndael Inverted S-box + rsbox: [0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d], + + /* rotate the word eight bits to the left */ + rotate: function (word) { + var c = word[0]; + for (var i = 0; i < 3; i++) + word[i] = word[i + 1]; + word[3] = c; + + return word; + }, + + // Rijndael Rcon + Rcon: [ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, + 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, + 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, + 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, + 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, + 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, + 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, + 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, + 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, + 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb + ], + + G2X: [ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, + 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, + 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, + 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, + 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, + 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, + 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, + 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, + 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, + 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, + 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, + 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd, + 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, + 0xe3, 0xe1, 0xe7, 0xe5 + ], + + G3X: [ + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, + 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, + 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, + 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, + 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, + 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, + 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, + 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, + 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, + 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, + 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, + 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, + 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, + 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, + 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e, + 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, + 0x1f, 0x1c, 0x19, 0x1a + ], + + G9X: [ + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, + 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, + 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, + 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, + 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, + 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, + 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, + 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, + 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, + 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, + 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, + 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, + 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, + 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, + 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba, + 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, + 0x5d, 0x54, 0x4f, 0x46 + ], + + GBX: [ + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, + 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, + 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, + 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, + 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, + 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, + 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, + 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, + 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, + 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, + 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, + 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, + 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, + 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, + 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67, + 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, + 0xbe, 0xb5, 0xa8, 0xa3 + ], + + GDX: [ + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, + 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, + 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, + 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, + 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, + 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, + 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, + 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, + 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, + 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, + 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, + 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, + 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, + 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, + 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b, + 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, + 0x80, 0x8d, 0x9a, 0x97 + ], + + GEX: [ + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, + 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, + 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, + 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, + 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, + 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, + 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, + 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, + 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, + 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, + 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, + 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, + 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, + 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, + 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25, + 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, + 0x9f, 0x91, 0x83, 0x8d + ], + + // Key Schedule Core + core: function (word, iteration) { + /* rotate the 32-bit word 8 bits to the left */ + word = this.rotate(word); + /* apply S-Box substitution on all 4 parts of the 32-bit word */ + for (var i = 0; i < 4; ++i) + word[i] = this.sbox[word[i]]; + /* XOR the output of the rcon operation with i to the first part (leftmost) only */ + word[0] = word[0] ^ this.Rcon[iteration]; + return word; + }, + + /* Rijndael's key expansion + * expands an 128,192,256 key into an 176,208,240 bytes key + * + * expandedKey is a pointer to an char array of large enough size + * key is a pointer to a non-expanded key + */ + expandKey: function (key, size) { + var expandedKeySize = (16 * (this.numberOfRounds(size) + 1)); + + /* current expanded keySize, in bytes */ + var currentSize = 0; + var rconIteration = 1; + var t = []; // temporary 4-byte variable + + var expandedKey = []; + for (var i = 0; i < expandedKeySize; i++) + expandedKey[i] = 0; + + /* set the 16,24,32 bytes of the expanded key to the input key */ + for (var j = 0; j < size; j++) + expandedKey[j] = key[j]; + currentSize += size; + + while (currentSize < expandedKeySize) { + /* assign the previous 4 bytes to the temporary value t */ + for (var k = 0; k < 4; k++) + t[k] = expandedKey[(currentSize - 4) + k]; + + /* every 16,24,32 bytes we apply the core schedule to t + * and increment rconIteration afterwards + */ + if (currentSize % size == 0) + t = this.core(t, rconIteration++); + + /* For 256-bit keys, we add an extra sbox to the calculation */ + if (size == this.keySize.SIZE_256 && ((currentSize % size) == 16)) + for (var l = 0; l < 4; l++) + t[l] = this.sbox[t[l]]; + + /* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key. + * This becomes the next four bytes in the expanded key. + */ + for (var m = 0; m < 4; m++) { + expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]; + currentSize++; + } + } + return expandedKey; + }, + + // Adds (XORs) the round key to the state + addRoundKey: function (state, roundKey) { + for (var i = 0; i < 16; i++) + state[i] ^= roundKey[i]; + return state; + }, + + // Creates a round key from the given expanded key and the + // position within the expanded key. + createRoundKey: function (expandedKey, roundKeyPointer) { + var roundKey = []; + for (var i = 0; i < 4; i++) + for (var j = 0; j < 4; j++) + roundKey[j * 4 + i] = expandedKey[roundKeyPointer + i * 4 + j]; + return roundKey; + }, + + /* substitute all the values from the state with the value in the SBox + * using the state value as index for the SBox + */ + subBytes: function (state, isInv) { + for (var i = 0; i < 16; i++) + state[i] = isInv ? this.rsbox[state[i]] : this.sbox[state[i]]; + return state; + }, + + /* iterate over the 4 rows and call shiftRow() with that row */ + shiftRows: function (state, isInv) { + for (var i = 0; i < 4; i++) + state = this.shiftRow(state, i * 4, i, isInv); + return state; + }, + + /* each iteration shifts the row to the left by 1 */ + shiftRow: function (state, statePointer, nbr, isInv) { + for (var i = 0; i < nbr; i++) { + if (isInv) { + var tmp = state[statePointer + 3]; + for (var j = 3; j > 0; j--) + state[statePointer + j] = state[statePointer + j - 1]; + state[statePointer] = tmp; + } else { + var tmp = state[statePointer]; + for (var j = 0; j < 3; j++) + state[statePointer + j] = state[statePointer + j + 1]; + state[statePointer + 3] = tmp; + } + } + return state; + }, + + // galois multiplication of 8 bit characters a and b + galois_multiplication: function (a, b) { + var p = 0; + for (var counter = 0; counter < 8; counter++) { + if ((b & 1) == 1) + p ^= a; + if (p > 0x100) p ^= 0x100; + var hi_bit_set = (a & 0x80); //keep p 8 bit + a <<= 1; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + if (hi_bit_set == 0x80) + a ^= 0x1b; + if (a > 0x100) a ^= 0x100; //keep a 8 bit + b >>= 1; + if (b > 0x100) b ^= 0x100; //keep b 8 bit + } + return p; + }, + + // galois multipication of the 4x4 matrix + mixColumns: function (state, isInv) { + var column = []; + /* iterate over the 4 columns */ + for (var i = 0; i < 4; i++) { + /* construct one column by iterating over the 4 rows */ + for (var j = 0; j < 4; j++) + column[j] = state[(j * 4) + i]; + /* apply the mixColumn on one column */ + column = this.mixColumn(column, isInv); + /* put the values back into the state */ + for (var k = 0; k < 4; k++) + state[(k * 4) + i] = column[k]; + } + return state; + }, + + // galois multipication of 1 column of the 4x4 matrix + mixColumn: function (column, isInv) { + var mult = []; + if (isInv) + mult = [14, 9, 13, 11]; + else + mult = [2, 1, 1, 3]; + var cpy = []; + for (var i = 0; i < 4; i++) + cpy[i] = column[i]; + + column[0] = this.galois_multiplication(cpy[0], mult[0]) ^ + this.galois_multiplication(cpy[3], mult[1]) ^ + this.galois_multiplication(cpy[2], mult[2]) ^ + this.galois_multiplication(cpy[1], mult[3]); + column[1] = this.galois_multiplication(cpy[1], mult[0]) ^ + this.galois_multiplication(cpy[0], mult[1]) ^ + this.galois_multiplication(cpy[3], mult[2]) ^ + this.galois_multiplication(cpy[2], mult[3]); + column[2] = this.galois_multiplication(cpy[2], mult[0]) ^ + this.galois_multiplication(cpy[1], mult[1]) ^ + this.galois_multiplication(cpy[0], mult[2]) ^ + this.galois_multiplication(cpy[3], mult[3]); + column[3] = this.galois_multiplication(cpy[3], mult[0]) ^ + this.galois_multiplication(cpy[2], mult[1]) ^ + this.galois_multiplication(cpy[1], mult[2]) ^ + this.galois_multiplication(cpy[0], mult[3]); + return column; + }, + + // applies the 4 operations of the forward round in sequence + round: function (state, roundKey) { + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.mixColumns(state, false); + state = this.addRoundKey(state, roundKey); + return state; + }, + + // applies the 4 operations of the inverse round in sequence + invRound: function (state, roundKey) { + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, roundKey); + state = this.mixColumns(state, true); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the forward aes, creating a round key for each round + */ + main: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + for (var i = 1; i < nbrRounds; i++) + state = this.round(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.subBytes(state, false); + state = this.shiftRows(state, false); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the inverse aes, creating a round key for each round + */ + invMain: function (state, expandedKey, nbrRounds) { + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 16 * nbrRounds)); + for (var i = nbrRounds - 1; i > 0; i--) + state = this.invRound(state, this.createRoundKey(expandedKey, 16 * i)); + state = this.shiftRows(state, true); + state = this.subBytes(state, true); + state = this.addRoundKey(state, this.createRoundKey(expandedKey, 0)); + return state; + }, + + numberOfRounds: function (size) { + var nbrRounds; + switch (size) /* set the number of rounds */ { + case this.keySize.SIZE_128: + nbrRounds = 10; + break; + case this.keySize.SIZE_192: + nbrRounds = 12; + break; + case this.keySize.SIZE_256: + nbrRounds = 14; + break; + default: + return null; + break; + } + return nbrRounds; + }, + + // encrypts a 128 bit input block against the given key of size specified + encrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to encode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); /* the expanded key */ + /* encrypt the block using the expandedKey */ + block = this.main(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + }, + + // decrypts a 128 bit input block against the given key of size specified + decrypt: function (input, key, size) { + var output = []; + var block = []; /* the 128 bit block to decode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i + (j * 4))] = input[(i * 4) + j]; + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); + /* decrypt the block using the expandedKey */ + block = this.invMain(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k * 4) + l] = block[(k + (l * 4))]; + return output; + } + }, + /* + * END AES SECTION + */ + + /* + * START MODE OF OPERATION SECTION + */ + //structure of supported modes of operation + modeOfOperation: { + OFB: 0, + CFB: 1, + CBC: 2 + }, + + // get a 16 byte block (aes operates on 128bits) + getBlock: function (bytesIn, start, end, mode) { + if (end - start > 16) + end = start + 16; + + return bytesIn.slice(start, end); + }, + + /* + * Mode of Operation Encryption + * bytesIn - Input String as array of bytes + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + encrypt: function (bytesIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var byteArray = []; + var input = []; + var output = []; + var ciphertext = []; + var cipherOut = []; + // char firstRound + var firstRound = true; + if (mode == this.modeOfOperation.CBC) + this.padBytesIn(bytesIn); + if (bytesIn !== null) { + for (var j = 0; j < Math.ceil(bytesIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > bytesIn.length) + end = bytesIn.length; + byteArray = this.getBlock(bytesIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for (var k = 0; k < end - start; k++) + cipherOut.push(ciphertext[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + for (var i = 0; i < 16; i++) + input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]); + firstRound = false; + ciphertext = this.aes.encrypt(input, key, size); + // always 16 bytes because of the padding for CBC + for (var k = 0; k < 16; k++) + cipherOut.push(ciphertext[k]); + } + } + } + return cipherOut; + }, + + /* + * Mode of Operation Decryption + * cipherIn - Encrypted String as array of bytes + * originalsize - The unencrypted string length - required for CBC + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + decrypt: function (cipherIn, mode, key, iv) { + var size = key.length; + if (iv.length % 16) { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var ciphertext = []; + var input = []; + var output = []; + var byteArray = []; + var bytesOut = []; + // char firstRound + var firstRound = true; + if (cipherIn !== null) { + for (var j = 0; j < Math.ceil(cipherIn.length / 16); j++) { + var start = j * 16; + var end = j * 16 + 16; + if (j * 16 + 16 > cipherIn.length) + end = cipherIn.length; + ciphertext = this.getBlock(cipherIn, start, end, mode); + if (mode == this.modeOfOperation.CFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } else if (mode == this.modeOfOperation.OFB) { + if (firstRound) { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = output; + } else if (mode == this.modeOfOperation.CBC) { + output = this.aes.decrypt(ciphertext, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i]; + firstRound = false; + for (var k = 0; k < end - start; k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + } + if (mode == this.modeOfOperation.CBC) + this.unpadBytesOut(bytesOut); + } + return bytesOut; + }, + padBytesIn: function (data) { + var len = data.length; + var padByte = 16 - (len % 16); + for (var i = 0; i < padByte; i++) { + data.push(padByte); + } + }, + unpadBytesOut: function (data) { + var padCount = 0; + var padByte = -1; + var blockSize = 16; + for (var i = data.length - 1; i >= data.length - 1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) + padByte = data[i]; + if (data[i] != padByte) { + padCount = 0; + break; + } + padCount++; + } else + break; + if (padCount == padByte) + break; + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); + } + /* + * END MODE OF OPERATION SECTION + */ +}; + +function toDigit(d) { + var e = []; + d.replace(/(..)/g, function(d) { + e.push(parseInt(d, 16)) + }); + return e +} + +function toHex() { + for (var d = [], d = 1 == arguments.length && arguments[0].constructor == Array ? arguments[0] : arguments, e = "", f = 0; f < d.length; f++) e += (16 > d[f] ? "0" : "") + d[f].toString(16); + return e.toLowerCase() +} + + +function getIronCookie(a, b, c) { + var cc = this.toHex(ironUtility.decrypt(c, 2, a, b)); + return cc; +}; + diff --git a/modules/ngx_http_bot_protection_module/util/back/aes.js b/modules/ngx_http_bot_protection_module/util/back/aes.js new file mode 100644 index 0000000..be0f4ae --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/back/aes.js @@ -0,0 +1,780 @@ +/* + * aes.js: implements AES - Advanced Encryption Standard + * from the SlowAES project, http://code.google.com/p/slowaes/ + * + * Copyright (c) 2008 Josh Davis ( http://www.josh-davis.org ), + * Mark Percival ( http://mpercival.com ), + * + * Ported from C code written by Laurent Haan ( http://www.progressive-coding.com ) + * + * Licensed under the Apache License, Version 2.0 + * http://www.apache.org/licenses/ + */ + +var slowAES = { + /* + * START AES SECTION + */ + aes:{ + // structure of valid key sizes + keySize:{ + SIZE_128:16, + SIZE_192:24, + SIZE_256:32 + }, + + // Rijndael S-box + sbox:[ + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 ], + + // Rijndael Inverted S-box + rsbox: + [ 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb + , 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb + , 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e + , 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25 + , 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92 + , 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84 + , 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06 + , 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b + , 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73 + , 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e + , 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b + , 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4 + , 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f + , 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef + , 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61 + , 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d ], + + /* rotate the word eight bits to the left */ + rotate:function(word) + { + var c = word[0]; + for (var i = 0; i < 3; i++) + word[i] = word[i+1]; + word[3] = c; + + return word; + }, + + // Rijndael Rcon + Rcon:[ + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, + 0xab, 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, + 0x7d, 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, + 0x25, 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, + 0x4d, 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, + 0xfa, 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, + 0x4a, 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, + 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, + 0x9a, 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, + 0xef, 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, + 0x94, 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, + 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, + 0xc5, 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, + 0x33, 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb, 0x8d, 0x01, 0x02, 0x04, + 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, 0x2f, + 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, + 0x91, 0x39, 0x72, 0xe4, 0xd3, 0xbd, 0x61, 0xc2, 0x9f, 0x25, 0x4a, 0x94, 0x33, + 0x66, 0xcc, 0x83, 0x1d, 0x3a, 0x74, 0xe8, 0xcb ], + + G2X: [ + 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e, 0x10, 0x12, 0x14, 0x16, + 0x18, 0x1a, 0x1c, 0x1e, 0x20, 0x22, 0x24, 0x26, 0x28, 0x2a, 0x2c, 0x2e, + 0x30, 0x32, 0x34, 0x36, 0x38, 0x3a, 0x3c, 0x3e, 0x40, 0x42, 0x44, 0x46, + 0x48, 0x4a, 0x4c, 0x4e, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5a, 0x5c, 0x5e, + 0x60, 0x62, 0x64, 0x66, 0x68, 0x6a, 0x6c, 0x6e, 0x70, 0x72, 0x74, 0x76, + 0x78, 0x7a, 0x7c, 0x7e, 0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c, 0x8e, + 0x90, 0x92, 0x94, 0x96, 0x98, 0x9a, 0x9c, 0x9e, 0xa0, 0xa2, 0xa4, 0xa6, + 0xa8, 0xaa, 0xac, 0xae, 0xb0, 0xb2, 0xb4, 0xb6, 0xb8, 0xba, 0xbc, 0xbe, + 0xc0, 0xc2, 0xc4, 0xc6, 0xc8, 0xca, 0xcc, 0xce, 0xd0, 0xd2, 0xd4, 0xd6, + 0xd8, 0xda, 0xdc, 0xde, 0xe0, 0xe2, 0xe4, 0xe6, 0xe8, 0xea, 0xec, 0xee, + 0xf0, 0xf2, 0xf4, 0xf6, 0xf8, 0xfa, 0xfc, 0xfe, 0x1b, 0x19, 0x1f, 0x1d, + 0x13, 0x11, 0x17, 0x15, 0x0b, 0x09, 0x0f, 0x0d, 0x03, 0x01, 0x07, 0x05, + 0x3b, 0x39, 0x3f, 0x3d, 0x33, 0x31, 0x37, 0x35, 0x2b, 0x29, 0x2f, 0x2d, + 0x23, 0x21, 0x27, 0x25, 0x5b, 0x59, 0x5f, 0x5d, 0x53, 0x51, 0x57, 0x55, + 0x4b, 0x49, 0x4f, 0x4d, 0x43, 0x41, 0x47, 0x45, 0x7b, 0x79, 0x7f, 0x7d, + 0x73, 0x71, 0x77, 0x75, 0x6b, 0x69, 0x6f, 0x6d, 0x63, 0x61, 0x67, 0x65, + 0x9b, 0x99, 0x9f, 0x9d, 0x93, 0x91, 0x97, 0x95, 0x8b, 0x89, 0x8f, 0x8d, + 0x83, 0x81, 0x87, 0x85, 0xbb, 0xb9, 0xbf, 0xbd, 0xb3, 0xb1, 0xb7, 0xb5, + 0xab, 0xa9, 0xaf, 0xad, 0xa3, 0xa1, 0xa7, 0xa5, 0xdb, 0xd9, 0xdf, 0xdd, + 0xd3, 0xd1, 0xd7, 0xd5, 0xcb, 0xc9, 0xcf, 0xcd, 0xc3, 0xc1, 0xc7, 0xc5, + 0xfb, 0xf9, 0xff, 0xfd, 0xf3, 0xf1, 0xf7, 0xf5, 0xeb, 0xe9, 0xef, 0xed, + 0xe3, 0xe1, 0xe7, 0xe5 + ], + + G3X: [ + 0x00, 0x03, 0x06, 0x05, 0x0c, 0x0f, 0x0a, 0x09, 0x18, 0x1b, 0x1e, 0x1d, + 0x14, 0x17, 0x12, 0x11, 0x30, 0x33, 0x36, 0x35, 0x3c, 0x3f, 0x3a, 0x39, + 0x28, 0x2b, 0x2e, 0x2d, 0x24, 0x27, 0x22, 0x21, 0x60, 0x63, 0x66, 0x65, + 0x6c, 0x6f, 0x6a, 0x69, 0x78, 0x7b, 0x7e, 0x7d, 0x74, 0x77, 0x72, 0x71, + 0x50, 0x53, 0x56, 0x55, 0x5c, 0x5f, 0x5a, 0x59, 0x48, 0x4b, 0x4e, 0x4d, + 0x44, 0x47, 0x42, 0x41, 0xc0, 0xc3, 0xc6, 0xc5, 0xcc, 0xcf, 0xca, 0xc9, + 0xd8, 0xdb, 0xde, 0xdd, 0xd4, 0xd7, 0xd2, 0xd1, 0xf0, 0xf3, 0xf6, 0xf5, + 0xfc, 0xff, 0xfa, 0xf9, 0xe8, 0xeb, 0xee, 0xed, 0xe4, 0xe7, 0xe2, 0xe1, + 0xa0, 0xa3, 0xa6, 0xa5, 0xac, 0xaf, 0xaa, 0xa9, 0xb8, 0xbb, 0xbe, 0xbd, + 0xb4, 0xb7, 0xb2, 0xb1, 0x90, 0x93, 0x96, 0x95, 0x9c, 0x9f, 0x9a, 0x99, + 0x88, 0x8b, 0x8e, 0x8d, 0x84, 0x87, 0x82, 0x81, 0x9b, 0x98, 0x9d, 0x9e, + 0x97, 0x94, 0x91, 0x92, 0x83, 0x80, 0x85, 0x86, 0x8f, 0x8c, 0x89, 0x8a, + 0xab, 0xa8, 0xad, 0xae, 0xa7, 0xa4, 0xa1, 0xa2, 0xb3, 0xb0, 0xb5, 0xb6, + 0xbf, 0xbc, 0xb9, 0xba, 0xfb, 0xf8, 0xfd, 0xfe, 0xf7, 0xf4, 0xf1, 0xf2, + 0xe3, 0xe0, 0xe5, 0xe6, 0xef, 0xec, 0xe9, 0xea, 0xcb, 0xc8, 0xcd, 0xce, + 0xc7, 0xc4, 0xc1, 0xc2, 0xd3, 0xd0, 0xd5, 0xd6, 0xdf, 0xdc, 0xd9, 0xda, + 0x5b, 0x58, 0x5d, 0x5e, 0x57, 0x54, 0x51, 0x52, 0x43, 0x40, 0x45, 0x46, + 0x4f, 0x4c, 0x49, 0x4a, 0x6b, 0x68, 0x6d, 0x6e, 0x67, 0x64, 0x61, 0x62, + 0x73, 0x70, 0x75, 0x76, 0x7f, 0x7c, 0x79, 0x7a, 0x3b, 0x38, 0x3d, 0x3e, + 0x37, 0x34, 0x31, 0x32, 0x23, 0x20, 0x25, 0x26, 0x2f, 0x2c, 0x29, 0x2a, + 0x0b, 0x08, 0x0d, 0x0e, 0x07, 0x04, 0x01, 0x02, 0x13, 0x10, 0x15, 0x16, + 0x1f, 0x1c, 0x19, 0x1a + ], + + G9X: [ + 0x00, 0x09, 0x12, 0x1b, 0x24, 0x2d, 0x36, 0x3f, 0x48, 0x41, 0x5a, 0x53, + 0x6c, 0x65, 0x7e, 0x77, 0x90, 0x99, 0x82, 0x8b, 0xb4, 0xbd, 0xa6, 0xaf, + 0xd8, 0xd1, 0xca, 0xc3, 0xfc, 0xf5, 0xee, 0xe7, 0x3b, 0x32, 0x29, 0x20, + 0x1f, 0x16, 0x0d, 0x04, 0x73, 0x7a, 0x61, 0x68, 0x57, 0x5e, 0x45, 0x4c, + 0xab, 0xa2, 0xb9, 0xb0, 0x8f, 0x86, 0x9d, 0x94, 0xe3, 0xea, 0xf1, 0xf8, + 0xc7, 0xce, 0xd5, 0xdc, 0x76, 0x7f, 0x64, 0x6d, 0x52, 0x5b, 0x40, 0x49, + 0x3e, 0x37, 0x2c, 0x25, 0x1a, 0x13, 0x08, 0x01, 0xe6, 0xef, 0xf4, 0xfd, + 0xc2, 0xcb, 0xd0, 0xd9, 0xae, 0xa7, 0xbc, 0xb5, 0x8a, 0x83, 0x98, 0x91, + 0x4d, 0x44, 0x5f, 0x56, 0x69, 0x60, 0x7b, 0x72, 0x05, 0x0c, 0x17, 0x1e, + 0x21, 0x28, 0x33, 0x3a, 0xdd, 0xd4, 0xcf, 0xc6, 0xf9, 0xf0, 0xeb, 0xe2, + 0x95, 0x9c, 0x87, 0x8e, 0xb1, 0xb8, 0xa3, 0xaa, 0xec, 0xe5, 0xfe, 0xf7, + 0xc8, 0xc1, 0xda, 0xd3, 0xa4, 0xad, 0xb6, 0xbf, 0x80, 0x89, 0x92, 0x9b, + 0x7c, 0x75, 0x6e, 0x67, 0x58, 0x51, 0x4a, 0x43, 0x34, 0x3d, 0x26, 0x2f, + 0x10, 0x19, 0x02, 0x0b, 0xd7, 0xde, 0xc5, 0xcc, 0xf3, 0xfa, 0xe1, 0xe8, + 0x9f, 0x96, 0x8d, 0x84, 0xbb, 0xb2, 0xa9, 0xa0, 0x47, 0x4e, 0x55, 0x5c, + 0x63, 0x6a, 0x71, 0x78, 0x0f, 0x06, 0x1d, 0x14, 0x2b, 0x22, 0x39, 0x30, + 0x9a, 0x93, 0x88, 0x81, 0xbe, 0xb7, 0xac, 0xa5, 0xd2, 0xdb, 0xc0, 0xc9, + 0xf6, 0xff, 0xe4, 0xed, 0x0a, 0x03, 0x18, 0x11, 0x2e, 0x27, 0x3c, 0x35, + 0x42, 0x4b, 0x50, 0x59, 0x66, 0x6f, 0x74, 0x7d, 0xa1, 0xa8, 0xb3, 0xba, + 0x85, 0x8c, 0x97, 0x9e, 0xe9, 0xe0, 0xfb, 0xf2, 0xcd, 0xc4, 0xdf, 0xd6, + 0x31, 0x38, 0x23, 0x2a, 0x15, 0x1c, 0x07, 0x0e, 0x79, 0x70, 0x6b, 0x62, + 0x5d, 0x54, 0x4f, 0x46 + ], + + GBX: [ + 0x00, 0x0b, 0x16, 0x1d, 0x2c, 0x27, 0x3a, 0x31, 0x58, 0x53, 0x4e, 0x45, + 0x74, 0x7f, 0x62, 0x69, 0xb0, 0xbb, 0xa6, 0xad, 0x9c, 0x97, 0x8a, 0x81, + 0xe8, 0xe3, 0xfe, 0xf5, 0xc4, 0xcf, 0xd2, 0xd9, 0x7b, 0x70, 0x6d, 0x66, + 0x57, 0x5c, 0x41, 0x4a, 0x23, 0x28, 0x35, 0x3e, 0x0f, 0x04, 0x19, 0x12, + 0xcb, 0xc0, 0xdd, 0xd6, 0xe7, 0xec, 0xf1, 0xfa, 0x93, 0x98, 0x85, 0x8e, + 0xbf, 0xb4, 0xa9, 0xa2, 0xf6, 0xfd, 0xe0, 0xeb, 0xda, 0xd1, 0xcc, 0xc7, + 0xae, 0xa5, 0xb8, 0xb3, 0x82, 0x89, 0x94, 0x9f, 0x46, 0x4d, 0x50, 0x5b, + 0x6a, 0x61, 0x7c, 0x77, 0x1e, 0x15, 0x08, 0x03, 0x32, 0x39, 0x24, 0x2f, + 0x8d, 0x86, 0x9b, 0x90, 0xa1, 0xaa, 0xb7, 0xbc, 0xd5, 0xde, 0xc3, 0xc8, + 0xf9, 0xf2, 0xef, 0xe4, 0x3d, 0x36, 0x2b, 0x20, 0x11, 0x1a, 0x07, 0x0c, + 0x65, 0x6e, 0x73, 0x78, 0x49, 0x42, 0x5f, 0x54, 0xf7, 0xfc, 0xe1, 0xea, + 0xdb, 0xd0, 0xcd, 0xc6, 0xaf, 0xa4, 0xb9, 0xb2, 0x83, 0x88, 0x95, 0x9e, + 0x47, 0x4c, 0x51, 0x5a, 0x6b, 0x60, 0x7d, 0x76, 0x1f, 0x14, 0x09, 0x02, + 0x33, 0x38, 0x25, 0x2e, 0x8c, 0x87, 0x9a, 0x91, 0xa0, 0xab, 0xb6, 0xbd, + 0xd4, 0xdf, 0xc2, 0xc9, 0xf8, 0xf3, 0xee, 0xe5, 0x3c, 0x37, 0x2a, 0x21, + 0x10, 0x1b, 0x06, 0x0d, 0x64, 0x6f, 0x72, 0x79, 0x48, 0x43, 0x5e, 0x55, + 0x01, 0x0a, 0x17, 0x1c, 0x2d, 0x26, 0x3b, 0x30, 0x59, 0x52, 0x4f, 0x44, + 0x75, 0x7e, 0x63, 0x68, 0xb1, 0xba, 0xa7, 0xac, 0x9d, 0x96, 0x8b, 0x80, + 0xe9, 0xe2, 0xff, 0xf4, 0xc5, 0xce, 0xd3, 0xd8, 0x7a, 0x71, 0x6c, 0x67, + 0x56, 0x5d, 0x40, 0x4b, 0x22, 0x29, 0x34, 0x3f, 0x0e, 0x05, 0x18, 0x13, + 0xca, 0xc1, 0xdc, 0xd7, 0xe6, 0xed, 0xf0, 0xfb, 0x92, 0x99, 0x84, 0x8f, + 0xbe, 0xb5, 0xa8, 0xa3 + ], + + GDX: [ + 0x00, 0x0d, 0x1a, 0x17, 0x34, 0x39, 0x2e, 0x23, 0x68, 0x65, 0x72, 0x7f, + 0x5c, 0x51, 0x46, 0x4b, 0xd0, 0xdd, 0xca, 0xc7, 0xe4, 0xe9, 0xfe, 0xf3, + 0xb8, 0xb5, 0xa2, 0xaf, 0x8c, 0x81, 0x96, 0x9b, 0xbb, 0xb6, 0xa1, 0xac, + 0x8f, 0x82, 0x95, 0x98, 0xd3, 0xde, 0xc9, 0xc4, 0xe7, 0xea, 0xfd, 0xf0, + 0x6b, 0x66, 0x71, 0x7c, 0x5f, 0x52, 0x45, 0x48, 0x03, 0x0e, 0x19, 0x14, + 0x37, 0x3a, 0x2d, 0x20, 0x6d, 0x60, 0x77, 0x7a, 0x59, 0x54, 0x43, 0x4e, + 0x05, 0x08, 0x1f, 0x12, 0x31, 0x3c, 0x2b, 0x26, 0xbd, 0xb0, 0xa7, 0xaa, + 0x89, 0x84, 0x93, 0x9e, 0xd5, 0xd8, 0xcf, 0xc2, 0xe1, 0xec, 0xfb, 0xf6, + 0xd6, 0xdb, 0xcc, 0xc1, 0xe2, 0xef, 0xf8, 0xf5, 0xbe, 0xb3, 0xa4, 0xa9, + 0x8a, 0x87, 0x90, 0x9d, 0x06, 0x0b, 0x1c, 0x11, 0x32, 0x3f, 0x28, 0x25, + 0x6e, 0x63, 0x74, 0x79, 0x5a, 0x57, 0x40, 0x4d, 0xda, 0xd7, 0xc0, 0xcd, + 0xee, 0xe3, 0xf4, 0xf9, 0xb2, 0xbf, 0xa8, 0xa5, 0x86, 0x8b, 0x9c, 0x91, + 0x0a, 0x07, 0x10, 0x1d, 0x3e, 0x33, 0x24, 0x29, 0x62, 0x6f, 0x78, 0x75, + 0x56, 0x5b, 0x4c, 0x41, 0x61, 0x6c, 0x7b, 0x76, 0x55, 0x58, 0x4f, 0x42, + 0x09, 0x04, 0x13, 0x1e, 0x3d, 0x30, 0x27, 0x2a, 0xb1, 0xbc, 0xab, 0xa6, + 0x85, 0x88, 0x9f, 0x92, 0xd9, 0xd4, 0xc3, 0xce, 0xed, 0xe0, 0xf7, 0xfa, + 0xb7, 0xba, 0xad, 0xa0, 0x83, 0x8e, 0x99, 0x94, 0xdf, 0xd2, 0xc5, 0xc8, + 0xeb, 0xe6, 0xf1, 0xfc, 0x67, 0x6a, 0x7d, 0x70, 0x53, 0x5e, 0x49, 0x44, + 0x0f, 0x02, 0x15, 0x18, 0x3b, 0x36, 0x21, 0x2c, 0x0c, 0x01, 0x16, 0x1b, + 0x38, 0x35, 0x22, 0x2f, 0x64, 0x69, 0x7e, 0x73, 0x50, 0x5d, 0x4a, 0x47, + 0xdc, 0xd1, 0xc6, 0xcb, 0xe8, 0xe5, 0xf2, 0xff, 0xb4, 0xb9, 0xae, 0xa3, + 0x80, 0x8d, 0x9a, 0x97 + ], + + GEX: [ + 0x00, 0x0e, 0x1c, 0x12, 0x38, 0x36, 0x24, 0x2a, 0x70, 0x7e, 0x6c, 0x62, + 0x48, 0x46, 0x54, 0x5a, 0xe0, 0xee, 0xfc, 0xf2, 0xd8, 0xd6, 0xc4, 0xca, + 0x90, 0x9e, 0x8c, 0x82, 0xa8, 0xa6, 0xb4, 0xba, 0xdb, 0xd5, 0xc7, 0xc9, + 0xe3, 0xed, 0xff, 0xf1, 0xab, 0xa5, 0xb7, 0xb9, 0x93, 0x9d, 0x8f, 0x81, + 0x3b, 0x35, 0x27, 0x29, 0x03, 0x0d, 0x1f, 0x11, 0x4b, 0x45, 0x57, 0x59, + 0x73, 0x7d, 0x6f, 0x61, 0xad, 0xa3, 0xb1, 0xbf, 0x95, 0x9b, 0x89, 0x87, + 0xdd, 0xd3, 0xc1, 0xcf, 0xe5, 0xeb, 0xf9, 0xf7, 0x4d, 0x43, 0x51, 0x5f, + 0x75, 0x7b, 0x69, 0x67, 0x3d, 0x33, 0x21, 0x2f, 0x05, 0x0b, 0x19, 0x17, + 0x76, 0x78, 0x6a, 0x64, 0x4e, 0x40, 0x52, 0x5c, 0x06, 0x08, 0x1a, 0x14, + 0x3e, 0x30, 0x22, 0x2c, 0x96, 0x98, 0x8a, 0x84, 0xae, 0xa0, 0xb2, 0xbc, + 0xe6, 0xe8, 0xfa, 0xf4, 0xde, 0xd0, 0xc2, 0xcc, 0x41, 0x4f, 0x5d, 0x53, + 0x79, 0x77, 0x65, 0x6b, 0x31, 0x3f, 0x2d, 0x23, 0x09, 0x07, 0x15, 0x1b, + 0xa1, 0xaf, 0xbd, 0xb3, 0x99, 0x97, 0x85, 0x8b, 0xd1, 0xdf, 0xcd, 0xc3, + 0xe9, 0xe7, 0xf5, 0xfb, 0x9a, 0x94, 0x86, 0x88, 0xa2, 0xac, 0xbe, 0xb0, + 0xea, 0xe4, 0xf6, 0xf8, 0xd2, 0xdc, 0xce, 0xc0, 0x7a, 0x74, 0x66, 0x68, + 0x42, 0x4c, 0x5e, 0x50, 0x0a, 0x04, 0x16, 0x18, 0x32, 0x3c, 0x2e, 0x20, + 0xec, 0xe2, 0xf0, 0xfe, 0xd4, 0xda, 0xc8, 0xc6, 0x9c, 0x92, 0x80, 0x8e, + 0xa4, 0xaa, 0xb8, 0xb6, 0x0c, 0x02, 0x10, 0x1e, 0x34, 0x3a, 0x28, 0x26, + 0x7c, 0x72, 0x60, 0x6e, 0x44, 0x4a, 0x58, 0x56, 0x37, 0x39, 0x2b, 0x25, + 0x0f, 0x01, 0x13, 0x1d, 0x47, 0x49, 0x5b, 0x55, 0x7f, 0x71, 0x63, 0x6d, + 0xd7, 0xd9, 0xcb, 0xc5, 0xef, 0xe1, 0xf3, 0xfd, 0xa7, 0xa9, 0xbb, 0xb5, + 0x9f, 0x91, 0x83, 0x8d + ], + + // Key Schedule Core + core:function(word,iteration) + { + /* rotate the 32-bit word 8 bits to the left */ + word = this.rotate(word); + /* apply S-Box substitution on all 4 parts of the 32-bit word */ + for (var i = 0; i < 4; ++i) + word[i] = this.sbox[word[i]]; + /* XOR the output of the rcon operation with i to the first part (leftmost) only */ + word[0] = word[0]^this.Rcon[iteration]; + return word; + }, + + /* Rijndael's key expansion + * expands an 128,192,256 key into an 176,208,240 bytes key + * + * expandedKey is a pointer to an char array of large enough size + * key is a pointer to a non-expanded key + */ + expandKey:function(key,size) + { + var expandedKeySize = (16*(this.numberOfRounds(size)+1)); + + /* current expanded keySize, in bytes */ + var currentSize = 0; + var rconIteration = 1; + var t = []; // temporary 4-byte variable + + var expandedKey = []; + for(var i = 0;i < expandedKeySize;i++) + expandedKey[i] = 0; + + /* set the 16,24,32 bytes of the expanded key to the input key */ + for (var j = 0; j < size; j++) + expandedKey[j] = key[j]; + currentSize += size; + + while (currentSize < expandedKeySize) + { + /* assign the previous 4 bytes to the temporary value t */ + for (var k = 0; k < 4; k++) + t[k] = expandedKey[(currentSize - 4) + k]; + + /* every 16,24,32 bytes we apply the core schedule to t + * and increment rconIteration afterwards + */ + if(currentSize % size == 0) + t = this.core(t, rconIteration++); + + /* For 256-bit keys, we add an extra sbox to the calculation */ + if(size == this.keySize.SIZE_256 && ((currentSize % size) == 16)) + for(var l = 0; l < 4; l++) + t[l] = this.sbox[t[l]]; + + /* We XOR t with the four-byte block 16,24,32 bytes before the new expanded key. + * This becomes the next four bytes in the expanded key. + */ + for(var m = 0; m < 4; m++) { + expandedKey[currentSize] = expandedKey[currentSize - size] ^ t[m]; + currentSize++; + } + } + return expandedKey; + }, + + // Adds (XORs) the round key to the state + addRoundKey:function(state,roundKey) + { + for (var i = 0; i < 16; i++) + state[i] ^= roundKey[i]; + return state; + }, + + // Creates a round key from the given expanded key and the + // position within the expanded key. + createRoundKey:function(expandedKey,roundKeyPointer) + { + var roundKey = []; + for (var i = 0; i < 4; i++) + for (var j = 0; j < 4; j++) + roundKey[j*4+i] = expandedKey[roundKeyPointer + i*4 + j]; + return roundKey; + }, + + /* substitute all the values from the state with the value in the SBox + * using the state value as index for the SBox + */ + subBytes:function(state,isInv) + { + for (var i = 0; i < 16; i++) + state[i] = isInv?this.rsbox[state[i]]:this.sbox[state[i]]; + return state; + }, + + /* iterate over the 4 rows and call shiftRow() with that row */ + shiftRows:function(state,isInv) + { + for (var i = 0; i < 4; i++) + state = this.shiftRow(state,i*4, i,isInv); + return state; + }, + + /* each iteration shifts the row to the left by 1 */ + shiftRow:function(state,statePointer,nbr,isInv) + { + for (var i = 0; i < nbr; i++) + { + if(isInv) + { + var tmp = state[statePointer + 3]; + for (var j = 3; j > 0; j--) + state[statePointer + j] = state[statePointer + j-1]; + state[statePointer] = tmp; + } + else + { + var tmp = state[statePointer]; + for (var j = 0; j < 3; j++) + state[statePointer + j] = state[statePointer + j+1]; + state[statePointer + 3] = tmp; + } + } + return state; + }, + + // galois multiplication of 8 bit characters a and b + galois_multiplication:function(a,b) + { + var p = 0; + for(var counter = 0; counter < 8; counter++) + { + if((b & 1) == 1) + p ^= a; + if(p > 0x100) p ^= 0x100; + var hi_bit_set = (a & 0x80); //keep p 8 bit + a <<= 1; + if(a > 0x100) a ^= 0x100; //keep a 8 bit + if(hi_bit_set == 0x80) + a ^= 0x1b; + if(a > 0x100) a ^= 0x100; //keep a 8 bit + b >>= 1; + if(b > 0x100) b ^= 0x100; //keep b 8 bit + } + return p; + }, + + // galois multipication of the 4x4 matrix + mixColumns:function(state,isInv) + { + var column = []; + /* iterate over the 4 columns */ + for (var i = 0; i < 4; i++) + { + /* construct one column by iterating over the 4 rows */ + for (var j = 0; j < 4; j++) + column[j] = state[(j*4)+i]; + /* apply the mixColumn on one column */ + column = this.mixColumn(column,isInv); + /* put the values back into the state */ + for (var k = 0; k < 4; k++) + state[(k*4)+i] = column[k]; + } + return state; + }, + + // galois multipication of 1 column of the 4x4 matrix + mixColumn:function(column,isInv) + { + var mult = []; + if(isInv) + mult = [14,9,13,11]; + else + mult = [2,1,1,3]; + var cpy = []; + for(var i = 0; i < 4; i++) + cpy[i] = column[i]; + + column[0] = this.galois_multiplication(cpy[0],mult[0]) ^ + this.galois_multiplication(cpy[3],mult[1]) ^ + this.galois_multiplication(cpy[2],mult[2]) ^ + this.galois_multiplication(cpy[1],mult[3]); + column[1] = this.galois_multiplication(cpy[1],mult[0]) ^ + this.galois_multiplication(cpy[0],mult[1]) ^ + this.galois_multiplication(cpy[3],mult[2]) ^ + this.galois_multiplication(cpy[2],mult[3]); + column[2] = this.galois_multiplication(cpy[2],mult[0]) ^ + this.galois_multiplication(cpy[1],mult[1]) ^ + this.galois_multiplication(cpy[0],mult[2]) ^ + this.galois_multiplication(cpy[3],mult[3]); + column[3] = this.galois_multiplication(cpy[3],mult[0]) ^ + this.galois_multiplication(cpy[2],mult[1]) ^ + this.galois_multiplication(cpy[1],mult[2]) ^ + this.galois_multiplication(cpy[0],mult[3]); + return column; + }, + + // applies the 4 operations of the forward round in sequence + round:function(state, roundKey) + { + state = this.subBytes(state,false); + state = this.shiftRows(state,false); + state = this.mixColumns(state,false); + state = this.addRoundKey(state, roundKey); + return state; + }, + + // applies the 4 operations of the inverse round in sequence + invRound:function(state,roundKey) + { + state = this.shiftRows(state,true); + state = this.subBytes(state,true); + state = this.addRoundKey(state, roundKey); + state = this.mixColumns(state,true); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the forward aes, creating a round key for each round + */ + main:function(state,expandedKey,nbrRounds) + { + state = this.addRoundKey(state, this.createRoundKey(expandedKey,0)); + for (var i = 1; i < nbrRounds; i++) + state = this.round(state, this.createRoundKey(expandedKey,16*i)); + state = this.subBytes(state,false); + state = this.shiftRows(state,false); + state = this.addRoundKey(state, this.createRoundKey(expandedKey,16*nbrRounds)); + return state; + }, + + /* + * Perform the initial operations, the standard round, and the final operations + * of the inverse aes, creating a round key for each round + */ + invMain:function(state, expandedKey, nbrRounds) + { + state = this.addRoundKey(state, this.createRoundKey(expandedKey,16*nbrRounds)); + for (var i = nbrRounds-1; i > 0; i--) + state = this.invRound(state, this.createRoundKey(expandedKey,16*i)); + state = this.shiftRows(state,true); + state = this.subBytes(state,true); + state = this.addRoundKey(state, this.createRoundKey(expandedKey,0)); + return state; + }, + + numberOfRounds:function(size) + { + var nbrRounds; + switch (size) /* set the number of rounds */ + { + case this.keySize.SIZE_128: + nbrRounds = 10; + break; + case this.keySize.SIZE_192: + nbrRounds = 12; + break; + case this.keySize.SIZE_256: + nbrRounds = 14; + break; + default: + return null; + break; + } + return nbrRounds; + }, + + // encrypts a 128 bit input block against the given key of size specified + encrypt:function(input,key,size) + { + var output = []; + var block = []; /* the 128 bit block to encode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i+(j*4))] = input[(i*4)+j]; + + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); /* the expanded key */ + /* encrypt the block using the expandedKey */ + block = this.main(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++) /* unmap the block again into the output */ + for (var l = 0; l < 4; l++) /* iterate over the rows */ + output[(k*4)+l] = block[(k+(l*4))]; + return output; + }, + + // decrypts a 128 bit input block against the given key of size specified + decrypt:function(input, key, size) + { + var output = []; + var block = []; /* the 128 bit block to decode */ + var nbrRounds = this.numberOfRounds(size); + /* Set the block values, for the block: + * a0,0 a0,1 a0,2 a0,3 + * a1,0 a1,1 a1,2 a1,3 + * a2,0 a2,1 a2,2 a2,3 + * a3,0 a3,1 a3,2 a3,3 + * the mapping order is a0,0 a1,0 a2,0 a3,0 a0,1 a1,1 ... a2,3 a3,3 + */ + for (var i = 0; i < 4; i++) /* iterate over the columns */ + for (var j = 0; j < 4; j++) /* iterate over the rows */ + block[(i+(j*4))] = input[(i*4)+j]; + /* expand the key into an 176, 208, 240 bytes key */ + var expandedKey = this.expandKey(key, size); + /* decrypt the block using the expandedKey */ + block = this.invMain(block, expandedKey, nbrRounds); + for (var k = 0; k < 4; k++)/* unmap the block again into the output */ + for (var l = 0; l < 4; l++)/* iterate over the rows */ + output[(k*4)+l] = block[(k+(l*4))]; + return output; + } + }, + /* + * END AES SECTION + */ + + /* + * START MODE OF OPERATION SECTION + */ + //structure of supported modes of operation + modeOfOperation:{ + OFB:0, + CFB:1, + CBC:2 + }, + + // get a 16 byte block (aes operates on 128bits) + getBlock: function(bytesIn,start,end,mode) + { + if(end - start > 16) + end = start + 16; + + return bytesIn.slice(start, end); + }, + + /* + * Mode of Operation Encryption + * bytesIn - Input String as array of bytes + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + encrypt: function (bytesIn, mode, key, iv) + { + var size = key.length; + if(iv.length%16) + { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var byteArray = []; + var input = []; + var output = []; + var ciphertext = []; + var cipherOut = []; + // char firstRound + var firstRound = true; + if (mode == this.modeOfOperation.CBC) + this.padBytesIn(bytesIn); + if (bytesIn !== null) + { + for (var j = 0;j < Math.ceil(bytesIn.length/16); j++) + { + var start = j*16; + var end = j*16+16; + if(j*16+16 > bytesIn.length) + end = bytesIn.length; + byteArray = this.getBlock(bytesIn,start,end,mode); + if (mode == this.modeOfOperation.CFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for(var k = 0;k < end-start;k++) + cipherOut.push(ciphertext[k]); + input = ciphertext; + } + else if (mode == this.modeOfOperation.OFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (var i = 0; i < 16; i++) + ciphertext[i] = byteArray[i] ^ output[i]; + for(var k = 0;k < end-start;k++) + cipherOut.push(ciphertext[k]); + input = output; + } + else if (mode == this.modeOfOperation.CBC) + { + for (var i = 0; i < 16; i++) + input[i] = byteArray[i] ^ ((firstRound) ? iv[i] : ciphertext[i]); + firstRound = false; + ciphertext = this.aes.encrypt(input, key, size); + // always 16 bytes because of the padding for CBC + for(var k = 0;k < 16;k++) + cipherOut.push(ciphertext[k]); + } + } + } + return cipherOut; + }, + + /* + * Mode of Operation Decryption + * cipherIn - Encrypted String as array of bytes + * originalsize - The unencrypted string length - required for CBC + * mode - mode of type modeOfOperation + * key - a number array of length 'size' + * size - the bit length of the key + * iv - the 128 bit number array Initialization Vector + */ + decrypt:function(cipherIn,mode,key,iv) + { + var size = key.length; + if(iv.length%16) + { + throw 'iv length must be 128 bits.'; + } + // the AES input/output + var ciphertext = []; + var input = []; + var output = []; + var byteArray = []; + var bytesOut = []; + // char firstRound + var firstRound = true; + if (cipherIn !== null) + { + for (var j = 0;j < Math.ceil(cipherIn.length/16); j++) + { + var start = j*16; + var end = j*16+16; + if(j*16+16 > cipherIn.length) + end = cipherIn.length; + ciphertext = this.getBlock(cipherIn,start,end,mode); + if (mode == this.modeOfOperation.CFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for(var k = 0;k < end-start;k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + else if (mode == this.modeOfOperation.OFB) + { + if (firstRound) + { + output = this.aes.encrypt(iv, key, size); + firstRound = false; + } + else + output = this.aes.encrypt(input, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = output[i] ^ ciphertext[i]; + for(var k = 0;k < end-start;k++) + bytesOut.push(byteArray[k]); + input = output; + } + else if(mode == this.modeOfOperation.CBC) + { + output = this.aes.decrypt(ciphertext, key, size); + for (i = 0; i < 16; i++) + byteArray[i] = ((firstRound) ? iv[i] : input[i]) ^ output[i]; + firstRound = false; + for(var k = 0;k < end-start;k++) + bytesOut.push(byteArray[k]); + input = ciphertext; + } + } + if(mode == this.modeOfOperation.CBC) + this.unpadBytesOut(bytesOut); + } + return bytesOut; + }, + padBytesIn: function(data) { + var len = data.length; + var padByte = 16 - (len % 16); + for (var i = 0; i < padByte; i++) { + data.push(padByte); + } + }, + unpadBytesOut: function(data) { + var padCount = 0; + var padByte = -1; + var blockSize = 16; + for (var i = data.length - 1; i >= data.length-1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) + padByte = data[i]; + if (data[i] != padByte) { + padCount = 0; + break; + } + padCount++; + } else + break; + if (padCount == padByte) + break; + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); + } + /* + * END MODE OF OPERATION SECTION + */ +}; diff --git a/modules/ngx_http_bot_protection_module/util/back/aes.patch b/modules/ngx_http_bot_protection_module/util/back/aes.patch new file mode 100644 index 0000000..c4aa7a1 --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/back/aes.patch @@ -0,0 +1,18 @@ +--- aes.min.js 2012-05-05 22:03:32.000000000 +0400 ++++ aes.min.new.js 2012-05-05 22:15:46.000000000 +0400 +@@ -767,6 +767,7 @@ + var padCount = 0; + var padByte = -1; + var blockSize = 16; ++ if (data.length > 16) { + for (var i = data.length - 1; i >= data.length-1 - blockSize; i--) { + if (data[i] <= blockSize) { + if (padByte == -1) +@@ -783,6 +784,7 @@ + } + if (padCount > 0) + data.splice(data.length - padCount, padCount); ++ } + } + /* + * END MODE OF OPERATION SECTION diff --git a/modules/ngx_http_bot_protection_module/util/back/tests.sh b/modules/ngx_http_bot_protection_module/util/back/tests.sh new file mode 100644 index 0000000..72c4bbd --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/back/tests.sh @@ -0,0 +1,5 @@ +#!/bin/sh + + +export TEST_NGINX_PORT=30001 +prove -v -r t diff --git a/modules/ngx_http_bot_protection_module/util/back/valgrind.sh b/modules/ngx_http_bot_protection_module/util/back/valgrind.sh new file mode 100644 index 0000000..c5297ff --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/back/valgrind.sh @@ -0,0 +1,6 @@ +#!/bin/sh + + +export TEST_NGINX_PORT=30001 +export TEST_NGINX_USE_VALGRIND=1 +prove -v -r t diff --git a/modules/ngx_http_bot_protection_module/util/tests.sh b/modules/ngx_http_bot_protection_module/util/tests.sh new file mode 100644 index 0000000..72c4bbd --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/tests.sh @@ -0,0 +1,5 @@ +#!/bin/sh + + +export TEST_NGINX_PORT=30001 +prove -v -r t diff --git a/modules/ngx_http_bot_protection_module/util/valgrind.sh b/modules/ngx_http_bot_protection_module/util/valgrind.sh new file mode 100644 index 0000000..c5297ff --- /dev/null +++ b/modules/ngx_http_bot_protection_module/util/valgrind.sh @@ -0,0 +1,6 @@ +#!/bin/sh + + +export TEST_NGINX_PORT=30001 +export TEST_NGINX_USE_VALGRIND=1 +prove -v -r t diff --git a/modules/ngx_http_captcha_module/README.md b/modules/ngx_http_captcha_module/README.md new file mode 100644 index 0000000..2a069be --- /dev/null +++ b/modules/ngx_http_captcha_module/README.md @@ -0,0 +1,81 @@ +# ngx_http_captcha_module +

说明:

+
此nginx模块可直接生成验证码和验证验证码,可在nginx配置中自定义验证码大小、长度、字体、过期时间等。此项目无需版权,可自由下载使用或二次开发。
+

+

安装方法:

+
1. $ cp ngx_http_captcha_module.c /usr/local/src/nginx-1.14.0/src/http/modules/
+
2. cd /usr/local/src/nginx-1.14.0
+
3. $ vim auto/modules
+
添加代码
+

+if :; then
+    ngx_module_name=ngx_http_captcha_module
+    ngx_module_incs=
+    ngx_module_deps=
+    ngx_module_srcs=src/http/modules/ngx_http_captcha_module.c
+    ngx_module_libs=
+    ngx_module_link=YES
+
+    . auto/module
+fi
+
+
4. $ ./configure --with-debug
+
5. $ vim objs/Makefile
+ +
找到
+

+objs/src/http/modules/ngx_http_captcha_module.o:        $(CORE_DEPS) $(HTTP_DEPS) \
+        src/http/modules/ngx_http_captcha_module.c
+        $(CC) -c -g $(CFLAGS) $(CORE_INCS) $(HTTP_INCS) \
+                -o objs/src/http/modules/ngx_http_captcha_module.o \
+                src/http/modules/ngx_http_captcha_module.c
+
+ +
改为
+

+objs/src/http/modules/ngx_http_captcha_module.o:        $(CORE_DEPS) $(HTTP_DEPS) \
+        src/http/modules/ngx_http_captcha_module.c
+        $(CC) -c -g $(CFLAGS) $(CORE_INCS) $(HTTP_INCS) \
+                -I /usr/include -I /usr/local/include \
+                -L /usr/lib/ -L /usr/local/lib/ -lgd -lhiredis \
+                -o objs/src/http/modules/ngx_http_captcha_module.o \
+                src/http/modules/ngx_http_captcha_module.c
+
+
找到
+

+-ldl -lrt -lpthread -lcrypt -lpcre -lz \
+
+
改为
+

+-ldl -lrt -lpthread -lcrypt -lpcre -lz -lgd -lhiredis \
+
+
6. $ make && make install
+ +

+

nginx配置

+

+    location /captcha_img {
+        captcha_redis_conf 127.0.0.1 6379;    #redis配置,默认127.0.0.1 6379
+        captcha_init;                         #验证码初始化
+        captcha_width 130;                    #验证码宽度,默认130像素
+        captcha_height 30;                    #验证码高度,默认30像素
+        captcha_length 4;                     #验证码长度,默认4,最大长度6
+        captcha_font /data/font/elephant.ttf; #字体库
+        captcha_expire 3600;                  #过期时间, 默认3600秒
+        captcha_output;                       #输出图像
+    }
+
+    location /captcha_auth {
+        captcha_redis_conf 127.0.0.1 6379;    #redis配置,默认127.0.0.1 6379
+        captcha_auth;                         #验证
+    }
+
+ +
重启nginx +
访问http://xxx/captcha_img显示验证码图片
+
访问http://xxx/captcha_auth?captcha_code=1234
+
captcha_code=1234为用户输入的验证码参数,用get请求方式
+ +

+

联系方式:

+
欢迎发邮件962404383@qq.com,一起学习交流
\ No newline at end of file diff --git a/modules/ngx_http_captcha_module/config b/modules/ngx_http_captcha_module/config new file mode 100644 index 0000000..287716d --- /dev/null +++ b/modules/ngx_http_captcha_module/config @@ -0,0 +1,12 @@ +ngx_addon_name=ngx_http_captcha_module + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=ngx_http_captcha_module + ngx_module_srcs="$ngx_addon_dir/ngx_http_captcha_module.c" + . auto/module +else + + HTTP_MODULES="$HTTP_MODULES ngx_http_captcha_module.c" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_captcha_module.c" +fi diff --git a/modules/ngx_http_captcha_module/ngx_http_captcha_module.c b/modules/ngx_http_captcha_module/ngx_http_captcha_module.c new file mode 100644 index 0000000..363581e --- /dev/null +++ b/modules/ngx_http_captcha_module/ngx_http_captcha_module.c @@ -0,0 +1,1092 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include /* 1 Tiny font */ +#include /* 2 Small font */ +#include /* 3 Medium bold font */ +#include /* 4 Large font */ +#include /* 5 Giant font */ +#include + + +#define M_PI 3.14159265358979323846 +#define MAXPATHLEN 256 +#define CHARSET "abcdefghijklamnop23456789" +#define CHARSET_LEN strlen(CHARSET) +#define FONT_SIZE 20 +#define TTFTEXT_DRAW 0 +#define CAPTCHA_CODE_LEN 4 +#define CAPTCHA_CODE_LEN_MAX 6 +#define CAPTCHA_WIDTH 130 +#define CAPTCHA_HEIGHT 30 +#define CAPTCHA_REDIS_HOST "127.0.0.1" +#define CAPTCHA_REDIS_PORT 6379 +#define CAPTCHA_EXPIRE 3600 +#define CAPTCHA_COOKIE_NAME "IronFox" +#ifndef MD5_DIGEST_LENGTH +#define MD5_DIGEST_LENGTH 16 +#endif + +#define CAPTCHA_ARG_NAME "captcha_code" +#define CAPTCHA_SECURITY_KEY "@@^Shcv&" +#define AUTH_SUCCESS "{\"code\" : 0, \"data\" : [], \"message\" : \"SUCCESS\"}" +#define AUTH_FAIL "{\"code\" : -1, \"data\" : [], \"message\" : \"FAIL\"}" + +unsigned seed; + +typedef struct _ngx_captcha_redis_conf { + char *host; + int port; +} ngx_captcha_redis_conf; + +typedef struct _ngx_captcha_conf { + ngx_int_t width; + ngx_int_t height; + ngx_int_t length; + char *font; + ngx_int_t expire; + ngx_captcha_redis_conf *redis_conf; +} ngx_captcha_conf; + +typedef struct _png_stream_buffer { + char *buffer; + size_t size; + ngx_pool_t *pool; +} png_stream_buffer; + + +typedef struct _ngx_captcha_cookie { + ngx_str_t path; + ngx_str_t domain; + ngx_str_t expire; + ngx_str_t name; + ngx_str_t value; +} ngx_captcha_cookie; + +static void *ngx_prealloc(ngx_pool_t *pool, void *p, size_t old_size, size_t new_size); + +static int mt_rand(int min, int max); + +static void create_code(char *code, int len); + +static gdImagePtr create_bg(int width, int height); + +static void +gd_image_TTF_text(gdImagePtr img, int font_size, int angle, long x, long y, long font_color, const char *font, + char *str); + +static void create_font(gdImagePtr img, char *code, int len, int width, int height, char *font); + +static void create_line(gdImagePtr img, int width, int height, char *font); + +static void _image_output_putc(struct gdIOCtx *ctx, int c); + +static int _image_output_putbuf(struct gdIOCtx *ctx, const void *buf, int len); + +static void _image_output_ctxfree(struct gdIOCtx *ctx); + +static void freeCtx(ngx_pool_t *pool, gdIOCtx *ctx); + +static void get_png_stream_buffer(ngx_pool_t *pool, gdImagePtr img, char *buf, int *len); + +static void create_captcha_png(ngx_pool_t *pool, char *buf, int *len, char *code, ngx_captcha_conf *captcha); + +static in_addr_t get_remote_ip(ngx_http_request_t *req); + +static ngx_str_t get_user_agent(ngx_http_request_t *req); + +static u_char *get_unique_id(ngx_http_request_t *req); + +static u_char *user_crc_hash(ngx_http_request_t *req); + +static redisContext *connectRedis(char *host, int port, ngx_log_t *log); + +static ngx_int_t closeRedisConnect(redisContext *conn); + +static ngx_int_t redisSetex(redisContext *conn, char *key, int expire_time, char *val, ngx_log_t *log); + +static ngx_int_t redisGet(redisContext *conn, char *key, u_char *result, ngx_log_t *log); + +static void create_captcha_img(ngx_pool_t *pool, char *img_buf, int *len, char *code, ngx_captcha_conf *captcha_conf); + +static void save_captcha_code(ngx_http_request_t *req, char *code); + +static ngx_captcha_cookie *generate_captcha_cookie(ngx_http_request_t *req, ngx_captcha_conf *captcha_conf); + +static ngx_int_t set_captcha_cookie(ngx_http_request_t *req, ngx_captcha_conf *captcha_conf); + +static ngx_uint_t get_captcha_cookie(ngx_http_request_t *req, u_char *captcha_id); + +static ngx_uint_t get_query_param_value(ngx_http_request_t *req, const char *param_name, ngx_str_t *param_value); + +static ngx_int_t get_user_captcha_code(ngx_http_request_t *req, u_char *input_code); + +static char *set_captcha_init(ngx_conf_t *, ngx_command_t *, void *); + +static char *set_captcha_font(ngx_conf_t *, ngx_command_t *, void *); + +static char *set_captcha_width(ngx_conf_t *, ngx_command_t *, void *); + +static char *set_captcha_height(ngx_conf_t *, ngx_command_t *, void *); + +static char *set_captcha_length(ngx_conf_t *, ngx_command_t *, void *); + +static char *set_captcha_expire(ngx_conf_t *, ngx_command_t *, void *); + +static char *set_captcha_redis_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static char *set_captcha_output_handler(ngx_conf_t *, ngx_command_t *, void *); + +static ngx_int_t captcha_output_handler(ngx_http_request_t *req); + +static char *set_captcha_auth_handler(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + +static ngx_int_t captcha_auth_handler(ngx_http_request_t *req); + +// khalegh +static u_char * +ngx_cookie_digest_hex(u_char *dest, const u_char *buf, int buf_len); + +static ngx_str_t +ngx_http_get_ironfox_cid(ngx_http_request_t *req, ngx_str_t *KEY); + + +static ngx_command_t captcha_commands[] = { + { + ngx_string("ironfox_captcha_redis_conf"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE2, + set_captcha_redis_conf, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_init"), + NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, + set_captcha_init, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_font"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + set_captcha_font, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_width"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + set_captcha_width, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_height"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + set_captcha_height, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_length"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + set_captcha_length, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_expire"), + NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + set_captcha_expire, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_output"), + NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, + set_captcha_output_handler, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + { + ngx_string("ironfox_captcha_auth"), + NGX_HTTP_LOC_CONF | NGX_CONF_NOARGS, + set_captcha_auth_handler, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL + }, + ngx_null_command +}; + +static ngx_http_module_t captcha_ctx = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +ngx_module_t ngx_http_captcha_module = { + NGX_MODULE_V1, + &captcha_ctx, + captcha_commands, + NGX_HTTP_MODULE, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NGX_MODULE_V1_PADDING +}; + +ngx_captcha_conf *captcha_conf; +ngx_captcha_redis_conf *redis_conf; + +static void * +ngx_prealloc(ngx_pool_t *pool, void *p, size_t old_size, size_t new_size) { + void *new; + + if (p == NULL) { + return ngx_palloc(pool, new_size); + } + + if (new_size == 0) { + if ((u_char *) p + old_size == pool->d.last) { + pool->d.last = p; + } else { + ngx_pfree(pool, p); + } + + return NULL; + } + + if ((u_char *) p + old_size == pool->d.last + && (u_char *) p + new_size <= pool->d.end) { + pool->d.last = (u_char *) p + new_size; + return p; + } + + new = ngx_palloc(pool, new_size); + if (new == NULL) { + return NULL; + } + + ngx_memcpy(new, p, old_size); + + ngx_pfree(pool, p); + + return new; +} + +static int +mt_rand(int min, int max) { + srand(seed++); + + return (rand() % (max - min + 1)) + min; +} + +static void +create_code(char *code, int len) { + int i = 0; + int idx = 0; + + for (i = 0; i < len; i++) { + idx = mt_rand(0, CHARSET_LEN - 1); + code[i] = CHARSET[idx]; + } +} + +static gdImagePtr +create_bg(int width, int height) { + gdImagePtr img; + int color; + + img = gdImageCreateTrueColor(width, height); + color = gdImageColorAllocate(img, mt_rand(157, 255), mt_rand(157, 255), mt_rand(157, 255)); + gdImageFilledRectangle(img, 0, height, width, 0, color); + + return img; +} + +static void +gd_image_TTF_text(gdImagePtr img, int font_size, int angle, long x, long y, long font_color, const char *font, + char *str) { + int brect[8]; + char *error = NULL; + + angle = angle * (M_PI / 180); + error = gdImageStringFT(img, brect, font_color, (char *) font, font_size, angle, x, y, str); +} + +static void +create_font(gdImagePtr img, char *code, int len, int width, int height, char *font) { + int x = width / len; + int i = 0; + int font_color = 0; + char str[2] = "\0"; + + for (i = 0; i < len; i++) { + memcpy(str, code++, 1); + font_color = gdImageColorAllocate(img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156)); + gd_image_TTF_text(img, FONT_SIZE, mt_rand(-30, 30), x * i + mt_rand(1, 5), height / 1.4, font_color, font, str); + } + +} + + +static void +create_line(gdImagePtr img, int width, int height, char *font) { + int i, brect[8]; + int color = 0; + const char *str = "*"; + int font_size = 8; + int angle = 0; + + for (i = 0; i < 6; i++) { + color = gdImageColorAllocate(img, mt_rand(0, 156), mt_rand(0, 156), mt_rand(0, 156)); + gdImageLine(img, mt_rand(0, width), mt_rand(0, height), mt_rand(0, width), mt_rand(0, height), color); + } + + for (i = 0; i < 100; i++) { + color = gdImageColorAllocate(img, mt_rand(200, 255), mt_rand(200, 255), mt_rand(200, 255)); + gdImageStringFT(img, brect, color, font, font_size, angle, mt_rand(0, width), mt_rand(0, height), (char *) str); + } + +} + + +static void +_image_output_putc(struct gdIOCtx *ctx, int c) { + +} + +static int +_image_output_putbuf(struct gdIOCtx *ctx, const void *buf, int len) { + + png_stream_buffer *p = (png_stream_buffer *) ctx->data; + size_t nsize = p->size + len; + + if (p->buffer) { + p->buffer = ngx_prealloc(p->pool, p->buffer, p->size, nsize); + } else { + p->buffer = ngx_pcalloc(p->pool, nsize);//alloc 1 + } + + if (!p->buffer) { + return -1; + } + + memcpy(p->buffer + p->size, buf, len); + p->size += len; + + return 0; +} + +static void +_image_output_ctxfree(struct gdIOCtx *ctx) { + +} + +static void +freeCtx(ngx_pool_t *pool, gdIOCtx *ctx) { + png_stream_buffer *p = (png_stream_buffer *) ctx->data; + ngx_pfree(pool, p->buffer);//free 3 + ngx_pfree(pool, ctx->data);//free 1 + //ctx->gd_free(ctx); + ngx_pfree(pool, ctx);//free 2 +} + +static void +get_png_stream_buffer(ngx_pool_t *pool, gdImagePtr img, char *buf, int *len) { + int q = -1; + gdIOCtx *ctx; + png_stream_buffer *p; + ctx = (gdIOCtx *) ngx_pcalloc(pool, sizeof(gdIOCtx));//alloc 2 + ctx->putC = _image_output_putc; + ctx->putBuf = _image_output_putbuf; + ctx->gd_free = _image_output_ctxfree; + p = (png_stream_buffer *) ngx_pcalloc(pool, sizeof(png_stream_buffer));//alloc 3 + p->pool = pool; + ctx->data = p; + gdImagePngCtxEx(img, ctx, q); + p = (png_stream_buffer *) ctx->data; + buf = memcpy(buf, p->buffer, p->size); + *len = p->size; + freeCtx(pool, ctx); +} + +static void +create_captcha_png(ngx_pool_t *pool, char *buf, int *len, char *code, ngx_captcha_conf *captcha) { + gdImagePtr img; + seed = (unsigned int) time(NULL); + create_code(code, captcha->length); + img = create_bg(captcha->width, captcha->height); + create_font(img, code, captcha->length, captcha->width, captcha->height, captcha->font); + create_line(img, captcha->width, captcha->height, captcha->font); + get_png_stream_buffer(pool, img, buf, len); + gdImageDestroy(img); +} + +static void +redis_conf_init(ngx_conf_t *cf) { + redis_conf = (ngx_captcha_redis_conf *) ngx_pcalloc(cf->pool, sizeof(ngx_captcha_redis_conf));//alloc 4 + redis_conf->host = (char *) CAPTCHA_REDIS_HOST; + redis_conf->port = CAPTCHA_REDIS_PORT; +}; + + +static char * +set_captcha_init(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + + if (!redis_conf) { + redis_conf_init(cf); + } + captcha_conf = (ngx_captcha_conf *) ngx_pcalloc(cf->pool, sizeof(ngx_captcha_conf));//alloc 5 + captcha_conf->width = CAPTCHA_WIDTH; + captcha_conf->height = CAPTCHA_HEIGHT; + captcha_conf->length = CAPTCHA_CODE_LEN; + captcha_conf->font = NULL; + captcha_conf->expire = CAPTCHA_EXPIRE; + captcha_conf->redis_conf = redis_conf; + return NGX_CONF_OK; +}; + +static char * +set_captcha_font(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + value = cf->args->elts; + captcha_conf->font = (char *) value[1].data; + return NGX_CONF_OK; +}; + +static char * +set_captcha_width(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + ngx_int_t w; + value = cf->args->elts; + w = ngx_atoi(value[1].data, value[1].len); + captcha_conf->width = w < 0 ? 0 : w; + return NGX_CONF_OK; +}; + +static char * +set_captcha_height(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + ngx_int_t h; + value = cf->args->elts; + h = ngx_atoi(value[1].data, value[1].len); + captcha_conf->height = h < 0 ? 0 : h; + return NGX_CONF_OK; +}; + +static char * +set_captcha_length(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + ngx_int_t len; + value = cf->args->elts; + len = ngx_atoi(value[1].data, value[1].len); + captcha_conf->length = len > CAPTCHA_CODE_LEN_MAX ? CAPTCHA_CODE_LEN_MAX : len; + return NGX_CONF_OK; +}; + + +static char * +set_captcha_expire(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + ngx_int_t exp; + value = cf->args->elts; + exp = ngx_atoi(value[1].data, value[1].len); + captcha_conf->expire = exp < 0 ? 0 : exp; + return NGX_CONF_OK; +}; + + +static char * +set_captcha_auth_handler(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_core_loc_conf_t *corecf; + corecf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + corecf->handler = captcha_auth_handler; + if (!redis_conf) { + redis_conf_init(cf); + } + return NGX_CONF_OK; +}; + +static char * +set_captcha_redis_conf(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_str_t *value; + value = cf->args->elts; + if (!redis_conf) { + redis_conf_init(cf); + } + redis_conf->host = (char *) value[1].data; + redis_conf->port = ngx_atoi(value[2].data, value[2].len); + + return NGX_CONF_OK; +}; + +static char * +set_captcha_output_handler(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_core_loc_conf_t *corecf; + corecf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + corecf->handler = captcha_output_handler; + return NGX_CONF_OK; +}; + +/* + * khalegh + */ + +static u_char * +ngx_cookie_digest_hex(u_char *dest, const u_char *buf, int buf_len) { + ngx_md5_t md5; + u_char md5_buf[MD5_DIGEST_LENGTH]; + + ngx_md5_init(&md5); + ngx_md5_update(&md5, buf, buf_len); + ngx_md5_final(md5_buf, &md5); + + return ngx_hex_dump(dest, md5_buf, sizeof(md5_buf)); +} + +static ngx_str_t +ngx_http_get_ironfox_cid(ngx_http_request_t *req, ngx_str_t *KEY) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: ====[ngx_http_get_ironfox_cid start]===="); + + u_char *tmpcrc_str; + ngx_str_t tmpua; + in_addr_t tmpip; + u_char *finalhash; + + tmpip = get_remote_ip(req); // get user ip + tmpua = get_user_agent(req); // get user aget + + tmpcrc_str = ngx_pcalloc(req->pool, tmpua.len + 19);//alloc n + finalhash = ngx_pcalloc(req->pool, tmpua.len + 19);//alloc n + ngx_sprintf(tmpcrc_str, "%ul%s%s", tmpip, tmpua.data, KEY); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: tmpcrc_str md5 raw value %s", + tmpcrc_str); + ngx_cookie_digest_hex(finalhash, tmpcrc_str, ngx_strlen(tmpcrc_str)); + + ngx_pfree(req->pool, tmpcrc_str);//free n + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: [%s] tmpcrc hashed md5 value", + finalhash); + ngx_str_t res; + res.data = finalhash; + + ngx_pfree(req->pool, finalhash);//free n + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: res value before return %s len %d", res.data, res.len); + + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: ====[ngx_http_get_ironfox_cid end]===="); + + return res; +} + + +static u_char * +get_unique_id(ngx_http_request_t *req) { + return user_crc_hash(req); +} + +static redisContext * +connectRedis(char *host, int port, ngx_log_t *log) { + redisContext *conn = redisConnect(host, port); + if (conn != NULL && conn->err) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "captcha: can't connect to redis by host[%s] port[%d]", + host, port); + return conn; + } + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, log, 0, + "captcha: connect to redis by host[%s] port[%d]", + host, port); + return conn; +} + +static ngx_int_t +closeRedisConnect(redisContext *conn) { + redisFree(conn); + return NGX_OK; +} + +static ngx_int_t +redisSetex(redisContext *conn, char *key, int expire_time, char *val, ngx_log_t *log) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + log, + 0, + "captcha: redisSETEX called"); + redisReply *reply; + reply = redisCommand(conn, "SETEX %s %d %s", key, expire_time, val); + if (reply->type == REDIS_REPLY_ERROR) { + ngx_log_error(NGX_LOG_ERR, log, 0, + "captcha: redis command[SETEX %s %d %s] result[%s]", + key, expire_time, val, reply->str); + freeReplyObject(reply); + closeRedisConnect(conn); + return NGX_ERROR; + } + ngx_log_debug(NGX_LOG_DEBUG_HTTP, log, 0, + "captcha: redis command[SETEX %s %d %s] result[%s]", + key, expire_time, val, reply->str); + freeReplyObject(reply); + return NGX_OK; +} + +static ngx_int_t +redisGet(redisContext *conn, char *key, u_char *result, ngx_log_t *log) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, log, 0, + "captcha: redisGET called"); + redisReply *reply; + + reply = redisCommand(conn, "GET %s", key); + //reply = redisCommand(conn, "GET DSSSSSSDFDDDDDDDDDDDDD"); + + + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + log, + 0, + "captcha: resualt redis command[GET %s] result[%d]", + key, reply->type + ); + + + if (reply->type == REDIS_REPLY_ERROR || reply->type == REDIS_REPLY_NIL) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + log, + 0, + "captcha: ==[Error]== redis command[GET %s] result[%d]", + key, reply->type + ); + + } else { + result = ngx_copy(result, (u_char *) reply->str, ngx_strlen(reply->str)); + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + log, + 0, + "captcha: redis command[GET %s] result[%s]", + key, reply->str + ); + } + + freeReplyObject(reply); + return NGX_OK; +} + +static void +create_captcha_img(ngx_pool_t *pool, char *img_buf, int *len, char *code, ngx_captcha_conf *captcha_conf) { + create_captcha_png(pool, img_buf, len, code, captcha_conf); +} + +static void +save_captcha_code(ngx_http_request_t *req, char *code) { + //u_char *unique_id = get_unique_id(req); + + u_char *unique_id; + unique_id = malloc(31 * sizeof(unsigned char)); + strncpy(unique_id, user_crc_hash(req), 31); + + + + + + redisContext *conn = connectRedis(redis_conf->host, redis_conf->port, req->connection->log); + redisSetex(conn, (char *) unique_id, CAPTCHA_EXPIRE, code, req->connection->log); + closeRedisConnect(conn); + ngx_pfree(req->pool, unique_id);//free 6 +} + +static ngx_captcha_cookie * +generate_captcha_cookie(ngx_http_request_t *req, ngx_captcha_conf *captcha_conf) { + u_char *value; + size_t value_len; + u_char *expire, *p; + size_t expire_len; + size_t exp_len; + + ngx_captcha_cookie *captcha_cookie; + + captcha_cookie = (ngx_captcha_cookie *) ngx_pcalloc(req->pool, sizeof(ngx_captcha_cookie));//alloc 7 + + value = get_unique_id(req); + value_len = 32; + + exp_len = ngx_strlen("; expires="); + expire = (u_char *) ngx_pcalloc(req->pool, exp_len + 40);//alloc 8 + p = expire; + p = ngx_copy(p, "; expires=", exp_len); + p = ngx_http_cookie_time(p, ngx_time() + 8 * 3600 + captcha_conf->expire); + expire_len = ngx_strlen((const char *) expire); + + captcha_cookie->name.data = (u_char *) CAPTCHA_COOKIE_NAME; + captcha_cookie->name.len = strlen(CAPTCHA_COOKIE_NAME); + captcha_cookie->value.data = value; + captcha_cookie->value.len = value_len; + captcha_cookie->expire.data = expire; + captcha_cookie->expire.len = expire_len; + captcha_cookie->path.data = (u_char *) "; path=/;"; + captcha_cookie->path.len = ngx_strlen("; path=/;"); + + return captcha_cookie; +} + +static ngx_int_t +set_captcha_cookie(ngx_http_request_t *req, ngx_captcha_conf *captcha_conf) { + u_char *cookie, *p; + size_t len; + ngx_table_elt_t *set_cookie; + // k1 generate captcha + ngx_captcha_cookie *captcha_cookie = generate_captcha_cookie(req, captcha_conf); + + len = captcha_cookie->name.len + 1 + captcha_cookie->value.len; + + if (captcha_cookie->expire.len) { + len += captcha_cookie->expire.len; + } + + if (captcha_cookie->path.len) { + len += captcha_cookie->path.len; + } + + cookie = ngx_pnalloc(req->pool, len);//alloc 9 + + if (cookie == NULL) { + ngx_log_error(NGX_LOG_ERR, req->connection->log, 0, + "captcha: cookie ngx_pnalloc error length[%d]", + len); + return NGX_ERROR; + } + + p = ngx_copy(cookie, captcha_cookie->name.data, captcha_cookie->name.len); + *p++ = '='; + p = ngx_copy(p, captcha_cookie->value.data, captcha_cookie->value.len); + + if (captcha_cookie->expire.len) { + p = ngx_copy(p, captcha_cookie->expire.data, captcha_cookie->expire.len); + } + + if (captcha_cookie->path.len) { + p = ngx_copy(p, captcha_cookie->path.data, captcha_cookie->path.len); + } + + ngx_pfree(req->pool, captcha_cookie->value.data);//free 6 + ngx_pfree(req->pool, captcha_cookie->expire.data);//free 8 + ngx_pfree(req->pool, captcha_cookie);//free 7 + + set_cookie = ngx_list_push(&req->headers_out.headers); + if (set_cookie == NULL) { + ngx_log_error(NGX_LOG_ERR, req->connection->log, 0, + "captcha: set_cookie ngx_list_push error cookie[%s]", + cookie); + return NGX_ERROR; + } + + set_cookie->hash = 1; + ngx_str_set(&set_cookie->key, "Set-Cookie"); + set_cookie->value.len = p - cookie; + set_cookie->value.data = cookie; + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: captcha cookie: \"%V\"", &set_cookie->value); + + + return NGX_OK; +} + + +static ngx_uint_t +get_captcha_cookie(ngx_http_request_t *req, u_char *captcha_id) { + ngx_str_t cookie_name; + ngx_str_t cookie_value; + + cookie_name.data = (u_char *) CAPTCHA_COOKIE_NAME; + cookie_name.len = ngx_strlen(CAPTCHA_COOKIE_NAME); + + ngx_uint_t n = ngx_http_parse_multi_header_lines(&req->headers_in.cookies, &cookie_name, &cookie_value); + captcha_id = ngx_cpymem(captcha_id, cookie_value.data, 32); + + return n; +} + +static ngx_uint_t +get_query_param_value(ngx_http_request_t *req, const char *param_name, ngx_str_t *param_value) { + size_t param_name_len; + param_name_len = ngx_strlen(param_name); + if (ngx_http_arg(req, (u_char *) param_name, param_name_len, param_value) != NGX_OK) { + param_value->len = 0; + } + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: get_query_param_value param_name[%s:%d] param_value[%s:%d]", + param_name, param_name_len, param_value->data, param_value->len + ); + return NGX_OK; +} + +static ngx_int_t +get_user_captcha_code(ngx_http_request_t *req, u_char *input_code) { + ngx_int_t ret; + ngx_str_t param_value; + + if (!(req->method & NGX_HTTP_GET)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: get_user_captcha_code request method error"); + + return NGX_ERROR; + } + + ret = ngx_http_discard_request_body(req); + + if (NGX_OK != ret) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: get_user_captcha_code discard_request_body error"); + return NGX_ERROR; + } + + ret = get_query_param_value(req, CAPTCHA_ARG_NAME, ¶m_value); + + if (ret == NGX_OK) { + input_code = ngx_cpymem(input_code, param_value.data, param_value.len); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: input_code value [%s]", input_code); + + return NGX_OK; + } + + return NGX_ERROR; +} + +static in_addr_t +get_remote_ip(ngx_http_request_t *req) { + in_addr_t inaddr; + struct sockaddr_in *sin; + + sin = (struct sockaddr_in *) req->connection->sockaddr; + inaddr = ntohl(sin->sin_addr.s_addr); + + return inaddr; +} + +static ngx_str_t +get_user_agent(ngx_http_request_t *req) { + return req->headers_in.user_agent->value; +} + +static u_char * +user_crc_hash(ngx_http_request_t *req) { + ngx_str_t hashC; + hashC.data = ngx_http_get_ironfox_cid(req, CAPTCHA_SECURITY_KEY).data; + + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: ironfox_cid value [%s]", + hashC.data + ); + u_char *cookie; + cookie = malloc(32 * sizeof(unsigned char)); + strncpy(cookie, hashC.data, 32); + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: cookie hash value [%s] before return to parent", + cookie + ); + return cookie; +} + +static ngx_int_t +captcha_output_handler(ngx_http_request_t *req) { + int len = 0; + u_char img_buf[6144] = {"\0"}; + u_char code[CAPTCHA_CODE_LEN_MAX] = {"\0"}; + + create_captcha_img(req->pool, (char *) img_buf, &len, (char *) code, captcha_conf); + save_captcha_code(req, (char *) code); + set_captcha_cookie(req, captcha_conf); + ngx_pfree(req->pool, captcha_conf);//free 5 + ngx_pfree(req->pool, redis_conf);//free 4 + + req->headers_out.status = 200; + req->headers_out.content_length_n = len; + ngx_str_set(&req->headers_out.content_type, "image/png"); + ngx_http_send_header(req); + + ngx_buf_t *b; + b = ngx_pcalloc(req->pool, sizeof(ngx_buf_t)); + ngx_chain_t out; + out.buf = b; + out.next = NULL; + b->pos = (u_char *) img_buf; + b->last = (u_char *) img_buf + len; + b->memory = 1; + b->last_buf = 1; + + return ngx_http_output_filter(req, &out); +} + + +static ngx_int_t +captcha_auth_handler(ngx_http_request_t *req) { + size_t len = 0; + ngx_int_t ret; + u_char *auth_result; + u_char captcha_id[32] = {'\0'}; + + u_char *unique_id; + u_char input_code[CAPTCHA_CODE_LEN_MAX] = {"\0"};; + u_char code[CAPTCHA_CODE_LEN_MAX] = {"\0"}; + redisContext *conn = NULL; + + ret = get_user_captcha_code(req, input_code); // get captcha code passd via url + + if (ret != NGX_OK) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: if#1 captcha_auth_handler get_user_captcha_code fail" + ); + + goto auth_fail; + } + + //unique_id = get_unique_id(req); // cline browser info + ip + random key md5 hash + //todo change it + unique_id = malloc(31 * sizeof(unsigned char)); + strncpy(unique_id, user_crc_hash(req), 31); + + + + + + + get_captcha_cookie(req, captcha_id); + + + ngx_log_debug(NGX_LOG_DEBUG_HTTP, + req->connection->log, + 0, + "captcha: strcasecmp values unique_id[%s] captcha_id[%s]", + unique_id, captcha_id + ); + + + ngx_pfree(req->pool, unique_id);//free 6 + + conn = connectRedis(redis_conf->host, redis_conf->port, req->connection->log); + if (!conn) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: if#3 Conn! error captcha_auth_handler code is equal input_code[%s] redis_code[%s]", + input_code, code + ); + goto auth_fail; + } + + //get_and_check(conn, (char *) captcha_id, code, req->connection->log); + redisGet(conn, (char *) unique_id, code, req->connection->log); + closeRedisConnect(conn); + if (0 == ngx_strcmp(input_code, code)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: if#2 SUCCESS code is equal input_code[%s] redis_code[%s]", + input_code, code + ); + ngx_pfree(req->pool, unique_id);//free 6 + len = ngx_strlen(AUTH_SUCCESS); + auth_result = (u_char *) AUTH_SUCCESS; + goto output; + } + + + if (0 != ngx_strcasecmp(unique_id, captcha_id)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: if#2 captcha_auth_handler code is equal input_code[%s] redis_code[%s]", + input_code, code + ); + ngx_pfree(req->pool, unique_id);//free 6 + goto auth_fail; + } + +// ngx_pfree(req->pool, unique_id);//free 6 +// +// conn = connectRedis(redis_conf->host, redis_conf->port, req->connection->log); +// if (!conn) { +// ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, +// "captcha: if#3 captcha_auth_handler code is equal input_code[%s] redis_code[%s]", +// input_code, code +// ); +// goto auth_fail; +// } +// +// get_and_check(conn, (char *) captcha_id, code, req->connection->log); +// closeRedisConnect(conn); + + if (0 != ngx_strcasecmp(&input_code[0], code)) { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: if#4 captcha_auth_handler code is not equal input_code[%s] redis_code[%s]", + input_code, code + ); + + goto auth_fail; + } else { + ngx_log_debug(NGX_LOG_DEBUG_HTTP, req->connection->log, 0, + "captcha: if#5 captcha_auth_handler code is equal input_code[%s] redis_code[%s]", + input_code, code + ); + + len = ngx_strlen(AUTH_SUCCESS); + auth_result = (u_char *) AUTH_SUCCESS; + goto output; + } + + + auth_fail: + len = ngx_strlen(AUTH_FAIL); + auth_result = (u_char *) AUTH_FAIL; + goto output; + + output: + ngx_pfree(req->pool, captcha_conf);//free 5 + ngx_pfree(req->pool, redis_conf);//free 4 + + req->headers_out.status = 200; + req->headers_out.content_length_n = len; + ngx_str_set(&req->headers_out.content_type, "application/json"); + ngx_http_send_header(req); + + ngx_buf_t *b; + b = ngx_pcalloc(req->pool, sizeof(ngx_buf_t)); + ngx_chain_t out; + out.buf = b; + out.next = NULL; + b->pos = auth_result; + b->last = auth_result + len; + b->memory = 1; + b->last_buf = 1; + + return ngx_http_output_filter(req, &out); +} diff --git a/modules/ngx_http_header_inspect/README b/modules/ngx_http_header_inspect/README new file mode 100644 index 0000000..de9eff7 --- /dev/null +++ b/modules/ngx_http_header_inspect/README @@ -0,0 +1,63 @@ +Name + ngx_http_header_inspect - Inspect HTTP headers + +Synopsis + location /foo { + inspect_headers on; + inspect_headers_log_violations on; + inspect_headers_log_uninspected on; + inspect_headers_block_violations on; + + # only allow 3 range definitions in Range header + inspect_headers_range_max_byteranges 3; + } + +Limitations + Currently only inspects the following HTTP/1.1 headers: + Range, If-Range, If-Unmodified-Since, If-Modified-Since, Date, + Accept-Encoding, Accept-Language, Accept-Charset, Max-Forwards, + If-Match, If-None-Match, Last-Modified, Content-Length, + Expires, Content-Language, Content-Encoding, Allow, Host, + Accept, Connection, Content-Range, User-Agent, Upgrade, Via, + From, Pragma, Content-Type, Content-MD5, Authorization, Expect, + Proxy-Authorization, Warning, Trailer, Transfer-Encoding, TE, + Referer, Content-Location, Cache-Control + +Report Bugs + Create a ticket on the issue tracking interface of GitHub: + http://github.com/x-way/ngx_http_header_inspect/issues + +Source Repository + Available on GitHub: + http://github.com/x-way/ngx_http_header_inspect + +Author + Andreas Jaggi + +Copyright & License + Copyright (c) 2011 Andreas Jaggi + + This module is licensed under the terms of the BSD license. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 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/modules/ngx_http_header_inspect/config b/modules/ngx_http_header_inspect/config new file mode 100644 index 0000000..f9fee4a --- /dev/null +++ b/modules/ngx_http_header_inspect/config @@ -0,0 +1,12 @@ +ngx_addon_name=ngx_http_header_inspect + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=ngx_http_header_inspect_module + ngx_module_srcs="$ngx_addon_dir/ngx_http_header_inspect.c" + . auto/module +else + + HTTP_MODULES="$HTTP_MODULES ngx_http_header_inspect.c" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_http_header_inspect.c" +fi diff --git a/modules/ngx_http_header_inspect/ironaes.c b/modules/ngx_http_header_inspect/ironaes.c new file mode 100644 index 0000000..1f8cadb --- /dev/null +++ b/modules/ngx_http_header_inspect/ironaes.c @@ -0,0 +1,683 @@ +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +ECB-AES128 +---------- + + plain-text: + 6bc1bee22e409f96e93d7e117393172a + ae2d8a571e03ac9c9eb76fac45af8e51 + 30c81c46a35ce411e5fbc1191a0a52ef + f69f2445df4f9b17ad2b417be66c3710 + + key: + 2b7e151628aed2a6abf7158809cf4f3c + + resulting cipher + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 + + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For AES192/256 the key size is proportionally larger. + +*/ + + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include +#include // CBC mode, for memset +//#include "ironaes.h" + + + + + + +//~~~~~~~~~~~~~~~~~ + + +#include + +// #define the macros below to 1/0 to enable/disable the mode of operation. +// +// CBC enables AES encryption in CBC-mode of operation. +// CTR enables encryption in counter-mode. +// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. + +// The #ifndef-guard allows it to be configured before #include'ing or at compile time. +#ifndef CBC +#define CBC 1 +#endif + +#ifndef ECB +#define ECB 1 +#endif + +#ifndef CTR +#define CTR 1 +#endif + + +#define AES128 1 +//#define AES192 1 +//#define AES256 1 + +#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only + +#if defined(AES256) && (AES256 == 1) +#define AES_KEYLEN 32 + #define AES_keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) +#define AES_KEYLEN 24 + #define AES_keyExpSize 208 +#else +#define AES_KEYLEN 16 // Key length in bytes +#define AES_keyExpSize 176 +#endif + +struct AES_ctx +{ + uint8_t RoundKey[AES_keyExpSize]; +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + uint8_t Iv[AES_BLOCKLEN]; +#endif +}; + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); +#endif + +#if defined(ECB) && (ECB == 1) +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB +// NB: ECB is considered insecure for most uses +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + +#endif // #if defined(ECB) && (ECB == !) + + +#if defined(CBC) && (CBC == 1) +// buffer size MUST be mutile of AES_BLOCKLEN; +// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +// Same function for encrypting as for decrypting. +// IV is incremented for every block, and used after encryption as XOR-compliment for output +// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +#endif // #if defined(CTR) && (CTR == 1) + + + + + +//~~~~~~~~~~~~~~~~~ + + + + + + + + + + + + + +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +// The number of columns comprising a state in AES. This is a constant in AES. Value=4 +#define Nb 4 + +#if defined(AES256) && (AES256 == 1) +#define Nk 8 + #define Nr 14 +#elif defined(AES192) && (AES192 == 1) +#define Nk 6 + #define Nr 12 +#else +#define Nk 4 // The number of 32 bit words in a key. +#define Nr 10 // The number of rounds in AES Cipher. +#endif + +// jcallan@github points out that declaring Multiply as a function +// reduces code size considerably with the Keil ARM compiler. +// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 +#ifndef MULTIPLY_AS_A_FUNCTION +#define MULTIPLY_AS_A_FUNCTION 0 +#endif + + + + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +// state - array holding the intermediate results during decryption. +typedef uint8_t state_t[4][4]; + + + +// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM +// The numbers below can be computed dynamically trading ROM for RAM - +// This can be useful in (embedded) bootloader applications, where ROM is often limited. +static const uint8_t sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16 }; + +static const uint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d }; + +// The round constant word array, Rcon[i], contains the values given by +// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 }; + +/* + * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), + * that you can remove most of the elements in the Rcon array, because they are unused. + * + * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon + * + * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), + * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." + */ + + +/*****************************************************************************/ +/* Private functions: */ +/*****************************************************************************/ +/* +static uint8_t getSBoxValue(uint8_t num) +{ + return sbox[num]; +} +*/ +#define getSBoxValue(num) (sbox[(num)]) +/* +static uint8_t getSBoxInvert(uint8_t num) +{ + return rsbox[num]; +} +*/ +#define getSBoxInvert(num) (rsbox[(num)]) + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(uint8_t* RoundKey, const uint8_t* Key) +{ + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) + { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) + { + { + k = (i - 1) * 4; + tempa[0]=RoundKey[k + 0]; + tempa[1]=RoundKey[k + 1]; + tempa[2]=RoundKey[k + 2]; + tempa[3]=RoundKey[k + 3]; + + } + + if (i % Nk == 0) + { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i/Nk]; + } +#if defined(AES256) && (AES256 == 1) + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + j = i * 4; k=(i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key) +{ + KeyExpansion(ctx->RoundKey, key); +} +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv) +{ + KeyExpansion(ctx->RoundKey, key); + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv) +{ + memcpy (ctx->Iv, iv, AES_BLOCKLEN); +} +#endif + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(uint8_t round, state_t* state, const uint8_t* RoundKey) +{ + uint8_t i,j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static uint8_t xtime(uint8_t x) +{ + return ((x<<1) ^ (((x>>7) & 1) * 0x1b)); +} + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(state_t* state) +{ + uint8_t i; + uint8_t Tmp, Tm, t; + for (i = 0; i < 4; ++i) + { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3] ; + Tm = (*state)[i][0] ^ (*state)[i][1] ; Tm = xtime(Tm); (*state)[i][0] ^= Tm ^ Tmp ; + Tm = (*state)[i][1] ^ (*state)[i][2] ; Tm = xtime(Tm); (*state)[i][1] ^= Tm ^ Tmp ; + Tm = (*state)[i][2] ^ (*state)[i][3] ; Tm = xtime(Tm); (*state)[i][2] ^= Tm ^ Tmp ; + Tm = (*state)[i][3] ^ t ; Tm = xtime(Tm); (*state)[i][3] ^= Tm ^ Tmp ; + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary +// The compiler seems to be able to vectorize the operation better this way. +// See https://github.com/kokke/tiny-AES-c/pull/34 +#if MULTIPLY_AS_A_FUNCTION +static uint8_t Multiply(uint8_t x, uint8_t y) +{ + return (((y & 1) * x) ^ + ((y>>1 & 1) * xtime(x)) ^ + ((y>>2 & 1) * xtime(xtime(x))) ^ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ + } +#else +#define Multiply(x, y) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + +#endif + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(state_t* state) +{ + int i; + uint8_t a, b, c, d; + for (i = 0; i < 4; ++i) + { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(state_t* state) +{ + uint8_t i, j; + for (i = 0; i < 4; ++i) + { + for (j = 0; j < 4; ++j) + { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(state_t* state) +{ + uint8_t temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +// Cipher is the main function that encrypts the PlainText. +static void Cipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = 1; round < Nr; ++round) + { + SubBytes(state); + ShiftRows(state); + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + SubBytes(state); + ShiftRows(state); + AddRoundKey(Nr, state, RoundKey); +} + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) +static void InvCipher(state_t* state, const uint8_t* RoundKey) +{ + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = (Nr - 1); round > 0; --round) + { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + InvMixColumns(state); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(0, state, RoundKey); +} +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ +#if defined(ECB) && (ECB == 1) + + +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher((state_t*)buf, ctx->RoundKey); +} + +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf) +{ + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher((state_t*)buf, ctx->RoundKey); +} + + +#endif // #if defined(ECB) && (ECB == 1) + + + + + +#if defined(CBC) && (CBC == 1) + + +static void XorWithIv(uint8_t* buf, const uint8_t* Iv) +{ + uint8_t i; + for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } +} + +void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t* buf, uint32_t length) +{ + uintptr_t i; + uint8_t *Iv = ctx->Iv; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + XorWithIv(buf, Iv); + Cipher((state_t*)buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + //printf("Step %d - %d", i/16, i); + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) +{ + uintptr_t i; + uint8_t storeNextIv[AES_BLOCKLEN]; + for (i = 0; i < length; i += AES_BLOCKLEN) + { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher((state_t*)buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } + +} + +#endif // #if defined(CBC) && (CBC == 1) + + + +#if defined(CTR) && (CTR == 1) + +/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length) +{ + uint8_t buffer[AES_BLOCKLEN]; + + unsigned i; + int bi; + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) + { + if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); + Cipher((state_t*)buffer,ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) + { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) + { + ctx->Iv[bi] = 0; + continue; + } + ctx->Iv[bi] += 1; + break; + } + bi = 0; + } + + buf[i] = (buf[i] ^ buffer[bi]); + } +} + +#endif // #if defined(CTR) && (CTR == 1) + diff --git a/modules/ngx_http_header_inspect/ironaes.h b/modules/ngx_http_header_inspect/ironaes.h new file mode 100644 index 0000000..a863921 --- /dev/null +++ b/modules/ngx_http_header_inspect/ironaes.h @@ -0,0 +1,97 @@ +// +// Created by machin on 11/9/19. +// + +#ifndef NGINX_1_16_1_IRONAES_H +#define NGINX_1_16_1_IRONAES_H + + +#include + +// #define the macros below to 1/0 to enable/disable the mode of operation. +// +// CBC enables AES encryption in CBC-mode of operation. +// CTR enables encryption in counter-mode. +// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. + +// The #ifndef-guard allows it to be configured before #include'ing or at compile time. +#ifndef CBC +#define CBC 1 +#endif + +#ifndef ECB +#define ECB 1 +#endif + +#ifndef CTR +#define CTR 1 +#endif + + +#define AES128 1 +//#define AES192 1 +//#define AES256 1 + +#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only + +#if defined(AES256) && (AES256 == 1) +#define AES_KEYLEN 32 + #define AES_keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) +#define AES_KEYLEN 24 + #define AES_keyExpSize 208 +#else +#define AES_KEYLEN 16 // Key length in bytes +#define AES_keyExpSize 176 +#endif + +struct AES_ctx +{ + uint8_t RoundKey[AES_keyExpSize]; +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + uint8_t Iv[AES_BLOCKLEN]; +#endif +}; + +void AES_init_ctx(struct AES_ctx* ctx, const uint8_t* key); +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) +void AES_init_ctx_iv(struct AES_ctx* ctx, const uint8_t* key, const uint8_t* iv); +void AES_ctx_set_iv(struct AES_ctx* ctx, const uint8_t* iv); +#endif + +#if defined(ECB) && (ECB == 1) +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB +// NB: ECB is considered insecure for most uses +void AES_ECB_encrypt(const struct AES_ctx* ctx, uint8_t* buf); +void AES_ECB_decrypt(const struct AES_ctx* ctx, uint8_t* buf); + +#endif // #if defined(ECB) && (ECB == !) + + +#if defined(CBC) && (CBC == 1) +// buffer size MUST be mutile of AES_BLOCKLEN; +// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CBC_encrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); +void AES_CBC_decrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +// Same function for encrypting as for decrypting. +// IV is incremented for every block, and used after encryption as XOR-compliment for output +// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CTR_xcrypt_buffer(struct AES_ctx* ctx, uint8_t* buf, uint32_t length); + +#endif // #if defined(CTR) && (CTR == 1) + + + + +#endif //NGINX_1_16_1_IRONAES_H diff --git a/modules/ngx_http_header_inspect/ngx_http_header_inspect.c b/modules/ngx_http_header_inspect/ngx_http_header_inspect.c new file mode 100644 index 0000000..5c64524 --- /dev/null +++ b/modules/ngx_http_header_inspect/ngx_http_header_inspect.c @@ -0,0 +1,4780 @@ +/* + * ngx_http_header_inspect - Inspect HTTP headers + * + * Copyright (c) 2011, Andreas Jaggi + */ + + +/* + * IronFox header inspector + * Copyright (c) 2019, Khalegh Salehi +#include +#include +#include + +#define HASH_CODE_LEN_MAX 256 +#define SDK_VERSION "0.09.0" +#define MAGIC_LEN 4 +#define HEADER_KEY_LEN 48 +#define HEADER_VAL_LEN 64 +#define IRON_FOX_HEADER_NAME "ironfoxhash" + +#include +#include +//#include "ironaes.h" + + + + + + + +// all of AES here + +/* + +This is an implementation of the AES algorithm, specifically ECB, CTR and CBC mode. +Block size can be chosen in aes.h - available choices are AES128, AES192, AES256. + +The implementation is verified against the test vectors in: + National Institute of Standards and Technology Special Publication 800-38A 2001 ED + +ECB-AES128 +---------- + + plain-text: + 6bc1bee22e409f96e93d7e117393172a + ae2d8a571e03ac9c9eb76fac45af8e51 + 30c81c46a35ce411e5fbc1191a0a52ef + f69f2445df4f9b17ad2b417be66c3710 + + key: + 2b7e151628aed2a6abf7158809cf4f3c + + resulting cipher + 3ad77bb40d7a3660a89ecaf32466ef97 + f5d3d58503b9699de785895a96fdbaaf + 43b1cd7f598ece23881b00e3ed030688 + 7b0c785e27e8ad3f8223207104725dd4 + + +NOTE: String length must be evenly divisible by 16byte (str_len % 16 == 0) + You should pad the end of the string with zeros if this is not the case. + For AES192/256 the key size is proportionally larger. + +*/ + + +/*****************************************************************************/ +/* Includes: */ +/*****************************************************************************/ +#include +#include // CBC mode, for memset +//#include "ironaes.h" + + + + + + +//~~~~~~~~~~~~~~~~~ + + +#include + +// #define the macros below to 1/0 to enable/disable the mode of operation. +// +// CBC enables AES encryption in CBC-mode of operation. +// CTR enables encryption in counter-mode. +// ECB enables the basic ECB 16-byte block algorithm. All can be enabled simultaneously. + +// The #ifndef-guard allows it to be configured before #include'ing or at compile time. +#ifndef CBC +#define CBC 1 +#endif + +#ifndef ECB +#define ECB 1 +#endif + +#ifndef CTR +#define CTR 1 +#endif + + +#define AES128 1 +//#define AES192 1 +//#define AES256 1 + +#define AES_BLOCKLEN 16 //Block length in bytes AES is 128b block only + +#if defined(AES256) && (AES256 == 1) +#define AES_KEYLEN 32 +#define AES_keyExpSize 240 +#elif defined(AES192) && (AES192 == 1) +#define AES_KEYLEN 24 +#define AES_keyExpSize 208 +#else +#define AES_KEYLEN 16 // Key length in bytes +#define AES_keyExpSize 176 +#endif + +struct AES_ctx { + uint8_t RoundKey[AES_keyExpSize]; +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + uint8_t Iv[AES_BLOCKLEN]; +#endif +}; + +void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key); + +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + +void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv); + +void AES_ctx_set_iv(struct AES_ctx *ctx, const uint8_t *iv); + +#endif + +#if defined(ECB) && (ECB == 1) + +// buffer size is exactly AES_BLOCKLEN bytes; +// you need only AES_init_ctx as IV is not used in ECB +// NB: ECB is considered insecure for most uses +void AES_ECB_encrypt(const struct AES_ctx *ctx, uint8_t *buf); + +void AES_ECB_decrypt(const struct AES_ctx *ctx, uint8_t *buf); + +#endif // #if defined(ECB) && (ECB == !) + + +#if defined(CBC) && (CBC == 1) + +// buffer size MUST be mutile of AES_BLOCKLEN; +// Suggest https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx via AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length); + +void AES_CBC_decrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length); + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +// Same function for encrypting as for decrypting. +// IV is incremented for every block, and used after encryption as XOR-compliment for output +// Suggesting https://en.wikipedia.org/wiki/Padding_(cryptography)#PKCS7 for padding scheme +// NOTES: you need to set IV in ctx with AES_init_ctx_iv() or AES_ctx_set_iv() +// no IV should ever be reused with the same key +void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length); + +#endif // #if defined(CTR) && (CTR == 1) + + + + + +//~~~~~~~~~~~~~~~~~ + + + + + + + + + + + + + +/*****************************************************************************/ +/* Defines: */ +/*****************************************************************************/ +// The number of columns comprising a state in AES. This is a constant in AES. Value=4 +#define Nb 4 + +#if defined(AES256) && (AES256 == 1) +#define Nk 8 +#define Nr 14 +#elif defined(AES192) && (AES192 == 1) +#define Nk 6 +#define Nr 12 +#else +#define Nk 4 // The number of 32 bit words in a key. +#define Nr 10 // The number of rounds in AES Cipher. +#endif + +// jcallan@github points out that declaring Multiply as a function +// reduces code size considerably with the Keil ARM compiler. +// See this link for more information: https://github.com/kokke/tiny-AES-C/pull/3 +#ifndef MULTIPLY_AS_A_FUNCTION +#define MULTIPLY_AS_A_FUNCTION 0 +#endif + + + + +/*****************************************************************************/ +/* Private variables: */ +/*****************************************************************************/ +// state - array holding the intermediate results during decryption. +typedef uint8_t state_t[4][4]; + + +// The lookup-tables are marked const so they can be placed in read-only storage instead of RAM +// The numbers below can be computed dynamically trading ROM for RAM - +// This can be useful in (embedded) bootloader applications, where ROM is often limited. +static const uint8_t sbox[256] = { + //0 1 2 3 4 5 6 7 8 9 A B C D E F + 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76, + 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, + 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15, + 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75, + 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, + 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf, + 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8, + 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, + 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73, + 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb, + 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, + 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08, + 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a, + 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, + 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf, + 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16}; + +static const uint8_t rsbox[256] = { + 0x52, 0x09, 0x6a, 0xd5, 0x30, 0x36, 0xa5, 0x38, 0xbf, 0x40, 0xa3, 0x9e, 0x81, 0xf3, 0xd7, 0xfb, + 0x7c, 0xe3, 0x39, 0x82, 0x9b, 0x2f, 0xff, 0x87, 0x34, 0x8e, 0x43, 0x44, 0xc4, 0xde, 0xe9, 0xcb, + 0x54, 0x7b, 0x94, 0x32, 0xa6, 0xc2, 0x23, 0x3d, 0xee, 0x4c, 0x95, 0x0b, 0x42, 0xfa, 0xc3, 0x4e, + 0x08, 0x2e, 0xa1, 0x66, 0x28, 0xd9, 0x24, 0xb2, 0x76, 0x5b, 0xa2, 0x49, 0x6d, 0x8b, 0xd1, 0x25, + 0x72, 0xf8, 0xf6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xd4, 0xa4, 0x5c, 0xcc, 0x5d, 0x65, 0xb6, 0x92, + 0x6c, 0x70, 0x48, 0x50, 0xfd, 0xed, 0xb9, 0xda, 0x5e, 0x15, 0x46, 0x57, 0xa7, 0x8d, 0x9d, 0x84, + 0x90, 0xd8, 0xab, 0x00, 0x8c, 0xbc, 0xd3, 0x0a, 0xf7, 0xe4, 0x58, 0x05, 0xb8, 0xb3, 0x45, 0x06, + 0xd0, 0x2c, 0x1e, 0x8f, 0xca, 0x3f, 0x0f, 0x02, 0xc1, 0xaf, 0xbd, 0x03, 0x01, 0x13, 0x8a, 0x6b, + 0x3a, 0x91, 0x11, 0x41, 0x4f, 0x67, 0xdc, 0xea, 0x97, 0xf2, 0xcf, 0xce, 0xf0, 0xb4, 0xe6, 0x73, + 0x96, 0xac, 0x74, 0x22, 0xe7, 0xad, 0x35, 0x85, 0xe2, 0xf9, 0x37, 0xe8, 0x1c, 0x75, 0xdf, 0x6e, + 0x47, 0xf1, 0x1a, 0x71, 0x1d, 0x29, 0xc5, 0x89, 0x6f, 0xb7, 0x62, 0x0e, 0xaa, 0x18, 0xbe, 0x1b, + 0xfc, 0x56, 0x3e, 0x4b, 0xc6, 0xd2, 0x79, 0x20, 0x9a, 0xdb, 0xc0, 0xfe, 0x78, 0xcd, 0x5a, 0xf4, + 0x1f, 0xdd, 0xa8, 0x33, 0x88, 0x07, 0xc7, 0x31, 0xb1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xec, 0x5f, + 0x60, 0x51, 0x7f, 0xa9, 0x19, 0xb5, 0x4a, 0x0d, 0x2d, 0xe5, 0x7a, 0x9f, 0x93, 0xc9, 0x9c, 0xef, + 0xa0, 0xe0, 0x3b, 0x4d, 0xae, 0x2a, 0xf5, 0xb0, 0xc8, 0xeb, 0xbb, 0x3c, 0x83, 0x53, 0x99, 0x61, + 0x17, 0x2b, 0x04, 0x7e, 0xba, 0x77, 0xd6, 0x26, 0xe1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0c, 0x7d}; + +// The round constant word array, Rcon[i], contains the values given by +// x to the power (i-1) being powers of x (x is denoted as {02}) in the field GF(2^8) +static const uint8_t Rcon[11] = { + 0x8d, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36}; + +/* + * Jordan Goulder points out in PR #12 (https://github.com/kokke/tiny-AES-C/pull/12), + * that you can remove most of the elements in the Rcon array, because they are unused. + * + * From Wikipedia's article on the Rijndael key schedule @ https://en.wikipedia.org/wiki/Rijndael_key_schedule#Rcon + * + * "Only the first some of these constants are actually used – up to rcon[10] for AES-128 (as 11 round keys are needed), + * up to rcon[8] for AES-192, up to rcon[7] for AES-256. rcon[0] is not used in AES algorithm." + */ + + +/*****************************************************************************/ +/* Private functions: */ +/*****************************************************************************/ +/* +static uint8_t getSBoxValue(uint8_t num) +{ + return sbox[num]; +} +*/ +#define getSBoxValue(num) (sbox[(num)]) +/* +static uint8_t getSBoxInvert(uint8_t num) +{ + return rsbox[num]; +} +*/ +#define getSBoxInvert(num) (rsbox[(num)]) + +// This function produces Nb(Nr+1) round keys. The round keys are used in each round to decrypt the states. +static void KeyExpansion(uint8_t *RoundKey, const uint8_t *Key) { + unsigned i, j, k; + uint8_t tempa[4]; // Used for the column/row operations + + // The first round key is the key itself. + for (i = 0; i < Nk; ++i) { + RoundKey[(i * 4) + 0] = Key[(i * 4) + 0]; + RoundKey[(i * 4) + 1] = Key[(i * 4) + 1]; + RoundKey[(i * 4) + 2] = Key[(i * 4) + 2]; + RoundKey[(i * 4) + 3] = Key[(i * 4) + 3]; + } + + // All other round keys are found from the previous round keys. + for (i = Nk; i < Nb * (Nr + 1); ++i) { + { + k = (i - 1) * 4; + tempa[0] = RoundKey[k + 0]; + tempa[1] = RoundKey[k + 1]; + tempa[2] = RoundKey[k + 2]; + tempa[3] = RoundKey[k + 3]; + + } + + if (i % Nk == 0) { + // This function shifts the 4 bytes in a word to the left once. + // [a0,a1,a2,a3] becomes [a1,a2,a3,a0] + + // Function RotWord() + { + const uint8_t u8tmp = tempa[0]; + tempa[0] = tempa[1]; + tempa[1] = tempa[2]; + tempa[2] = tempa[3]; + tempa[3] = u8tmp; + } + + // SubWord() is a function that takes a four-byte input word and + // applies the S-box to each of the four bytes to produce an output word. + + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + + tempa[0] = tempa[0] ^ Rcon[i / Nk]; + } +#if defined(AES256) && (AES256 == 1) + if (i % Nk == 4) + { + // Function Subword() + { + tempa[0] = getSBoxValue(tempa[0]); + tempa[1] = getSBoxValue(tempa[1]); + tempa[2] = getSBoxValue(tempa[2]); + tempa[3] = getSBoxValue(tempa[3]); + } + } +#endif + j = i * 4; + k = (i - Nk) * 4; + RoundKey[j + 0] = RoundKey[k + 0] ^ tempa[0]; + RoundKey[j + 1] = RoundKey[k + 1] ^ tempa[1]; + RoundKey[j + 2] = RoundKey[k + 2] ^ tempa[2]; + RoundKey[j + 3] = RoundKey[k + 3] ^ tempa[3]; + } +} + +void AES_init_ctx(struct AES_ctx *ctx, const uint8_t *key) { + KeyExpansion(ctx->RoundKey, key); +} + +#if (defined(CBC) && (CBC == 1)) || (defined(CTR) && (CTR == 1)) + +void AES_init_ctx_iv(struct AES_ctx *ctx, const uint8_t *key, const uint8_t *iv) { + KeyExpansion(ctx->RoundKey, key); + memcpy(ctx->Iv, iv, AES_BLOCKLEN); +} + +void AES_ctx_set_iv(struct AES_ctx *ctx, const uint8_t *iv) { + memcpy(ctx->Iv, iv, AES_BLOCKLEN); +} + +#endif + +// This function adds the round key to state. +// The round key is added to the state by an XOR function. +static void AddRoundKey(uint8_t round, state_t *state, const uint8_t *RoundKey) { + uint8_t i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + (*state)[i][j] ^= RoundKey[(round * Nb * 4) + (i * Nb) + j]; + } + } +} + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void SubBytes(state_t *state) { + uint8_t i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + (*state)[j][i] = getSBoxValue((*state)[j][i]); + } + } +} + +// The ShiftRows() function shifts the rows in the state to the left. +// Each row is shifted with different offset. +// Offset = Row number. So the first row is not shifted. +static void ShiftRows(state_t *state) { + uint8_t temp; + + // Rotate first row 1 columns to left + temp = (*state)[0][1]; + (*state)[0][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[3][1]; + (*state)[3][1] = temp; + + // Rotate second row 2 columns to left + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to left + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[3][3]; + (*state)[3][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[1][3]; + (*state)[1][3] = temp; +} + +static uint8_t xtime(uint8_t x) { + return ((x << 1) ^ (((x >> 7) & 1) * 0x1b)); +} + +// MixColumns function mixes the columns of the state matrix +static void MixColumns(state_t *state) { + uint8_t i; + uint8_t Tmp, Tm, t; + for (i = 0; i < 4; ++i) { + t = (*state)[i][0]; + Tmp = (*state)[i][0] ^ (*state)[i][1] ^ (*state)[i][2] ^ (*state)[i][3]; + Tm = (*state)[i][0] ^ (*state)[i][1]; + Tm = xtime(Tm); + (*state)[i][0] ^= Tm ^ Tmp; + Tm = (*state)[i][1] ^ (*state)[i][2]; + Tm = xtime(Tm); + (*state)[i][1] ^= Tm ^ Tmp; + Tm = (*state)[i][2] ^ (*state)[i][3]; + Tm = xtime(Tm); + (*state)[i][2] ^= Tm ^ Tmp; + Tm = (*state)[i][3] ^ t; + Tm = xtime(Tm); + (*state)[i][3] ^= Tm ^ Tmp; + } +} + +// Multiply is used to multiply numbers in the field GF(2^8) +// Note: The last call to xtime() is unneeded, but often ends up generating a smaller binary +// The compiler seems to be able to vectorize the operation better this way. +// See https://github.com/kokke/tiny-AES-c/pull/34 +#if MULTIPLY_AS_A_FUNCTION +static uint8_t Multiply(uint8_t x, uint8_t y) +{ + return (((y & 1) * x) ^ + ((y>>1 & 1) * xtime(x)) ^ + ((y>>2 & 1) * xtime(xtime(x))) ^ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))); /* this last call to xtime() can be omitted */ + } +#else +#define Multiply(x, y) \ + ( ((y & 1) * x) ^ \ + ((y>>1 & 1) * xtime(x)) ^ \ + ((y>>2 & 1) * xtime(xtime(x))) ^ \ + ((y>>3 & 1) * xtime(xtime(xtime(x)))) ^ \ + ((y>>4 & 1) * xtime(xtime(xtime(xtime(x)))))) \ + +#endif + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +// MixColumns function mixes the columns of the state matrix. +// The method used to multiply may be difficult to understand for the inexperienced. +// Please use the references to gain more information. +static void InvMixColumns(state_t *state) { + int i; + uint8_t a, b, c, d; + for (i = 0; i < 4; ++i) { + a = (*state)[i][0]; + b = (*state)[i][1]; + c = (*state)[i][2]; + d = (*state)[i][3]; + + (*state)[i][0] = Multiply(a, 0x0e) ^ Multiply(b, 0x0b) ^ Multiply(c, 0x0d) ^ Multiply(d, 0x09); + (*state)[i][1] = Multiply(a, 0x09) ^ Multiply(b, 0x0e) ^ Multiply(c, 0x0b) ^ Multiply(d, 0x0d); + (*state)[i][2] = Multiply(a, 0x0d) ^ Multiply(b, 0x09) ^ Multiply(c, 0x0e) ^ Multiply(d, 0x0b); + (*state)[i][3] = Multiply(a, 0x0b) ^ Multiply(b, 0x0d) ^ Multiply(c, 0x09) ^ Multiply(d, 0x0e); + } +} + + +// The SubBytes Function Substitutes the values in the +// state matrix with values in an S-box. +static void InvSubBytes(state_t *state) { + uint8_t i, j; + for (i = 0; i < 4; ++i) { + for (j = 0; j < 4; ++j) { + (*state)[j][i] = getSBoxInvert((*state)[j][i]); + } + } +} + +static void InvShiftRows(state_t *state) { + uint8_t temp; + + // Rotate first row 1 columns to right + temp = (*state)[3][1]; + (*state)[3][1] = (*state)[2][1]; + (*state)[2][1] = (*state)[1][1]; + (*state)[1][1] = (*state)[0][1]; + (*state)[0][1] = temp; + + // Rotate second row 2 columns to right + temp = (*state)[0][2]; + (*state)[0][2] = (*state)[2][2]; + (*state)[2][2] = temp; + + temp = (*state)[1][2]; + (*state)[1][2] = (*state)[3][2]; + (*state)[3][2] = temp; + + // Rotate third row 3 columns to right + temp = (*state)[0][3]; + (*state)[0][3] = (*state)[1][3]; + (*state)[1][3] = (*state)[2][3]; + (*state)[2][3] = (*state)[3][3]; + (*state)[3][3] = temp; +} + +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +// Cipher is the main function that encrypts the PlainText. +static void Cipher(state_t *state, const uint8_t *RoundKey) { + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(0, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = 1; round < Nr; ++round) { + SubBytes(state); + ShiftRows(state); + MixColumns(state); + AddRoundKey(round, state, RoundKey); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + SubBytes(state); + ShiftRows(state); + AddRoundKey(Nr, state, RoundKey); +} + +#if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +static void InvCipher(state_t *state, const uint8_t *RoundKey) { + uint8_t round = 0; + + // Add the First round key to the state before starting the rounds. + AddRoundKey(Nr, state, RoundKey); + + // There will be Nr rounds. + // The first Nr-1 rounds are identical. + // These Nr-1 rounds are executed in the loop below. + for (round = (Nr - 1); round > 0; --round) { + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(round, state, RoundKey); + InvMixColumns(state); + } + + // The last round is given below. + // The MixColumns function is not here in the last round. + InvShiftRows(state); + InvSubBytes(state); + AddRoundKey(0, state, RoundKey); +} + +#endif // #if (defined(CBC) && CBC == 1) || (defined(ECB) && ECB == 1) + +/*****************************************************************************/ +/* Public functions: */ +/*****************************************************************************/ +#if defined(ECB) && (ECB == 1) + + +void AES_ECB_encrypt(const struct AES_ctx *ctx, uint8_t *buf) { + // The next function call encrypts the PlainText with the Key using AES algorithm. + Cipher((state_t *) buf, ctx->RoundKey); +} + +void AES_ECB_decrypt(const struct AES_ctx *ctx, uint8_t *buf) { + // The next function call decrypts the PlainText with the Key using AES algorithm. + InvCipher((state_t *) buf, ctx->RoundKey); +} + + +#endif // #if defined(ECB) && (ECB == 1) + + +#if defined(CBC) && (CBC == 1) + + +static void XorWithIv(uint8_t *buf, const uint8_t *Iv) { + uint8_t i; + for (i = 0; i < AES_BLOCKLEN; ++i) // The block in AES is always 128bit no matter the key size + { + buf[i] ^= Iv[i]; + } +} + +void AES_CBC_encrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length) { + uintptr_t i; + uint8_t *Iv = ctx->Iv; + for (i = 0; i < length; i += AES_BLOCKLEN) { + XorWithIv(buf, Iv); + Cipher((state_t *) buf, ctx->RoundKey); + Iv = buf; + buf += AES_BLOCKLEN; + //printf("Step %d - %d", i/16, i); + } + /* store Iv in ctx for next call */ + memcpy(ctx->Iv, Iv, AES_BLOCKLEN); +} + +void AES_CBC_decrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length) { + uintptr_t i; + uint8_t storeNextIv[AES_BLOCKLEN]; + for (i = 0; i < length; i += AES_BLOCKLEN) { + memcpy(storeNextIv, buf, AES_BLOCKLEN); + InvCipher((state_t *) buf, ctx->RoundKey); + XorWithIv(buf, ctx->Iv); + memcpy(ctx->Iv, storeNextIv, AES_BLOCKLEN); + buf += AES_BLOCKLEN; + } + +} + +#endif // #if defined(CBC) && (CBC == 1) + + +#if defined(CTR) && (CTR == 1) + +/* Symmetrical operation: same function for encrypting as for decrypting. Note any IV/nonce should never be reused with the same key */ +void AES_CTR_xcrypt_buffer(struct AES_ctx *ctx, uint8_t *buf, uint32_t length) { + uint8_t buffer[AES_BLOCKLEN]; + + unsigned i; + int bi; + for (i = 0, bi = AES_BLOCKLEN; i < length; ++i, ++bi) { + if (bi == AES_BLOCKLEN) /* we need to regen xor compliment in buffer */ + { + + memcpy(buffer, ctx->Iv, AES_BLOCKLEN); + Cipher((state_t *) buffer, ctx->RoundKey); + + /* Increment Iv and handle overflow */ + for (bi = (AES_BLOCKLEN - 1); bi >= 0; --bi) { + /* inc will overflow */ + if (ctx->Iv[bi] == 255) { + ctx->Iv[bi] = 0; + continue; + } + ctx->Iv[bi] += 1; + break; + } + bi = 0; + } + + buf[i] = (buf[i] ^ buffer[bi]); + } +} + +#endif // #if defined(CTR) && (CTR == 1) + + + + + + + +// end of AES +//todo refactor AES, + + + + + + + + + + + +static ngx_int_t +get_and_check(redisContext *con, char *key, char *value, ngx_log_t *log); + + +typedef struct { + ngx_flag_t inspect; + ngx_flag_t log; + ngx_flag_t log_uninspected; + ngx_flag_t block; + + ngx_uint_t range_max_byteranges; +} ngx_header_inspect_loc_conf_t; + + +static ngx_int_t ngx_header_inspect_init(ngx_conf_t *cf); + +static ngx_int_t ngx_header_inspect_http_date(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len); + +static ngx_int_t +ngx_header_inspect_parse_base64(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, u_char *data, + ngx_uint_t maxlen); + +static ngx_int_t ngx_header_inspect_parse_entity_tag(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len); + +static ngx_int_t ngx_header_inspect_parse_languagerange(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len); + +static ngx_int_t ngx_header_inspect_range_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_acceptencoding_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_contentencoding_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_acceptlanguage_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_contentlanguage_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_acceptcharset_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_digit_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_ifmatch_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_allow_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_host_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_accept_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_conection_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_contentrange_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_useragent_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_upgrade_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_via_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_from_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_ifrange_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_pragma_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_contenttype_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_date_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, char *header, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_contentmd5_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_authorization_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, + ngx_str_t value); + +static ngx_int_t ngx_header_inspect_expect_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_warning_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_trailer_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_transferencoding_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, + ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_referer_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t +ngx_header_inspect_cachecontrol_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value); + +static ngx_int_t ngx_header_inspect_process_request(ngx_http_request_t *r); + +static void *ngx_header_inspect_create_conf(ngx_conf_t *cf); + +static char *ngx_header_inspect_merge_conf(ngx_conf_t *cf, void *parent, void *child); + + +static ngx_command_t ngx_header_inspect_commands[] = { + { + ngx_string("inspect_headers"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_header_inspect_loc_conf_t, inspect), + NULL + }, + { + ngx_string("inspect_headers_log_violations"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_header_inspect_loc_conf_t, log), + NULL + }, + { + ngx_string("inspect_headers_block_violations"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_header_inspect_loc_conf_t, block), + NULL + }, + { + ngx_string("inspect_headers_log_uninspected"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_header_inspect_loc_conf_t, log_uninspected), + NULL + }, + { + ngx_string("inspect_headers_range_max_byteranges"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_header_inspect_loc_conf_t, range_max_byteranges), + NULL + }, + ngx_null_command +}; + +static ngx_http_module_t ngx_header_inspect_module_ctx = { + NULL, /* preconfiguration */ + ngx_header_inspect_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_header_inspect_create_conf, /* create location configuration */ + ngx_header_inspect_merge_conf, /* merge location configuration */ +}; + +ngx_module_t ngx_http_header_inspect_module = { + NGX_MODULE_V1, + &ngx_header_inspect_module_ctx, /* module context */ + ngx_header_inspect_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t ngx_header_inspect_init(ngx_conf_t *cf) { + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_header_inspect_process_request; + + return NGX_OK; +} + +static ngx_int_t ngx_header_inspect_range_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i, a, b, setcount; + ngx_int_t rc = NGX_OK; + enum range_header_states { + RHS_NEWSET, RHS_NUM1, DELIM, RHS_NUM2, RHS_SUFDELIM, RHS_SUFNUM + } state; + + if ((value.len < 6) || (ngx_strncmp("bytes=", value.data, 6) != 0)) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Range header does not start with \"bytes=\""); + } + rc = NGX_ERROR; + } + + setcount = 1; + a = 0; + b = 0; + state = RHS_NEWSET; + + i = 6; /* start after bytes= */ + for (; i < value.len; i++) { + + switch (value.data[i]) { + case ',': + if ((state != DELIM) && (state != RHS_NUM2) && (state != RHS_SUFNUM)) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected ',' at position %d in Range header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + } + if (state == RHS_NUM2) { + /* verify a <= b in 'a-b' sets */ + if (a > b) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid range definition at position %d in Range header \"%s\"", + i, value.data); + } + rc = NGX_ERROR; + } + } + setcount++; + a = 0; + b = 0; + state = RHS_NEWSET; + break; + + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if ((state == RHS_NEWSET) || (state == RHS_NUM1)) { + a = a * 10 + (value.data[i] - '0'); + state = RHS_NUM1; + } else if ((state == DELIM) || (state == RHS_NUM2)) { + b = b * 10 + (value.data[i] - '0'); + state = RHS_NUM2; + } else if ((state == RHS_SUFDELIM) || (state == RHS_SUFNUM)) { + state = RHS_SUFNUM; + } else { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected digit at position %d in Range header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + } + break; + + case '-': + if (state == RHS_NEWSET) { + state = RHS_SUFDELIM; + } else if (state == RHS_NUM1) { + state = DELIM; + } else { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected '-' at position %d in Range header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + } + break; + + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Range header \"%s\"", i, value.data); + } + rc = NGX_ERROR; + } + + if (setcount > conf->range_max_byteranges) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Range header contains more than %d byteranges", + conf->range_max_byteranges); + } + return NGX_ERROR; + break; + } + } + + if ((state != DELIM) && (state != RHS_NUM2) && (state != RHS_SUFNUM)) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: Range header \"%s\" contains incomplete byteset definition", value.data); + } + rc = NGX_ERROR; + } + if (state == RHS_NUM2) { + /* verify a <= b in 'a-b' sets */ + if (a > b) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid range definition at position %d in Range header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + } + } + + return rc; +} + +static ngx_int_t ngx_header_inspect_http_date(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + ngx_uint_t i = 0; + enum http_date_type { + RFC1123, RFC850, ASCTIME + } type; + + if (maxlen < 24) { + *len = i; + return NGX_ERROR; + } + + if ((data[0] == 'M') && (data[1] == 'o') && (data[2] == 'n')) { + /* Mon(day) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 'd': + type = RFC850; + if ( + (data[4] != 'a') || + (data[5] != 'y') || + (data[6] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 7; + break; + default: + *len = i; + return NGX_ERROR; + } + } else if ((data[0] == 'T') && (data[1] == 'u') && (data[2] == 'e')) { + /* Tue(sday) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 's': + type = RFC850; + if ( + (data[4] != 'd') || + (data[5] != 'a') || + (data[6] != 'y') || + (data[7] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 8; + break; + default: + *len = i; + return NGX_ERROR; + } + } else if ((data[0] == 'W') && (data[1] == 'e') && (data[2] == 'd')) { + /* Wed(nesday) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 'n': + type = RFC850; + if ( + (data[4] != 'e') || + (data[5] != 's') || + (data[6] != 'd') || + (data[7] != 'a') || + (data[8] != 'y') || + (data[9] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 10; + break; + default: + *len = i; + return NGX_ERROR; + } + } else if ((data[0] == 'T') && (data[1] == 'h') && (data[2] == 'u')) { + /* Thu(rsday) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 'r': + type = RFC850; + if ( + (data[4] != 's') || + (data[5] != 'd') || + (data[6] != 'a') || + (data[7] != 'y') || + (data[8] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 9; + break; + default: + *len = i; + return NGX_ERROR; + } + } else if ((data[0] == 'F') && (data[1] == 'r') && (data[2] == 'i')) { + /* Fri(day) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 'd': + type = RFC850; + if ( + (data[4] != 'a') || + (data[5] != 'y') || + (data[6] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 7; + break; + default: + *len = i; + return NGX_ERROR; + } + } else if ((data[0] == 'S') && (data[1] == 'a') && (data[2] == 't')) { + /* Sat(urday) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 'u': + type = RFC850; + if ( + (data[4] != 'r') || + (data[5] != 'd') || + (data[6] != 'a') || + (data[7] != 'y') || + (data[8] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 9; + break; + default: + *len = i; + return NGX_ERROR; + } + } else if ((data[0] == 'S') && (data[1] == 'u') && (data[2] == 'n')) { + /* Sun(day) */ + switch (data[3]) { + case ',': + type = RFC1123; + i = 4; + break; + case ' ': + type = ASCTIME; + i = 3; + break; + case 'd': + type = RFC850; + if ( + (data[4] != 'a') || + (data[5] != 'y') || + (data[6] != ',') + ) { + *len = i; + return NGX_ERROR; + } + i = 7; + break; + default: + *len = i; + return NGX_ERROR; + } + } else { + *len = i; + return NGX_ERROR; + } + + switch (type) { + case RFC1123: + if (maxlen < 29) { + *len = i; + return NGX_ERROR; + } + break; + case RFC850: + if (maxlen < 30) { + *len = i; + return NGX_ERROR; + } + break; + case ASCTIME: + if (maxlen < 24) { + *len = i; + return NGX_ERROR; + } + break; + default: + *len = i; + return NGX_ERROR; + } + + if (data[i] != ' ') { + *len = i; + return NGX_ERROR; + } + i++; + + if (type == RFC1123) { + /* rfc1123: day */ + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if (data[i] != ' ') { + *len = i; + return NGX_ERROR; + } + i++; + } else if (type == RFC850) { + /* rfc850: day */ + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if (data[i] != '-') { + *len = i; + return NGX_ERROR; + } + i++; + } + + /* month: Nov */ + if ( + ((data[i] == 'J') && (data[i + 1] == 'a') && (data[i + 2] == 'n')) || + ((data[i] == 'F') && (data[i + 1] == 'e') && (data[i + 2] == 'b')) || + ((data[i] == 'M') && (data[i + 1] == 'a') && (data[i + 2] == 'r')) || + ((data[i] == 'A') && (data[i + 1] == 'p') && (data[i + 2] == 'r')) || + ((data[i] == 'M') && (data[i + 1] == 'a') && (data[i + 2] == 'y')) || + ((data[i] == 'J') && (data[i + 1] == 'u') && (data[i + 2] == 'n')) || + ((data[i] == 'J') && (data[i + 1] == 'u') && (data[i + 2] == 'l')) || + ((data[i] == 'A') && (data[i + 1] == 'u') && (data[i + 2] == 'g')) || + ((data[i] == 'S') && (data[i + 1] == 'e') && (data[i + 2] == 'p')) || + ((data[i] == 'O') && (data[i + 1] == 'c') && (data[i + 2] == 't')) || + ((data[i] == 'N') && (data[i + 1] == 'o') && (data[i + 2] == 'v')) || + ((data[i] == 'D') && (data[i + 1] == 'e') && (data[i + 2] == 'c')) + ) { + i += 3; + } else { + *len = i; + return NGX_ERROR; + } + + if (type == RFC1123) { + /* rfc1123: year */ + if (data[i] != ' ') { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + } else if (type == RFC850) { + /* rfc850: year */ + if (data[i] != '-') { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + } else if (type == ASCTIME) { + /* asctime: day */ + if (data[i] != ' ') { + *len = i; + return NGX_ERROR; + } + i++; + if ((data[i] != ' ') || (data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + } + if ((data[i] < '0') || (data[i] > '9')) { + *len = i; + return NGX_ERROR; + } + i++; + if (data[i] != ' ') { + *len = i; + return NGX_ERROR; + } + i++; + + /* time 08:49:37 */ + if ( + (data[i] < '0') || (data[i] > '9') || + (data[i + 1] < '0') || (data[i + 1] > '9') || + (data[i + 2] != ':') + ) { + *len = i; + return NGX_ERROR; + } + i += 3; + if ( + (data[i] < '0') || (data[i] > '9') || + (data[i + 1] < '0') || (data[i + 1] > '9') || + (data[i + 2] != ':') + ) { + *len = i; + return NGX_ERROR; + } + i += 3; + if ( + (data[i] < '0') || (data[i] > '9') || + (data[i + 1] < '0') || (data[i + 1] > '9') || + (data[i + 2] != ' ') + ) { + *len = i; + return NGX_ERROR; + } + i += 3; + + if (type == ASCTIME) { + /* asctime: year: 1994 */ + if ( + (data[i] < '0') || (data[i] > '9') || + (data[i + 1] < '0') || (data[i + 1] > '9') || + (data[i + 2] < '0') || (data[i + 2] > '9') || + (data[i + 3] < '0') || (data[i + 3] > '9') + ) { + *len = i; + return NGX_ERROR; + } + i += 4; + } else { + /* GMT */ + if ((data[i] != 'G') || (data[i + 1] != 'M') || (data[i + 2] != 'T')) { + *len = i; + return NGX_ERROR; + } + i += 3; + } + + *len = i; + return NGX_OK; +} + +static ngx_int_t ngx_header_inspect_parse_entity_tag(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + ngx_uint_t i = 0; + + if (maxlen < 2) { + *len = 0; + return NGX_ERROR; + } + + if (data[0] == 'W') { + if (data[1] != '/') { + *len = 2; + return NGX_ERROR; + } + i = 2; + } + + if (i + 1 >= maxlen) { + *len = i; + return NGX_ERROR; + } + + if (data[i] != '"') { + *len = i + 1; + return NGX_ERROR; + } + i++; + + for (; i < maxlen - 1; i++) { + if (data[i] == '"') { + *len = i + 1; + return NGX_OK; + } + } + + *len = maxlen; + return NGX_ERROR; +} + +static ngx_int_t ngx_header_inspect_parse_qvalue(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + + *len = 0; + + if ((maxlen < 3) || (data[0] != 'q') || (data[1] != '=')) { + return NGX_ERROR; + } + + if (data[2] == '0') { + if ((maxlen == 3) || (data[3] != '.')) { + *len = 3; + return NGX_OK; + } + if ((data[4] < '0') || (data[4] > '9')) { + *len = 4; + return NGX_OK; + } + if ((data[5] < '0') || (data[5] > '9')) { + *len = 5; + return NGX_OK; + } + if ((data[6] < '0') || (data[6] > '9')) { + *len = 6; + } else { + *len = 7; + } + return NGX_OK; + } else if (data[2] == '1') { + if ((maxlen == 3) || (data[3] != '.')) { + *len = 3; + return NGX_OK; + } + if (data[4] != '0') { + *len = 4; + return NGX_OK; + } + if (data[5] != '0') { + *len = 5; + return NGX_OK; + } + if (data[6] != '0') { + *len = 6; + } else { + *len = 7; + } + return NGX_OK; + } else { + *len = 2; + return NGX_ERROR; + } +} + +static ngx_int_t ngx_header_inspect_parse_contentcoding(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + + if (maxlen < 1) { + *len = 0; + return NGX_ERROR; + } + *len = 1; + + switch (data[0]) { + case '*': + return NGX_OK; + break; + case 'c': + if ((maxlen < 8) || (ngx_strncmp("compress", data, 8) != 0)) { + return NGX_ERROR; + } + *len = 8; + break; + case 'd': + if ((maxlen < 7) || (ngx_strncmp("deflate", data, 7) != 0)) { + return NGX_ERROR; + } + *len = 7; + break; + case 'e': + if ((maxlen < 3) || (ngx_strncmp("exi", data, 3) != 0)) { + return NGX_ERROR; + } + *len = 3; + break; + case 'g': + if ((maxlen < 4) || (ngx_strncmp("gzip", data, 4) != 0)) { + return NGX_ERROR; + } + *len = 4; + break; + case 'i': + if ((maxlen < 8) || (ngx_strncmp("identity", data, 8) != 0)) { + return NGX_ERROR; + } + *len = 8; + break; + case 'p': + if ((maxlen < 12) || (ngx_strncmp("pack200-gzip", data, 12) != 0)) { + return NGX_ERROR; + } + *len = 12; + break; + default: + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t ngx_header_inspect_parse_mediatype(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + ngx_uint_t i = 0; + u_char d; + ngx_uint_t secondpart = 0; + ngx_uint_t parameter = 0; + + if (maxlen < 1) { + *len = 0; + return NGX_ERROR; + } + + *len = 1; + while (i < maxlen) { + d = data[i]; + if (d == '/') { + if (i < 1) { + *len = 1; + return NGX_ERROR; + } else { + if (secondpart == 0) { + secondpart = 1; + i++; + continue; + } else { + *len = i; + return NGX_ERROR; + } + } + } + + if ( + ((d < '0') || (d > '9')) && + ((d < 'a') || (d > 'z')) && + ((d < 'A') || (d > 'Z')) && + (d != '-') && (d != '_') && + (d != '+') && (d != '.') && + (d != ':') && (d != '*') + /* TODO: check with RFC which chars are valid */ + ) { + *len = i; + if (secondpart == 0) { + return NGX_ERROR; + } else { + if (d == ';') { + parameter = 1; + break; + } else { + return NGX_OK; + } + } + } + i++; + } + + if (parameter) { + if (i + 4 > maxlen) { + return NGX_ERROR; + } + while (i < maxlen) { + if (data[i] != ';') { + *len = i; + return NGX_OK; + } + i++; + + while ((i < maxlen) && (data[i] == ' ')) { i++; } + if (i == maxlen) { + *len = i; + return NGX_ERROR; + } + + /* attribute */ + while (i < maxlen) { + d = data[i]; + + if (d == '=') { + break; + } + + if ( + ((d < '0') || (d > '9')) && + ((d < 'a') || (d > 'z')) && + ((d < 'A') || (d > 'Z')) && + (d != '-') && (d != '_') && + (d != '+') && (d != '.') && + (d != ':') && (d != '*') + ) { + *len = i; + return NGX_ERROR; + } + i++; + } + if (i == maxlen) { + *len = i; + return NGX_ERROR; + } + i++; + + /* value */ + /* TODO: what if value is double-quoted? */ + while (i < maxlen) { + d = data[i]; + + if (d == ';') { + break; + } + + if ( + ((d < '0') || (d > '9')) && + ((d < 'a') || (d > 'z')) && + ((d < 'A') || (d > 'Z')) && + (d != '-') && (d != '_') && + (d != '+') && (d != '.') && + (d != ':') && (d != '*') + ) { + *len = i; + return NGX_OK; + } + i++; + } + while ((i < maxlen) && (data[i] == ' ')) { i++; } + } + } + + *len = i; + if (secondpart == 0) { + return NGX_ERROR; + } else { + return NGX_OK; + } +} + +static ngx_int_t ngx_header_inspect_parse_charset(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + ngx_uint_t i; + u_char d; + ngx_uint_t alphacount = 0; + + if (maxlen < 1) { + *len = 0; + return NGX_ERROR; + } + + if (data[0] == '*') { + *len = 1; + return NGX_OK; + } + + *len = 1; + for (i = 0; i < maxlen; i++) { + d = data[i]; + if ( + (d == '-') || + (d == '_') || + (d == '+') || + (d == '.') || + (d == ':') + ) { + if (alphacount == 0) { + *len = i; + return NGX_ERROR; + } + alphacount = 0; + continue; + } + if ( + ((d < '0') || (d > '9')) && + ((d < 'a') || (d > 'z')) && + ((d < 'A') || (d > 'Z')) + ) { + *len = i; + if (alphacount == 0) { + return NGX_ERROR; + } else { + return NGX_OK; + } + } + alphacount++; + } + + *len = i; + if (alphacount == 0) { + return NGX_ERROR; + } else { + return NGX_OK; + } +} + +static ngx_int_t ngx_header_inspect_parse_languagerange(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + ngx_uint_t i; + u_char d; + ngx_uint_t alphacount = 0; + + if (maxlen < 1) { + *len = 0; + return NGX_ERROR; + } + + if (data[0] == '*') { + *len = 1; + return NGX_OK; + } + + *len = 1; + for (i = 0; i < maxlen; i++) { + d = data[i]; + if (d == '-') { + if (alphacount == 0) { + *len = i; + return NGX_ERROR; + } + alphacount = 0; + continue; + } + if ( + ((d < 'a') || (d > 'z')) && + ((d < 'A') || (d > 'Z')) + ) { + *len = i; + if (alphacount == 0) { + return NGX_ERROR; + } else { + return NGX_OK; + } + } + if (alphacount == 8) { + *len = i; + return NGX_ERROR; + } + alphacount++; + } + + *len = i; + if (alphacount == 0) { + return NGX_ERROR; + } else { + return NGX_OK; + } +} + +static ngx_int_t +ngx_header_inspect_ifmatch_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ((value.len == 1) && (value.data[0] == '*')) { + return NGX_OK; + } + + if (value.len < 2) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: %s header \"%s\" too short", header, value.data); + } + return NGX_ERROR; + } + + while (i < value.len) { + if (ngx_header_inspect_parse_entity_tag(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid entity-tag at position %d in %s header \"%s\"", i, header, + value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: illegal char at position %d in %s header \"%s\"", + i, header, value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of %s header \"%s\"", header, + value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t +ngx_header_inspect_digit_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + + if (value.len <= 0) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: %s header \"%s\" is empty", header, value.data); + } + return NGX_ERROR; + } + + for (i = 0; i < value.len; i++) { + if ((value.data[i] < '0') || (value.data[i] > '9')) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid digit at position %d in %s header \"%s\"", + i, header, value.data); + } + return NGX_ERROR; + } + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_acceptcharset_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ((value.len == 0) || ((value.len == 1) && (value.data[0] == '*'))) { + return NGX_OK; + } + + while (i < value.len) { + if (ngx_header_inspect_parse_charset(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid charset at position %d in Accept-Charset header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] == ';') { + i++; + if (i >= value.len) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected end of Accept-Charset header \"%s\"", value.data); + } + rc = NGX_ERROR; + break; + } + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (ngx_header_inspect_parse_qvalue(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid qvalue at position %d in Accept-Charset header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Accept-Charset header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Accept-Charset header \"%s\"", + value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t +ngx_header_inspect_contentlanguage_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ((value.len == 0) || ((value.len == 1) && (value.data[0] == '*'))) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Content-Language header \"%s\" too short", + value.data); + } + return NGX_ERROR; + } + + while (i < value.len) { + if (value.data[i] == '*') { + /* hack, to prevent parse_languagerange from matching '*' */ + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Content-Language header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + if (ngx_header_inspect_parse_languagerange(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid language-range at position %d in Content-Language header \"%s\"", + i, value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Content-Language header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Content-Language header \"%s\"", + value.data); + } + rc = NGX_ERROR; + } + + return rc; + +} + +static ngx_int_t +ngx_header_inspect_acceptlanguage_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ((value.len == 0) || ((value.len == 1) && (value.data[0] == '*'))) { + return NGX_OK; + } + + while (i < value.len) { + if (ngx_header_inspect_parse_languagerange(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid language-range at position %d in Accept-Language header \"%s\"", + i, value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] == ';') { + i++; + if (i >= value.len) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected end of Accept-Language header \"%s\"", value.data); + } + rc = NGX_ERROR; + break; + } + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (ngx_header_inspect_parse_qvalue(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid qvalue at position %d in Accept-Language header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Accept-Language header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Accept-Language header \"%s\"", + value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t +ngx_header_inspect_contentencoding_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ((value.len == 0) || ((value.len == 1) && (value.data[0] == '*'))) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Content-Encoding header \"%s\" too short", + value.data); + } + return NGX_ERROR; + } + + while (i < value.len) { + if (value.data[i] == '*') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Content-Encoding header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + if (ngx_header_inspect_parse_contentcoding(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid content-coding at position %d in Content-Encoding header \"%s\"", + i, value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Content-Encoding header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Content-Encoding header \"%s\"", + value.data); + } + rc = NGX_ERROR; + } + + return rc; + +} + +static ngx_int_t +ngx_header_inspect_acceptencoding_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if ((value.len == 0) || ((value.len == 1) && (value.data[0] == '*'))) { + return NGX_OK; + } + + while (i < value.len) { + if (ngx_header_inspect_parse_contentcoding(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid content-coding at position %d in Accept-Encoding header \"%s\"", + i, value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] == ';') { + i++; + if (i >= value.len) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected end of Accept-Encoding header \"%s\"", value.data); + } + rc = NGX_ERROR; + break; + } + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (ngx_header_inspect_parse_qvalue(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid qvalue at position %d in Accept-Encoding header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Accept-Encoding header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Accept-Encoding header \"%s\"", + value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t ngx_header_inspect_parse_cache_directive(u_char *data, ngx_uint_t maxlen, ngx_uint_t *len) { + ngx_uint_t i = 0; + if ((maxlen >= 8) && (ngx_strncmp("no-cache", data, 8) == 0)) { + *len = 8; + return NGX_OK; + } + if ((maxlen >= 8) && (ngx_strncmp("no-store", data, 8) == 0)) { + *len = 8; + return NGX_OK; + } + if ((maxlen >= 12) && (ngx_strncmp("no-transform", data, 12) == 0)) { + *len = 12; + return NGX_OK; + } + if ((maxlen >= 14) && (ngx_strncmp("only-if-cached", data, 14) == 0)) { + *len = 14; + return NGX_OK; + } + if ((maxlen >= 9) && (ngx_strncmp("max-stale", data, 9) == 0)) { + *len = 9; + if (maxlen >= 11) { + if ((data[9] == '=') && (data[10] >= '0') && (data[10] <= '9')) { + i = 11; + while ((i <= maxlen) && (data[i] >= '0') && (data[i] <= '9')) { + i++; + } + *len = i; + } + } + return NGX_OK; + } + if ((maxlen >= 9) && (ngx_strncmp("max-age=", data, 8) == 0) && (data[8] >= '0') && (data[8] <= '9')) { + i = 9; + while ((i < maxlen) && (data[i] >= '0') && (data[i] <= '9')) { + i++; + } + *len = i; + return NGX_OK; + } + if ((maxlen >= 11) && (ngx_strncmp("min-fresh=", data, 10) == 0) && (data[10] >= '0') && (data[10] <= '9')) { + i = 11; + while ((i < maxlen) && (data[i] >= '0') && (data[i] <= '9')) { + i++; + } + *len = i; + return NGX_OK; + } + + return NGX_ERROR; +} + +static ngx_int_t +ngx_header_inspect_cachecontrol_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if (value.len < 1) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Cache-Control header \"%s\" too short", value.data); + } + return NGX_ERROR; + } + + while (i < value.len) { + if (ngx_header_inspect_parse_cache_directive(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid cache-directive at position %d in Cache-Control header \"%s\"", + i, value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Cache-Control header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Cache-Control header \"%s\"", + value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t +ngx_header_inspect_referer_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + enum referer_header_states { + RS_START, + RS_SCHEME, + RS_COLON, + RS_SLASH1, + RS_SLASH2, + RS_HOST, + RS_BR1, + RS_IP6, + RS_BR2, + RS_COLON2, + RS_PORT, + RS_PATH + } state; + ngx_uint_t i; + ngx_int_t rc = NGX_OK; + u_char d; + + if (value.len < 1) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: %s header \"%s\" too short", header, value.data); + } + return NGX_ERROR; + } + + switch (value.data[0]) { + case '/': + /* relativePath */ + return NGX_OK; + break; + case 'h': + case 'f': + /* absoluteURI */ + state = RS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + + if ( + ((d >= 'g') && (d <= 'z')) || + ((d >= 'G') && (d <= 'Z')) || + (d == '.') + ) { + switch (state) { + case RS_START: + if ( + !( + ((value.len > 4) && (ngx_strncmp("http:", value.data, 5) == 0)) || + ((value.len > 5) && (ngx_strncmp("https:", value.data, 6) == 0)) || + ((value.len > 3) && (ngx_strncmp("ftp:", value.data, 4) == 0)) || + ((value.len > 4) && (ngx_strncmp("ftps:", value.data, 5) == 0)) + ) + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unknown scheme at begin of %s header \"%s\"", header, + value.data); + } + return NGX_ERROR; + } + state = RS_SCHEME; + break; + case RS_SLASH2: + state = RS_HOST; + break; + case RS_HOST: + case RS_PATH: + case RS_SCHEME: + break; + default: + rc = NGX_ERROR; + } + } else if ( + ((d >= 'a') && (d <= 'f')) || + ((d >= 'A') && (d <= 'F')) + ) { + switch (state) { + case RS_START: + if ( + !( + ((value.len > 4) && (ngx_strncmp("http:", value.data, 5) == 0)) || + ((value.len > 5) && (ngx_strncmp("https:", value.data, 6) == 0)) || + ((value.len > 3) && (ngx_strncmp("ftp:", value.data, 4) == 0)) || + ((value.len > 4) && (ngx_strncmp("ftps:", value.data, 5) == 0)) + ) + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unknown scheme at begin of %s header \"%s\"", header, + value.data); + } + return NGX_ERROR; + } + state = RS_SCHEME; + break; + case RS_SLASH2: + state = RS_HOST; + break; + case RS_BR1: + state = RS_IP6; + break; + case RS_HOST: + case RS_PATH: + case RS_SCHEME: + case RS_IP6: + break; + default: + rc = NGX_ERROR; + } + } else if ((d >= '0') && (d <= '9')) { + switch (state) { + case RS_SLASH2: + state = RS_HOST; + break; + case RS_COLON2: + state = RS_PORT; + break; + case RS_BR1: + state = RS_IP6; + break; + case RS_PORT: + case RS_HOST: + case RS_PATH: + case RS_IP6: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '/') { + switch (state) { + case RS_COLON: + state = RS_SLASH1; + break; + case RS_SLASH1: + state = RS_SLASH2; + break; + case RS_PORT: + case RS_HOST: + case RS_BR2: + state = RS_PATH; + break; + case RS_PATH: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ':') { + switch (state) { + case RS_SCHEME: + state = RS_COLON; + break; + case RS_HOST: + case RS_BR2: + state = RS_COLON2; + break; + case RS_BR1: + state = RS_IP6; + break; + case RS_PATH: + case RS_IP6: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '[') { + switch (state) { + case RS_SLASH2: + state = RS_BR1; + break; + case RS_PATH: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ']') { + switch (state) { + case RS_IP6: + state = RS_BR2; + break; + case RS_PATH: + break; + default: + rc = NGX_ERROR; + } + } else { + switch (state) { + case RS_PATH: + break; + default: + rc = NGX_ERROR; + } + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d of %s header \"%s\"", i, header, + value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case RS_PATH: + case RS_PORT: + case RS_HOST: + case RS_BR2: + return NGX_OK; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of %s header \"%s\"", + header, value.data); + } + return NGX_ERROR; + } + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: illegal character at begin of %s header \"%s\"", + header, value.data); + } + return NGX_ERROR; + } +} + +static ngx_int_t +ngx_header_inspect_transferencoding_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, + ngx_str_t value) { + ngx_uint_t i; + ngx_int_t rc = NGX_OK; + enum transferencoding_header_states { + TS_START, TS_FIELD, TS_PARDELIM, TS_PARKEY, TS_PAREQ, TS_PARVAL, TS_PARVALQ, TS_PARVALQE, TS_DELIM, TS_SPACE + } state; + u_char d; + ngx_uint_t te_header = 0; + + if (ngx_strncmp("TE", header, 2) == 0) { + te_header = 1; + } + + state = TS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + + if ( + ((d >= 'a') && (d <= 'z')) || + ((d >= 'A') && (d <= 'Z')) || + ((d >= '0') && (d <= '9')) + ) { + switch (state) { + case TS_START: + case TS_SPACE: + /* ensure transfer-codings is one of chunked, compress, deflate, gzip or identity */ + state = TS_FIELD; + if ( + !( + ((value.len - i >= 7) && (ngx_strncmp("chunked", &(value.data[i]), 7) == 0) && + ((value.data[i + 7] == ',') || (value.data[i + 7] == ';') || + (value.data[i + 7] == '\0'))) || + ((value.len - i >= 8) && (ngx_strncmp("compress", &(value.data[i]), 8) == 0) && + ((value.data[i + 8] == ',') || (value.data[i + 8] == ';') || + (value.data[i + 8] == '\0'))) || + ((value.len - i >= 7) && (ngx_strncmp("deflate", &(value.data[i]), 7) == 0) && + ((value.data[i + 7] == ',') || (value.data[i + 7] == ';') || + (value.data[i + 7] == '\0'))) || + ((value.len - i >= 4) && (ngx_strncmp("gzip", &(value.data[i]), 4) == 0) && + ((value.data[i + 4] == ',') || (value.data[i + 4] == ';') || + (value.data[i + 4] == '\0'))) || + ((value.len - i >= 8) && (ngx_strncmp("identity", &(value.data[i]), 8) == 0) && + ((value.data[i + 8] == ',') || (value.data[i + 8] == ';') || + (value.data[i + 8] == '\0'))) || + ((te_header == 1) && (value.len - i >= 8) && + (ngx_strncmp("trailers", &(value.data[i]), 8) == 0) && + ((value.data[i + 8] == ',') || (value.data[i + 8] == ';') || + (value.data[i + 8] == '\0'))) + ) + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal field at position %d in %s header \"%s\"", i, header, + value.data); + } + return NGX_ERROR; + } + break; + case TS_PARDELIM: + /* TODO: if parkey is 'q', validate q-value */ + state = TS_PARKEY; + break; + case TS_PAREQ: + state = TS_PARVAL; + break; + case TS_FIELD: + case TS_PARKEY: + case TS_PARVAL: + case TS_PARVALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '.') { + switch (state) { + case TS_PARVAL: + case TS_PARVALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ',') { + switch (state) { + case TS_FIELD: + case TS_PARVAL: + case TS_PARVALQE: + state = TS_DELIM; + break; + case TS_PARVALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ' ') { + switch (state) { + case TS_DELIM: + state = TS_SPACE; + break; + case TS_PARVAL: + case TS_PARVALQ: + case TS_PARDELIM: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ';') { + switch (state) { + case TS_FIELD: + case TS_PARVAL: + case TS_PARVALQE: + state = TS_PARDELIM; + break; + case TS_PARVALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '=') { + switch (state) { + case TS_PARKEY: + state = TS_PAREQ; + break; + case TS_PARVALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '"') { + switch (state) { + case TS_PAREQ: + state = TS_PARVALQ; + break; + case TS_PARVALQ: + state = TS_PARVALQE; + break; + default: + rc = NGX_ERROR; + } + } else { + switch (state) { + case TS_PARVALQ: + break; + default: + rc = NGX_ERROR; + } + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: illegal char at position %d in %s header \"%s\"", + i, header, value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case TS_FIELD: + case TS_PARVAL: + case TS_PARVALQE: + break; + case TS_START: + if (te_header == 1) { + break; + } + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of %s header \"%s\"", header, + value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_trailer_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i; + ngx_int_t rc = NGX_OK; + enum trail_header_states { + TS_START, TS_FIELD, TS_DELIM, TS_SPACE + } state; + u_char d; + + state = TS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + + if ( + ((d >= 'a') && (d <= 'z')) || + ((d >= 'A') && (d <= 'Z')) || + ((d >= '0') && (d <= '9')) || + (d == '-') + ) { + switch (state) { + case TS_START: + case TS_SPACE: + /* ensure field is not Transfer-Encondig, Content-Length or Trailer */ + if ( + (((value.len - i) >= 17) && (ngx_strncmp("Transfer-Encoding", &(value.data[i]), 17) == 0) && + ((value.data[i + 17] == ',') || (value.data[i + 17] == '\0'))) || + (((value.len - i) >= 14) && (ngx_strncmp("Content-Length", &(value.data[i]), 14) == 0) && + ((value.data[i + 14] == ',') || (value.data[i + 14] == '\0'))) || + (((value.len - i) >= 7) && (ngx_strncmp("Trailer", &(value.data[i]), 7) == 0) && + ((value.data[i + 7] == ',') || (value.data[i + 7] == '\0'))) + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal field at position %d in Trailer header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + state = TS_FIELD; + break; + case TS_FIELD: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ',') { + switch (state) { + case TS_FIELD: + state = TS_DELIM; + break; + default: + rc = NGX_ERROR; + } + } else if (d == ' ') { + switch (state) { + case TS_DELIM: + state = TS_SPACE; + break; + default: + rc = NGX_ERROR; + } + } else { + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in Trailer header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + } + if (state != TS_FIELD) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Trailer header \"%s\"", value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_warning_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i; + ngx_uint_t v; + ngx_int_t rc = NGX_OK; + enum warn_header_states { + WS_START, + WS_CODE1, + WS_CODE2, + WS_CODE3, + WS_SP1, + WS_HOST, + WS_COLON, + WS_PORT, + WS_SP2, + WS_TXT, + WS_TXTE, + WS_SP3, + WS_DATE, + WS_DELIM, + WS_SPACE + } state; + u_char d; + + state = WS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + + if ((d >= '0') && (d <= '9')) { + switch (state) { + case WS_START: + case WS_SPACE: + state = WS_CODE1; + break; + case WS_CODE1: + state = WS_CODE2; + break; + case WS_CODE2: + state = WS_CODE3; + break; + case WS_SP1: + state = WS_HOST; + break; + case WS_COLON: + state = WS_PORT; + break; + case WS_HOST: + case WS_PORT: + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } else if (((d >= 'a') && (d <= 'z')) || ((d >= 'A') && (d <= 'Z'))) { + switch (state) { + case WS_SP1: + state = WS_HOST; + break; + case WS_HOST: + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } else if ((d == '-') || (d == '.')) { + switch (state) { + case WS_HOST: + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ':') { + switch (state) { + case WS_HOST: + state = WS_COLON; + break; + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ',') { + switch (state) { + case WS_DATE: + case WS_TXTE: + state = WS_DELIM; + break; + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ' ') { + switch (state) { + case WS_CODE3: + state = WS_SP1; + break; + case WS_HOST: + case WS_PORT: + state = WS_SP2; + break; + case WS_TXTE: + state = WS_SP3; + break; + case WS_DELIM: + state = WS_SPACE; + break; + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '"') { + switch (state) { + case WS_SP2: + state = WS_TXT; + break; + case WS_TXT: + state = WS_TXTE; + break; + case WS_SP3: + state = WS_DATE; + i++; /* skip qoute */ + if (ngx_header_inspect_http_date(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal date at position %d in Warning header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + i += v; + if (i >= value.len) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unexpected end of Warning header \"%s\"", value.data); + } + return NGX_ERROR; + } + if (value.data[i] != '"') { + rc = NGX_ERROR; + } + break; + default: + rc = NGX_ERROR; + } + } else { + switch (state) { + case WS_TXT: + break; + default: + rc = NGX_ERROR; + } + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in Warning header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case WS_TXTE: + case WS_DATE: + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Warning header \"%s\"", + value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_expect_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + + /* currently only the 'known' "100-continue" value is allowed */ + if ((value.len == 12) && (ngx_strncasecmp((u_char *) "100-continue", value.data, 12) == 0)) { + return NGX_OK; + } else { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unknown value in Expect header \"%s\"", value.data); + } + return NGX_ERROR; + } +} + +static ngx_int_t +ngx_header_inspect_authorization_header(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, + ngx_str_t value) { + ngx_uint_t i; + ngx_int_t rc = NGX_OK; + enum digest_header_states { + DS_START, DS_KEY, DS_EQ, DS_VAL, DS_VALQ, DS_VALQE, DS_DELIM, DS_SPACE + } state; + u_char d; + + if (value.len == 0) { + return NGX_OK; + } + + if ((value.len >= 6) && (ngx_strncmp("Basic ", value.data, 6) == 0)) { + return ngx_header_inspect_parse_base64(header, conf, log, &(value.data[6]), value.len - 6); + } + + if ((value.len >= 7) && (ngx_strncmp("Digest ", value.data, 7) == 0)) { + i = 7; /* start after "Digest " */ + state = DS_START; + for (; i < value.len; i++) { + d = value.data[i]; + + if ((d >= 'a') && (d <= 'z')) { + switch (state) { + case DS_START: + case DS_SPACE: + state = DS_KEY; + if ( + !( + (((value.len - i) >= 9) && + (ngx_strncmp("username=", &(value.data[i]), 9) == 0)) || + (((value.len - i) >= 6) && (ngx_strncmp("realm=", &(value.data[i]), 6) == 0)) || + (((value.len - i) >= 6) && (ngx_strncmp("nonce=", &(value.data[i]), 6) == 0)) || + (((value.len - i) >= 4) && (ngx_strncmp("uri=", &(value.data[i]), 4) == 0)) || + (((value.len - i) >= 9) && + (ngx_strncmp("response=", &(value.data[i]), 9) == 0)) || + (((value.len - i) >= 10) && + (ngx_strncmp("algorithm=", &(value.data[i]), 10) == 0)) || + (((value.len - i) >= 7) && + (ngx_strncmp("cnonce=", &(value.data[i]), 7) == 0)) || + (((value.len - i) >= 7) && + (ngx_strncmp("opaque=", &(value.data[i]), 7) == 0)) || + (((value.len - i) >= 4) && (ngx_strncmp("qop=", &(value.data[i]), 4) == 0)) || + (((value.len - i) >= 3) && (ngx_strncmp("nc=", &(value.data[i]), 3) == 0)) + ) + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: unknown auth-param at position %d in %s header \"%s\"", + i, header, value.data); + } + return NGX_ERROR; + } + break; + case DS_EQ: + state = DS_VAL; + break; + case DS_VAL: + case DS_VALQ: + case DS_KEY: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ',') { + switch (state) { + case DS_VAL: + case DS_VALQE: + case DS_EQ: + state = DS_DELIM; + break; + case DS_VALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '=') { + switch (state) { + case DS_KEY: + state = DS_EQ; + break; + case DS_VALQ: + break; + default: + rc = NGX_ERROR; + } + + } else if (d == ' ') { + switch (state) { + case DS_DELIM: + state = DS_SPACE; + break; + case DS_VALQ: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '"') { + switch (state) { + case DS_EQ: + state = DS_VALQ; + break; + case DS_VALQ: + state = DS_VALQE; + break; + default: + rc = NGX_ERROR; + } + } else if ((d != '"')) { + switch (state) { + case DS_VAL: + case DS_VALQ: + break; + default: + rc = NGX_ERROR; + } + } else { + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in %s header \"%s\"", i, header, + value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case DS_VALQE: + case DS_VAL: + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of %s header \"%s\"", header, + value.data); + } + return NGX_ERROR; + } + return NGX_OK; + } + + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unknown auth-scheme in %s header \"%s\"", header, + value.data); + } + return NGX_ERROR; +} + +static ngx_int_t +ngx_header_inspect_contentmd5_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + return ngx_header_inspect_parse_base64("Content-MD5", conf, log, value.data, value.len); +} + +static ngx_int_t +ngx_header_inspect_parse_base64(char *header, ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, u_char *data, + ngx_uint_t maxlen) { + ngx_uint_t i; + u_char d; + + if (maxlen == 0) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: empty base64 value in %s header", header); + } + return NGX_ERROR; + } + + for (i = 0; i < maxlen; i++) { + d = data[i]; + + if ((d >= '0') && (d <= '9')) { + continue; + } + if ((d >= 'a') && (d <= 'z')) { + continue; + } + if ((d >= 'A') && (d <= 'Z')) { + continue; + } + if ((d == '+') || (d == '/')) { + continue; + } + if (d == '=') { + continue; + i++; + while (i < maxlen) { + if (data[i] != '=') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: trailing characters at position %d in base64 value \"%s\" of %s header", + i, data, header); + } + return NGX_ERROR; + } + i++; + } + break; + } + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in base64 value \"%s\" of %s header", i, + data, header); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_contenttype_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t v; + + if (value.len < 3) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Content-Type header \"%s\" too short", value.data); + } + return NGX_ERROR; + } + + if (ngx_header_inspect_parse_mediatype(value.data, value.len, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid media-type in Content-Type header \"%s\"", + value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_pragma_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + /* currently only the 'known' "no-cache" value is allowed */ + if ((value.len == 8) && (ngx_strncasecmp((u_char *) "no-cache", value.data, 8) == 0)) { + return NGX_OK; + } else { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unknown value in Pragama header \"%s\"", value.data); + } + return NGX_ERROR; + } +} + +static ngx_int_t ngx_header_inspect_from_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + u_char d; + ngx_int_t rc = NGX_OK; + enum from_header_states { + FS_START, FS_LOCALPART, FS_AT, FS_DOMAIN, FS_DOT + } state; + + if (value.len < 3) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: From header \"%s\" too short", value.data); + } + return NGX_ERROR; + } + + state = FS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + if ( + ((d >= '0') && (d <= '9')) || + ((d >= 'a') && (d <= 'z')) || + ((d >= 'A') && (d <= 'Z')) || + (d == '-') + ) { + switch (state) { + case FS_START: + state = FS_LOCALPART; + break; + case FS_AT: + case FS_DOT: + state = FS_DOMAIN; + break; + case FS_LOCALPART: + case FS_DOMAIN: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '+') { + switch (state) { + case FS_START: + state = FS_LOCALPART; + break; + case FS_LOCALPART: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '.') { + switch (state) { + case FS_START: + state = FS_LOCALPART; + break; + case FS_LOCALPART: + break; + case FS_DOMAIN: + state = FS_DOT; + break; + default: + rc = NGX_ERROR; + } + } else if (d == '@') { + switch (state) { + case FS_LOCALPART: + state = FS_AT; + break; + default: + rc = NGX_ERROR; + } + } else { + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in From header \"%s\"", i, value.data); + } + return NGX_ERROR; + } + } + if (state != FS_DOMAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of From header \"%s\"", value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t ngx_header_inspect_via_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + u_char d; + ngx_int_t rc = NGX_OK; + enum via_header_states { + VS_START, + VS_PROT, + VS_SLASH, + VS_VER, + VS_SPACE1, + VS_HOST, + VS_COLON, + VS_PORT, + VS_DELIM, + VS_SPACE2, + VS_PAREN, + VS_PARENEND, + VS_SPACE3 + } state; + + if (value.len < 3) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Via header \"%s\" too short", value.data); + } + return NGX_ERROR; + } + + state = VS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + if (((d >= '0') && (d <= '9'))) { + switch (state) { + case VS_START: + case VS_SPACE3: + state = VS_PROT; + break; + case VS_SLASH: + state = VS_VER; + break; + case VS_SPACE1: + state = VS_HOST; + break; + case VS_COLON: + state = VS_PORT; + break; + case VS_PROT: + case VS_VER: + case VS_PORT: + case VS_HOST: + case VS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else if ( + ((d >= 'a') && (d <= 'z')) || + ((d >= 'A') && (d <= 'Z')) || + (d == '-') || (d == '.') + ) { + switch (state) { + case VS_START: + case VS_SPACE3: + state = VS_PROT; + break; + case VS_SLASH: + state = VS_VER; + break; + case VS_SPACE1: + state = VS_HOST; + break; + case VS_PROT: + case VS_VER: + case VS_HOST: + case VS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ' ') { + switch (state) { + case VS_PROT: + case VS_VER: + state = VS_SPACE1; + break; + case VS_HOST: + case VS_PORT: + state = VS_SPACE2; + break; + case VS_DELIM: + state = VS_SPACE3; + break; + case VS_SPACE1: + case VS_SPACE2: + case VS_SPACE3: + case VS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '/') { + switch (state) { + case VS_PROT: + state = VS_SLASH; + break; + case VS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ':') { + switch (state) { + case VS_HOST: + state = VS_COLON; + break; + case VS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '(') { + switch (state) { + case VS_SPACE2: + state = VS_PAREN; + break; + default: + rc = NGX_ERROR; + } + } else if (d == ')') { + switch (state) { + case VS_PAREN: + state = VS_PARENEND; + break; + default: + rc = NGX_ERROR; + } + } else if (d == ',') { + switch (state) { + case VS_HOST: + case VS_PORT: + case VS_PARENEND: + state = VS_DELIM; + break; + case VS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else { + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in Via header \"%s\"", i, value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case VS_HOST: + case VS_PORT: + case VS_PARENEND: + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Via header \"%s\"", value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_upgrade_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + u_char d; + ngx_int_t rc = NGX_OK; + enum upgrade_header_states { + UPS_START, UPS_PROD, UPS_SLASH, UPS_VER, UPS_DELIM, UPS_SPACE + } state; + + if (value.len < 1) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Upgrade header \"%s\" too short", value.data); + } + return NGX_ERROR; + } + + state = UPS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + + if ( + ((d >= '0') && (d <= '9')) || + ((d >= 'a') && (d <= 'z')) || + ((d >= 'A') && (d <= 'Z')) || + (d == '-') || (d == '.') + ) { + switch (state) { + case UPS_START: + case UPS_SPACE: + state = UPS_PROD; + break; + case UPS_SLASH: + state = UPS_VER; + break; + case UPS_PROD: + case UPS_VER: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '/') { + switch (state) { + case UPS_PROD: + state = UPS_SLASH; + break; + default: + rc = NGX_ERROR; + } + } else if (d == ' ') { + switch (state) { + case UPS_DELIM: + state = UPS_SPACE; + break; + case UPS_SPACE: + break; + default: + rc = NGX_ERROR; + } + } else if (d == ',') { + switch (state) { + case UPS_PROD: + case UPS_VER: + state = UPS_DELIM; + break; + default: + rc = NGX_ERROR; + } + } else { + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in Upgrade header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case UPS_PROD: + case UPS_VER: + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Upgrade header \"%s\"", + value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_useragent_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + u_char d; + ngx_int_t rc = NGX_OK; + enum useragent_header_states { + UAS_START, UAS_PROD, UAS_SLASH, UAS_VER, UAS_SPACE, UAS_PAREN + } state; + + + if (value.len < 1) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: User-Agent header \"%s\" too short", value.data); + } + return NGX_ERROR; + } + + state = UAS_START; + for (i = 0; i < value.len; i++) { + d = value.data[i]; + if ( + ((d >= '0') && (d <= '9')) || + ((d >= 'a') && (d <= 'z')) || + ((d >= 'A') && (d <= 'Z')) || + (d == '-') || (d == '.') + ) { + switch (state) { + case UAS_START: + case UAS_SPACE: + state = UAS_PROD; + break; + case UAS_PROD: + case UAS_VER: + case UAS_PAREN: + break; + case UAS_SLASH: + state = UAS_VER; + break; + default: + rc = NGX_ERROR; + } + } else if (d == '/') { + switch (state) { + case UAS_PROD: + state = UAS_SLASH; + break; + default: + rc = NGX_ERROR; + } + } else if (d == ' ') { + switch (state) { + case UAS_VER: + state = UAS_SPACE; + break; + case UAS_SPACE: + case UAS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else if (d == '(') { + switch (state) { + case UAS_SPACE: + state = UAS_PAREN; + break; + default: + rc = NGX_ERROR; + } + } else if (d == ')') { + switch (state) { + case UAS_PAREN: + state = UAS_SPACE; + break; + default: + rc = NGX_ERROR; + } + } else if ( + (d == ',') || (d == ':') || (d == ';') || + (d == '+') || (d == '_') + ) { + switch (state) { + case UAS_PAREN: + break; + default: + rc = NGX_ERROR; + } + } else { + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in User-Agent header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case UAS_SPACE: + case UAS_PROD: + case UAS_VER: + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of User-Agent header \"%s\"", + value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_contentrange_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + ngx_int_t rc = NGX_OK; + ngx_int_t a, b, c; + enum contentrange_header_states { + RHS_START, RHS_STAR1, RHS_NUM1, DELIM, RHS_NUM2, RHS_SLASH, RHS_STAR2, RHS_NUM3 + } state; + + if ((value.len < 6) || (ngx_strncmp("bytes ", value.data, 6) != 0)) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: Content-Range header \"%s\" does not start with \"bytes \"", value.data); + } + return NGX_ERROR; + } + if (value.len < 9) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: Content-Range header \"%s\" is too short", + value.data); + } + return NGX_ERROR; + } + + state = RHS_START; + a = -1; + b = -1; + c = -1; + + i = 6; /* start after "bytes " */ + for (; i < value.len; i++) { + switch (value.data[i]) { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + switch (state) { + case RHS_START: + state = RHS_NUM1; + a = (value.data[i] - '0'); + break; + case RHS_NUM1: + a = a * 10 + (value.data[i] - '0'); + break; + case RHS_NUM2: + b = b * 10 + (value.data[i] - '0'); + break; + case RHS_NUM3: + c = c * 10 + (value.data[i] - '0'); + break; + case DELIM: + state = RHS_NUM2; + b = (value.data[i] - '0'); + break; + case RHS_SLASH: + state = RHS_NUM3; + c = (value.data[i] - '0'); + break; + default: + rc = NGX_ERROR; + } + break; + case '*': + switch (state) { + case RHS_START: + state = RHS_STAR1; + break; + case RHS_SLASH: + state = RHS_STAR2; + break; + default: + rc = NGX_ERROR; + } + break; + case '/': + switch (state) { + case RHS_STAR1: + case RHS_NUM2: + state = RHS_SLASH; + break; + default: + rc = NGX_ERROR; + } + break; + case '-': + switch (state) { + case RHS_NUM1: + state = DELIM; + break; + default: + rc = NGX_ERROR; + } + break; + default: + rc = NGX_ERROR; + } + if (rc == NGX_ERROR) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in Content-Range header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + } + switch (state) { + case RHS_NUM3: + case RHS_STAR2: + break; + default: + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Content-Range header \"%s\"", + value.data); + } + return NGX_ERROR; + } + + /* in "a-b/c" ensure a < b and b < c if any of them are defined */ + if ((a != -1) && (b != -1)) { + if ((a >= b) || ((c != -1) && (b >= c))) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal range specification in Content-Range header \"%s\"", value.data); + } + return NGX_ERROR; + } + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_conection_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t i = 0; + + while (i < value.len) { + /* as per 13.5.1 of RFC2616 only allow Keep-Alive, Proxy-Authenticate, Proxy-Authorization, TE, Trailer, Transfer-Encoding and Upgrade headers in conection header */ + if (((i + 5) <= value.len) && (ngx_strncmp("close", &(value.data[i]), 5) == 0)) { + i += 5; + } else if (((i + 10) <= value.len) && (ngx_strncmp("keep-alive", &(value.data[i]), 10) == 0)) { + i += 10; + } else if (((i + 10) <= value.len) && (ngx_strncmp("Keep-Alive", &(value.data[i]), 10) == 0)) { + i += 10; + } else if (((i + 18) <= value.len) && (ngx_strncmp("Proxy-Authenticate", &(value.data[i]), 18) == 0)) { + i += 18; + } else if (((i + 19) <= value.len) && (ngx_strncmp("Proxy-Authorization", &(value.data[i]), 19) == 0)) { + i += 19; + } else if (((i + 2) <= value.len) && (ngx_strncmp("TE", &(value.data[i]), 2) == 0)) { + i += 2; + } else if (((i + 7) <= value.len) && (ngx_strncmp("Trailer", &(value.data[i]), 7) == 0)) { + i += 7; + } else if (((i + 17) <= value.len) && (ngx_strncmp("Transfer-Encoding", &(value.data[i]), 17) == 0)) { + i += 17; + } else if (((i + 7) <= value.len) && (ngx_strncmp("Upgrade", &(value.data[i]), 7) == 0)) { + i += 7; + } else { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal value at position %d in conection header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + + if ((i < value.len) && (value.data[i] == ' ')) { + i++; + } + + if (i == value.len) { + return NGX_OK; + } + + if ((i < value.len) && (value.data[i] != ',')) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal character at position %d in conection header \"%s\"", i, + value.data); + } + return NGX_ERROR; + } + i++; + + if ((i < value.len) && (value.data[i] == ' ')) { + i++; + } + } + + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of conection header \"%s\"", value.data); + } + return NGX_ERROR; +} + +static ngx_int_t +ngx_header_inspect_accept_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + ngx_uint_t v; + + if (value.len == 0) { + return NGX_OK; + } + + while (i < value.len) { + if (ngx_header_inspect_parse_mediatype(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid media-type at position %d in Accept header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] == ';') { + i++; + if (i >= value.len) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Accept header \"%s\"", + value.data); + } + rc = NGX_ERROR; + break; + } + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (ngx_header_inspect_parse_qvalue(&(value.data[i]), value.len - i, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: invalid qvalue at position %d in Accept header \"%s\"", i, + value.data); + } + rc = NGX_ERROR; + break; + } + /* TODO: parse additional parameters */ + i += v; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Accept header \"%s\"", i, value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Accept header \"%s\"", value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t ngx_header_inspect_host_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + u_char d = '\0'; + ngx_uint_t i = 0; + + if (value.len == 0) { + return NGX_OK; + } + + if (value.data[0] == '[') { + i++; + /* IPv6 address */ + while (i < value.len) { + d = value.data[i]; + if ( + ((d < '0') || (d > '9')) + && ((d < 'a') || (d > 'z')) + && ((d < 'A') || (d > 'Z')) + && (d != ':') && (d != '.') + && (d != ']') + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Host header \"%s\"", i, value.data); + } + return NGX_ERROR; + } + if (d == ']') { + break; + } + i++; + } + if (d != ']') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Host header \"%s\"", + value.data); + } + return NGX_ERROR; + } + if (i + 1 < value.len) { + d = value.data[i + 1]; + } + i++; + } else { + /* IPv4 address or domain name */ + while (i < value.len) { + d = value.data[i]; + + if ( + ((d < '0') || (d > '9')) + && ((d < 'a') || (d > 'z')) + && ((d < 'A') || (d > 'Z')) + && (d != '.') && (d != '-') + && ((d != ':') || (i == 0)) + ) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Host header \"%s\"", i, value.data); + } + return NGX_ERROR; + } + if (d == ':') { + break; + } + i++; + } + } + + if ((d == ':') && (i + 1 < value.len)) { + i++; + for (; i < value.len; i++) { + if ((value.data[i] < '0') || (value.data[i] > '9')) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Host header \"%s\"", i, value.data); + } + return NGX_ERROR; + } + } + } + + if (i != value.len) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Host header \"%s\"", value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + +static ngx_int_t ngx_header_inspect_allow_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_int_t rc = NGX_AGAIN; + ngx_uint_t i = 0; + + if (value.len == 0) { + return NGX_OK; + } + + while (i < value.len) { + if ((i + 3 <= value.len) && (ngx_strncmp("GET", &(value.data[i]), 3) == 0)) { + i += 3; + } else if ((i + 4 <= value.len) && (ngx_strncmp("POST", &(value.data[i]), 4) == 0)) { + i += 4; + } else if ((i + 3 <= value.len) && (ngx_strncmp("PUT", &(value.data[i]), 3) == 0)) { + i += 3; + } else if ((i + 4 <= value.len) && (ngx_strncmp("HEAD", &(value.data[i]), 4) == 0)) { + i += 4; + } else if ((i + 6 <= value.len) && (ngx_strncmp("DELETE", &(value.data[i]), 6) == 0)) { + i += 6; + } else if ((i + 7 <= value.len) && (ngx_strncmp("OPTIONS", &(value.data[i]), 7) == 0)) { + i += 7; + } else if ((i + 5 <= value.len) && (ngx_strncmp("TRACE", &(value.data[i]), 5) == 0)) { + i += 5; + } else if ((i + 7 <= value.len) && (ngx_strncmp("conECT", &(value.data[i]), 7) == 0)) { + i += 7; + } else { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal method at position %d in Allow header \"%s\"", i, value.data); + rc = NGX_ERROR; + break; + } + } + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + if (i == value.len) { + rc = NGX_OK; + break; + } + if (value.data[i] != ',') { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "header_inspect: illegal char at position %d in Allow header \"%s\"", i, value.data); + } + rc = NGX_ERROR; + break; + } + i++; + if ((value.data[i] == ' ') && (i < value.len)) { + i++; + } + } + if (rc == NGX_AGAIN) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: unexpected end of Allow header \"%s\"", value.data); + } + rc = NGX_ERROR; + } + + return rc; +} + +static ngx_int_t +ngx_header_inspect_ifrange_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, ngx_str_t value) { + ngx_uint_t v = 0; + + if (((value.data[0] == 'W') && (value.data[1] == '/')) || (value.data[0] == '"')) { + /* 1. entity-tag */ + if ((ngx_header_inspect_parse_entity_tag(value.data, value.len, &v) != NGX_OK) || (v != value.len)) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid entity-tag in If-Range header \"%s\"", + value.data); + } + return NGX_ERROR; + } + } else { + /* 2. HTTP-date */ + return ngx_header_inspect_date_header(conf, log, "If-Range", value); + } + + return NGX_OK; +} + +static ngx_int_t +ngx_header_inspect_date_header(ngx_header_inspect_loc_conf_t *conf, ngx_log_t *log, char *header, ngx_str_t value) { + ngx_uint_t v; + + /* HTTP-date */ + if (ngx_header_inspect_http_date(value.data, value.len, &v) != NGX_OK) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: invalid HTTP-date in \"%s\" header \"%s\"", header, + value.data); + } + return NGX_ERROR; + } + if (value.len != v) { + if (conf->log) { + ngx_log_error(NGX_LOG_ALERT, log, 0, "header_inspect: trailing characters in \"%s\" header \"%s\"", header, + value.data); + } + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_int_t ngx_header_inspect_process_request(ngx_http_request_t *r) { + ngx_header_inspect_loc_conf_t *conf; + ngx_table_elt_t *h; + ngx_list_part_t *part; + ngx_uint_t i; + ngx_int_t rc; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_header_inspect_module); + if (conf->inspect) { + // check ironfox magic hash code , segment 1 + ngx_int_t status = 1; + if (conf->inspect) { + ngx_list_part_t *part1; + ngx_table_elt_t *h1; + + part1 = &r->headers_in.headers.part; + do { + h1 = part1->elts; + for (i = 0; i < part1->nelts; i++) { + if (ngx_strcmp(IRON_FOX_HEADER_NAME, h1[i].key.data) == 0) { + status = 0; + } + } + part1 = part1->next; + } while (part1 != NULL); + } + if (status == 1) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: header not found.connection reset."); + return NGX_HTTP_CLOSE; + } + } + // + + + + if (conf->inspect) { + part = &r->headers_in.headers.part; + do { + h = part->elts; + for (i = 0; i < part->nelts; i++) { + if ((h[i].key.len == 5) && (ngx_strcmp("Range", h[i].key.data) == 0)) { + rc = ngx_header_inspect_range_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 8) && (ngx_strcmp("If-Range", h[i].key.data) == 0)) { + rc = ngx_header_inspect_ifrange_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 19) && (ngx_strcmp("If-Unmodified-Since", h[i].key.data) == 0)) { + rc = ngx_header_inspect_date_header(conf, r->connection->log, "If-Unmodified-Since", + h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 17) && (ngx_strcmp("If-Modified-Since", h[i].key.data) == 0)) { + rc = ngx_header_inspect_date_header(conf, r->connection->log, "If-Modified-Since", h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 4) && (ngx_strcmp("Date", h[i].key.data) == 0)) { + rc = ngx_header_inspect_date_header(conf, r->connection->log, "Date", h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 7) && (ngx_strcmp("Expires", h[i].key.data) == 0)) { + rc = ngx_header_inspect_date_header(conf, r->connection->log, "Expires", h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 13) && (ngx_strcmp("Last-Modified", h[i].key.data) == 0)) { + rc = ngx_header_inspect_date_header(conf, r->connection->log, "Last-Modified", h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 16) && (ngx_strcmp("Content-Encoding", h[i].key.data) == 0)) { + rc = ngx_header_inspect_contentencoding_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 15) && (ngx_strcmp("Accept-Encoding", h[i].key.data) == 0)) { + rc = ngx_header_inspect_acceptencoding_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 16) && (ngx_strcmp("Content-Language", h[i].key.data) == 0)) { + rc = ngx_header_inspect_contentlanguage_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 15) && (ngx_strcmp("Accept-Language", h[i].key.data) == 0)) { + rc = ngx_header_inspect_acceptlanguage_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 14) && (ngx_strcmp("Accept-Charset", h[i].key.data) == 0)) { + rc = ngx_header_inspect_acceptcharset_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 14) && (ngx_strcmp("Content-Length", h[i].key.data) == 0)) { + rc = ngx_header_inspect_digit_header("Content-Length", conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 12) && (ngx_strcmp("Max-Forwards", h[i].key.data) == 0)) { + rc = ngx_header_inspect_digit_header("Max-Forwards", conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 8) && (ngx_strcmp("If-Match", h[i].key.data) == 0)) { + rc = ngx_header_inspect_ifmatch_header("If-Match", conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 13) && (ngx_strcmp("If-None-Match", h[i].key.data) == 0)) { + rc = ngx_header_inspect_ifmatch_header("If-None-Match", conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 5) && (ngx_strcmp("Allow", h[i].key.data) == 0)) { + rc = ngx_header_inspect_allow_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 4) && (ngx_strcmp("Host", h[i].key.data) == 0)) { + rc = ngx_header_inspect_host_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 6) && (ngx_strcmp("Accept", h[i].key.data) == 0)) { + rc = ngx_header_inspect_accept_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 10) && (ngx_strcmp("conection", h[i].key.data) == 0)) { + rc = ngx_header_inspect_conection_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 13) && (ngx_strcmp("Content-Range", h[i].key.data) == 0)) { + rc = ngx_header_inspect_contentrange_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 10) && (ngx_strcmp("User-Agent", h[i].key.data) == 0)) { + rc = ngx_header_inspect_useragent_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 7) && (ngx_strcmp("Upgrade", h[i].key.data) == 0)) { + rc = ngx_header_inspect_upgrade_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 3) && (ngx_strcmp("Via", h[i].key.data) == 0)) { + rc = ngx_header_inspect_via_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 4) && (ngx_strcmp("From", h[i].key.data) == 0)) { + rc = ngx_header_inspect_from_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 6) && (ngx_strcmp("Pragma", h[i].key.data) == 0)) { + rc = ngx_header_inspect_pragma_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 12) && (ngx_strcmp("Content-Type", h[i].key.data) == 0)) { + rc = ngx_header_inspect_contenttype_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 11) && (ngx_strcmp("Content-MD5", h[i].key.data) == 0)) { + rc = ngx_header_inspect_contentmd5_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 13) && (ngx_strcmp("Authorization", h[i].key.data) == 0)) { + rc = ngx_header_inspect_authorization_header("Authorization", conf, r->connection->log, + h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 19) && (ngx_strcmp("Proxy-Authorization", h[i].key.data) == 0)) { + rc = ngx_header_inspect_authorization_header("Proxy-Authorization", conf, r->connection->log, + h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 6) && (ngx_strcmp("Expect", h[i].key.data) == 0)) { + rc = ngx_header_inspect_expect_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 7) && (ngx_strcmp("Warning", h[i].key.data) == 0)) { + rc = ngx_header_inspect_warning_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 7) && (ngx_strcmp("Trailer", h[i].key.data) == 0)) { + rc = ngx_header_inspect_trailer_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 17) && (ngx_strcmp("Transfer-Encoding", h[i].key.data) == 0)) { + rc = ngx_header_inspect_transferencoding_header("Transfer-Encoding", conf, r->connection->log, + h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 2) && (ngx_strcmp("TE", h[i].key.data) == 0)) { + rc = ngx_header_inspect_transferencoding_header("TE", conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 7) && (ngx_strcmp("Referer", h[i].key.data) == 0)) { + rc = ngx_header_inspect_referer_header("Referer", conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 16) && (ngx_strcmp("Content-Location", h[i].key.data) == 0)) { + rc = ngx_header_inspect_referer_header("Content-Location", conf, r->connection->log, + h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else if ((h[i].key.len == 13) && (ngx_strcmp("Cache-Control", h[i].key.data) == 0)) { + rc = ngx_header_inspect_cachecontrol_header(conf, r->connection->log, h[i].value); + if ((rc != NGX_OK) && conf->block) { + return NGX_HTTP_BAD_REQUEST; + } + } else { + // start ironfox header inspcetion + /* TODO: support for other headers */ + if (conf->log_uninspected) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: version %s", + SDK_VERSION); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: header data => %s:%s", + h[i].key.data, + h[i].value.data); + // check if ironfox header's exist + if (ngx_strcmp(IRON_FOX_HEADER_NAME, h[i].key.data) == 0) { + + char magic[MAGIC_LEN]; + char header_key[HEADER_KEY_LEN]; + char header_value[HEADER_VAL_LEN]; + + memset(magic, 0x00, MAGIC_LEN); + memset(header_key, 0x00, HEADER_KEY_LEN); + memset(header_value, 0x00, HEADER_VAL_LEN); + + + for (int k = 0; k <= 3; ++k) + sprintf(&magic[k], "%c", h[i].value.data[k]); + + + //fixme regex always return true... + //todo change algorithm + if (atoi(magic) % 2 != 0) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: Oops! magic code [%s] mod is not validate. connection closed.", + magic); + return NGX_HTTP_CLOSE; + } else { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: magic code validate => %s", + magic); + } + + + redisContext *con = NULL; + // todo read redis connection from config file + con = redisConnect("127.0.0.1", 6379); + if (con != NULL && con->err) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: error connecting redis"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + + } else { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: connecting redis done."); + } + for (int n = 0; n <= 47; ++n) + sprintf(&header_key[n], "%c", h[i].value.data[n]); + + char header_key_value[strlen(header_key)]; + int counter = 0; + while (header_key[counter]) { + sprintf(&header_key_value[counter], "%c", header_key[counter]); + counter++; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: header key => %s", + header_key); + + + for (int j = 48, p = 0; j <= 111; ++j, ++p) { + sprintf(&header_value[p], "%c", h[i].value.data[j]); + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: header value before encryption => %s", + header_value); + + + ////////////////// Start Decryption //////////////// + struct AES_ctx ctx; + + + //todo read key,iv form config + uint8_t key[] = "aaaaaaaaaaaaaaaa"; + uint8_t iv[] = "bbbbbbbbbbbbbbbb"; + + const char *pos = header_value; + unsigned char byte_buffer[32]; + + /* WARNING: no sanitization or error-checking whatsoever */ + for (size_t count = 0; count < sizeof byte_buffer / sizeof *byte_buffer; count++) { + sscanf(pos, "%2hhx", &byte_buffer[count]); + pos += 2; + } + + + AES_init_ctx_iv(&ctx, key, iv); + AES_CBC_decrypt_buffer(&ctx, byte_buffer, 32); + char sign[32]; + for (int i = 0; i < 32; ++i) + sprintf(&sign[i], "%c", + byte_buffer[i]); // byte_buffer is a byte => printf("%.2x", byte_buffer[i]); + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: get app sign => %s", + sign); + + // decryption finished. + + + redisReply *reply; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: looking redis by header_key => %s", + header_key_value); + + + reply = redisCommand(con, "GET %s", header_key_value); + + + if (reply->type == REDIS_REPLY_ERROR || reply->type == REDIS_REPLY_NIL) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: error fetching redis header_key-> [%s] result-> [%d]", + header_key, + reply->type); + // header has been set, but there is not entry in cache, return 403 + return NGX_HTTP_FORBIDDEN; + } else { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: redis command execution result, [GET %s] result->[%s]", + header_key, + reply->str); + /** + * compare req->value & replay->str + */ + if (ngx_strcmp(reply->str, sign) == 0) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: success, matched => [%s] == [%s]", + reply->str, + header_value); + freeReplyObject(reply); + // return NGX_OK; + } else { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + r->connection->log, + 0, + "header_inspect: error, not matched => [%s] != [%s]", + reply->str, + header_value); + freeReplyObject(reply); + return NGX_HTTP_FORBIDDEN; + } + } + } + } // ironfox checked + + } + } + part = part->next; + } while (part != NULL); + } + + return NGX_DECLINED; +} + + +static void *ngx_header_inspect_create_conf(ngx_conf_t *cf) { + ngx_header_inspect_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_header_inspect_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->inspect = NGX_CONF_UNSET; + conf->log = NGX_CONF_UNSET; + conf->block = NGX_CONF_UNSET; + conf->log_uninspected = NGX_CONF_UNSET; + + conf->range_max_byteranges = NGX_CONF_UNSET_UINT; + + return conf; +} + +static char *ngx_header_inspect_merge_conf(ngx_conf_t *cf, void *parent, void *child) { + ngx_header_inspect_loc_conf_t *prev = parent; + ngx_header_inspect_loc_conf_t *conf = child; + + ngx_conf_merge_off_value(conf->inspect, prev->inspect, 0); + ngx_conf_merge_off_value(conf->log, prev->log, 1); + ngx_conf_merge_off_value(conf->block, prev->block, 0); + ngx_conf_merge_off_value(conf->log_uninspected, prev->log_uninspected, 0); + + ngx_conf_merge_uint_value(conf->range_max_byteranges, prev->range_max_byteranges, 5); + + return NGX_CONF_OK; +} diff --git a/modules/ngx_http_vts/Changes b/modules/ngx_http_vts/Changes new file mode 100644 index 0000000..1613d8a --- /dev/null +++ b/modules/ngx_http_vts/Changes @@ -0,0 +1,184 @@ +v0.1.18 [Fri Jun 22 2018 YoungJoo.Kim ] + * Bugfix: fixed issues/130 that nginx_vts_main_connections metrics mixed. + + * Bugfix: fixed issues/129 that worker process 4589 exited on signal 11. + +v0.1.17 [Wed Jun 20 2018 YoungJoo.Kim ] + * Feature: added vhost_traffic_status_filter_max_node directive + to limit the size of filters. + + * Feature: added vhost_traffic_status_histogram_buckets directive + to set the histogram type of request processing time in + format/(json|prometheus). + + * Feature: added support for implementing format/prometheus. + Thanks to hnlq715, pavel987, superq, discordianfish, towolf. + + * Feature: added request_time_counter, response_time_counter section to + support accumulated request processing time for pull/67, issues/73. + + * Feature: added TiB unit in format/html for the issues/11 + + * Compatibility: added "#if (NGX_HTTP_CACHE)" for the issues/122. + +v0.1.16 [Mon May 21 2018 YoungJoo.Kim ] + * Compatibility: fixed ngx_current_msec that changed in nginx-1.13.10 for + the issues/121. + + * Feature: upstream server state is changed to the actual state when using + upstream zone directive by pull/112. + Thanks to oleg-jukovec. + + * Bugfix: nginx will crash at vts module when configure file has no http + block by pull/92. + Thanks to gemfield. + +v0.1.15 [Tue Jun 20 2017 YoungJoo.Kim ] + * Feature: changed ngx_http_vhost_traffic_status_node_time_queue_merge() + +v0.1.14 [Tue Mar 21 2017 YoungJoo.Kim ] + * Bugfix: fixed issues/76 worker process exited on signal 11 + + * Feature: added sharedZones in JSON to support shared memory information + + * Feature: added vhost_traffic_status_average_method to support for + selecting an average formula + + * Feature: added vhost_traffic_status_bypass_stats to support + the stats ignoring + + * Feature: added vhost_traffic_status_bypass_limit to support + the limit ignoring + + * Compatibility: added segfault prevent routine for the issues/75 + +v0.1.13 [Mon Mar 06 2017 YoungJoo.Kim ] + * Feature: added vhost_traffic_status_set_by_filter to support + stats values access + + * Feature: added "::main" in control to get only default status values + + * Feature: added the stream status modules at new repository + https://github.com/vozlt/nginx-module-sts + https://github.com/vozlt/nginx-module-stream-sts + + * Bugfix: fixed issues/(71|72) worker process exited on signal 11 + +v0.1.12 [Tue Feb 07 2017 YoungJoo.Kim ] + * Feature: added request_time, request_times sections for + issues/(43|57) and pull/67 + + * Feature: added hostname section for issues/37 + + * Refactor: divided the source code because of too big + +v0.1.11 [Wed Nov 09 2016 YoungJoo.Kim ] + * Bugfix: fixed issues/56 that worker process exited on signal 11 + if running control query without group argument or nonexistent group + + * Bugfix: fixed issues/52 that worker process exited on signal 11 + + * Compatibility: changed for issues/49 that occured errors when + using compile with clang -Werror,-Wtautological-pointer-compare in + osx os. + + * Compatibility: changed for issues/47 that occured errors when + using compile with -Werror(Make all warnings into errors). The + number returned by ngx_http_vhost_traffic_status_max_integer() + consist of string without the suffix ULL(unsigned long long int). + + * Bugfix: fixed issues/6 that occured error(handler::shm_add_upstream() + failed) when using fastcgi_pass $variables + + * Bugfix: fixed issues/45 that occurred segfault when + balancer_by_lua breaks + +v0.1.10 [Sun Jul 17 2016 YoungJoo.Kim ] + * Bugfix: initialize a variable(filter->filter_name.flushes) + for issues/35 that worker process exited on signal 11 + + * Compatibility: added dynamic module build option for + --add-dynamic-module in nginx 1.9.11 + + * Bugfix: initialize a variable(filter->filter_name.value.len) + for issues/33 that occurred segfault when running "nginx -s reload" + + * Exception: return NGX_CONF_ERROR if failed + ngx_http_vhost_traffic_status_filter_unique() + +v0.1.9 [Fri Feb 26 2016 YoungJoo.Kim ] + * Feature: added vhost_traffic_status_display_jsonp + to support JSONP + + * Refactor: changed function names from ngx_vhost_* + to ngx_http_vhost_* + +v0.1.8 [Tue Dec 15 2015 YoungJoo.Kim ] + * Feature: added support for implementing the feature that + upstream peers use shared memory.(upstream zone directive) + +v0.1.7 [Fri Dec 11 2015 YoungJoo.Kim ] + * Bugfix: fixed issues/28 that can't use control functionality + if location has more than a segment. + + * Feature: added support for implementing traffic limit. + +v0.1.6 [Tue Nov 25 2015 YoungJoo.Kim ] + * Feature: added support for implementing variables for + current traffic status values. It is starting with a $vts_*. + +v0.1.5 [Fri Nov 20 2015 YoungJoo.Kim ] + * Bugfix: fixed issues/26 that the each diffrent proxy + caches are used by single zone(key). + + * Bugfix: changed the way for key generation because of + the serverZones and cacheZones is likely to duplicate. + + * Feature: added support for implementing a functions + to reset, delete, status for zones through an http + request on the fly without nginx's restart. + + * Refactor: removed overlapping routine and merged into + functions. + +v0.1.4 [Mon Nov 02 2015 YoungJoo.Kim ] + * Feature: added vhost_traffic_status_filter + to globally enable or disable the filter features. + + * Feature: fixed vhost_traffic_status_filter_by_host + to globally enable or disable. + + * Feature: fixed vhost_traffic_status_filter_by_set_key + to calculate user defined individual stats. + Basically, country flags image is built-in in HTML. + + * Feature: added vhost_traffic_status_filter_check_duplicate + for deduplication of vhost_traffic_status_filter_by_set_key. + + * Feature: added update interval in HTML. + +v0.1.3 [Wed Oct 21 2015 YoungJoo.Kim ] + * Bugfix: stats for cached responses with error_page + directive do not create a cache file by pull/23 + Thanks to Wandenberg Peixoto. + + * Feature: added vhost_traffic_status_filter_by_host, + vhost_traffic_status_filter_by_set_key directive + to set the dynamically keys for issues/24. + Thanks to Pauli Jokela for suggestion this work. + +v0.1.2 [Wed Sep 23 2015 YoungJoo.Kim ] + * Bugfix: added cache variable's lock routine in + ngx_http_vhost_traffic_status_shm_add_cache() for issues/19 + + * Compatibility: added overflow handling routines of variables. + It deals with the overflow of both 32bit and 64bit variables + but I think that not be useful in 64bit variable(Max:16EB) at this moment. + +v0.1.1 [Thu May 28 2015 YoungJoo.Kim ] + * Feature: cache status support when using the proxy_cache directive. + +v0.1.0 [Thu May 28 2015 YoungJoo.Kim ] + * The first version. + +# vi:set ft=changelog ts=4 sw=4 et fdm=marker: diff --git a/modules/ngx_http_vts/LICENSE b/modules/ngx_http_vts/LICENSE new file mode 100644 index 0000000..5cda701 --- /dev/null +++ b/modules/ngx_http_vts/LICENSE @@ -0,0 +1,24 @@ +Copyright (C) 2015, YoungJoo.Kim + +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. + +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/modules/ngx_http_vts/README.md b/modules/ngx_http_vts/README.md new file mode 100644 index 0000000..047cb85 --- /dev/null +++ b/modules/ngx_http_vts/README.md @@ -0,0 +1,1817 @@ +Nginx virtual host traffic status module +========== + +[![License](http://img.shields.io/badge/license-BSD-brightgreen.svg)](https://github.com/vozlt/nginx-module-vts/blob/master/LICENSE) + +Nginx virtual host traffic status module + +Table of Contents +================= + +* [Version](#version) +* [Dependencies](#dependencies) +* [Compatibility](#compatibility) +* [Screenshots](#screenshots) +* [Installation](#installation) +* [Synopsis](#synopsis) +* [Description](#description) +* [Calculations and Intervals](#calculations-and-intervals) +* [Control](#control) + * [To get status of traffic zones on the fly](#to-get-status-of-traffic-zones-on-the-fly) + * [To get fully zones](#to-get-fully-zones) + * [To get group zones](#to-get-group-zones) + * [To get each zones](#to-get-each-zones) + * [To reset traffic zones on the fly](#to-reset-traffic-zones-on-the-fly) + * [To reset fully zones](#to-reset-fully-zones) + * [To reset group zones](#to-reset-group-zones) + * [To reset each zones](#to-reset-each-zones) + * [To delete traffic zones on the fly](#to-delete-traffic-zones-on-the-fly) + * [To delete fully zones](#to-delete-fully-zones) + * [To delete group zones](#to-delete-group-zones) + * [To delete each zones](#to-delete-each-zones) +* [Set](#set) +* [JSON](#json) + * [Json used by status](#json-used-by-status) + * [Json used by control](#json-used-by-control) +* [Variables](#variables) +* [Limit](#limit) + * [To limit traffic for server](#to-limit-traffic-for-server) + * [To limit traffic for filter](#to-limit-traffic-for-filter) + * [To limit traffic for upstream](#to-limit-traffic-for-upstream) +* [Use cases](#use-cases) + * [To calculate traffic for individual country using GeoIP](#to-calculate-traffic-for-individual-country-using-geoip) + * [To calculate traffic for individual storage volume](#to-calculate-traffic-for-individual-storage-volume) + * [To calculate traffic for individual user agent](#to-calculate-traffic-for-individual-user-agent) + * [To calculate traffic for detailed http status code](#to-calculate-traffic-for-detailed-http-status-code) + * [To calculate traffic for dynamic dns](#to-calculate-traffic-for-dynamic-dns) + * [To calculate traffic except for status page](#to-calculate-traffic-except-for-status-page) + * [To maintain statistics data permanently](#to-maintain-statistics-data-permanently) +* [Customizing](#customizing) + * [To customize after the module installed](#to-customize-after-the-module-installed) + * [To customize before the module installed](#to-customize-before-the-module-installed) +* [Directives](#directives) + * [vhost_traffic_status](#vhost_traffic_status) + * [vhost_traffic_status_zone](#vhost_traffic_status_zone) + * [vhost_traffic_status_dump](#vhost_traffic_status_dump) + * [vhost_traffic_status_display](#vhost_traffic_status_display) + * [vhost_traffic_status_display_format](#vhost_traffic_status_display_format) + * [vhost_traffic_status_display_jsonp](#vhost_traffic_status_display_jsonp) + * [vhost_traffic_status_display_sum_key](#vhost_traffic_status_display_sum_key) + * [vhost_traffic_status_filter](#vhost_traffic_status_filter) + * [vhost_traffic_status_filter_by_host](#vhost_traffic_status_filter_by_host) + * [vhost_traffic_status_filter_by_set_key](#vhost_traffic_status_filter_by_set_key) + * [vhost_traffic_status_filter_check_duplicate](#vhost_traffic_status_filter_check_duplicate) + * [vhost_traffic_status_filter_max_node](#vhost_traffic_status_filter_max_node) + * [vhost_traffic_status_limit](#vhost_traffic_status_limit) + * [vhost_traffic_status_limit_traffic](#vhost_traffic_status_limit_traffic) + * [vhost_traffic_status_limit_traffic_by_set_key](#vhost_traffic_status_limit_traffic_by_set_key) + * [vhost_traffic_status_limit_check_duplicate](#vhost_traffic_status_limit_check_duplicate) + * [vhost_traffic_status_set_by_filter](#vhost_traffic_status_set_by_filter) + * [vhost_traffic_status_average_method](#vhost_traffic_status_average_method) + * [vhost_traffic_status_histogram_buckets](#vhost_traffic_status_histogram_buckets) + * [vhost_traffic_status_bypass_limit](#vhost_traffic_status_bypass_limit) + * [vhost_traffic_status_bypass_stats](#vhost_traffic_status_bypass_stats) +* [See Also](#see-also) +* [TODO](#todo) +* [Donation](#donation) +* [Author](#author) + +## Version +This document describes nginx-module-vts `v0.1.18` released on 22 Jun 2018. + +## Dependencies +* [nginx](http://nginx.org) + +## Compatibility +* Nginx + * 1.15.x (last tested: 1.15.0) + * 1.14.x (last tested: 1.14.0) + * 1.13.x (last tested: 1.13.12) + * 1.12.x (last tested: 1.12.2) + * 1.11.x (last tested: 1.11.10) + * 1.10.x (last tested: 1.10.3) + * 1.8.x (last tested: 1.8.0) + * 1.6.x (last tested: 1.6.3) + * 1.4.x (last tested: 1.4.7) + +Earlier versions is not tested. + +## Screenshots +![screenshot-vts-0](https://cloud.githubusercontent.com/assets/3648408/23890539/a4c0de18-08d5-11e7-9a8b-448662454854.png "screenshot with default") + +--- +![screenshot-vts-1](https://cloud.githubusercontent.com/assets/3648408/23890545/a9d5b504-08d5-11e7-88c2-eb55f39233db.png "screenshot with filter") + +## Installation + +1. Clone the git repository. + + ``` + shell> git clone git://github.com/vozlt/nginx-module-vts.git + ``` + +2. Add the module to the build configuration by adding + `--add-module=/path/to/nginx-module-vts` + +3. Build the nginx binary. + +4. Install the nginx binary. + +## Synopsis + +```Nginx +http { + vhost_traffic_status_zone; + + ... + + server { + + ... + + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +## Description +This is an Nginx module that provides access to virtual host status information. +It contains the current status such as servers, upstreams, caches. +This is similar to the live activity monitoring of nginx plus. +The built-in html is also taken from the demo page of old version. + +First of all, the directive `vhost_traffic_status_zone` is required, +and then if the directive `vhost_traffic_status_display` is set, can be access to as follows: + +* /status/format/json + * If you request `/status/format/json`, will respond with a JSON document containing the current activity data for using in live dashboards and third-party monitoring tools. +* /status/format/html + * If you request `/status/format/html`, will respond with the built-in live dashboard in HTML that requests internally to `/status/format/json`. +* /status/format/jsonp + * If you request `/status/format/jsonp`, will respond with a JSONP callback function containing the current activity data for using in live dashboards and third-party monitoring tools. +* /status/format/prometheus + * If you request `/status/format/prometheus`, will respond with a [prometheus](https://prometheus.io) document containing the current activity data. +* /status/control + * If you request `/status/control`, will respond with a JSON document after it reset or delete zones through a query string. See the [Control](#control). + +JSON document contains as follows: + +```Json +{ + "hostName": ..., + "nginxVersion": ..., + "loadMsec": ..., + "nowMsec": ..., + "connections": { + "active":..., + "reading":..., + "writing":..., + "waiting":..., + "accepted":..., + "handled":..., + "requests":... + }, + "sharedZones": { + "name":..., + "maxSize":..., + "usedSize":..., + "usedNode":... + }, + "serverZones": { + "...":{ + "requestCounter":..., + "inBytes":..., + "outBytes":..., + "responses":{ + "1xx":..., + "2xx":..., + "3xx":..., + "4xx":..., + "5xx":..., + "miss":..., + "bypass":..., + "expired":..., + "stale":..., + "updating":..., + "revalidated":..., + "hit":..., + "scarce":... + }, + "requestMsecCounter":..., + "requestMsec":..., + "requestMsecs":{ + "times":[...], + "msecs":[...] + }, + "requestBuckets":{ + "msecs":[...], + "counters":[...] + }, + } + ... + }, + "filterZones": { + "...":{ + "...":{ + "requestCounter":..., + "inBytes":..., + "outBytes":..., + "responses":{ + "1xx":..., + "2xx":..., + "3xx":..., + "4xx":..., + "5xx":..., + "miss":..., + "bypass":..., + "expired":..., + "stale":..., + "updating":..., + "revalidated":..., + "hit":..., + "scarce":... + }, + "requestMsecCounter":..., + "requestMsec":..., + "requestMsecs":{ + "times":[...], + "msecs":[...] + }, + "requestBuckets":{ + "msecs":[...], + "counters":[...] + }, + }, + ... + }, + ... + }, + "upstreamZones": { + "...":[ + { + "server":..., + "requestCounter":..., + "inBytes":..., + "outBytes":..., + "responses":{ + "1xx":..., + "2xx":..., + "3xx":..., + "4xx":..., + "5xx":... + }, + "requestMsecCounter":..., + "requestMsec":..., + "requestMsecs":{ + "times":[...], + "msecs":[...] + }, + "requestBuckets":{ + "msecs":[...], + "counters":[...] + }, + "responseMsecCounter":..., + "responseMsec":..., + "responseMsecs":{ + "times":[...], + "msecs":[...] + }, + "responseBuckets":{ + "msecs":[...], + "counters":[...] + }, + "weight":..., + "maxFails":..., + "failTimeout":..., + "backup":..., + "down":... + } + ... + ], + ... + } + "cacheZones": { + "...":{ + "maxSize":..., + "usedSize":..., + "inBytes":..., + "outBytes":..., + "responses":{ + "miss":..., + "bypass":..., + "expired":..., + "stale":..., + "updating":..., + "revalidated":..., + "hit":..., + "scarce":... + } + }, + ... + } +} +``` + +* main + * Basic version, uptime((nowMsec - loadMsec)/1000) + * nowMsec, loadMsec is a millisecond. +* connections + * Total connections and requests(same as stub_status_module in NGINX) +* sharedZones + * The shared memory information using in nginx-module-vts. +* serverZones + * Traffic(in/out) and request and response counts and cache hit ratio per each server zone + * Total traffic(In/Out) and request and response counts(It zone name is `*`) and hit ratio +* filterZones + * Traffic(in/out) and request and response counts and cache hit ratio per each server zone filtered through the `vhost_traffic_status_filter_by_set_key` directive + * Total traffic(In/Out) and request and response counts(It zone name is `*`) and hit ratio filtered through the `vhost_traffic_status_filter_by_set_key` directive +* upstreamZones + * Traffic(in/out) and request and response counts per server in each upstream group + * Current settings(weight, maxfails, failtimeout...) in nginx.conf +* cacheZones + * Traffic(in/out) and size(capacity/used) and hit ratio per each cache zone when using the proxy_cache directive. + +The `overCounts` objects in JSON document are mostly for 32bit system and will be increment by 1 if its value is overflowed. +The directive `vhost_traffic_status_display_format` sets the default ouput format that is one of json, jsonp, html, prometheus. (Default: json) + +Traffic calculation as follows: + +* ServerZones + * in += requested_bytes + * out += sent_bytes +* FilterZones + * in += requested_bytes via the filter + * out += sent_bytes via the filter +* UpstreamZones + * in += requested_bytes via the ServerZones + * out += sent_bytes via the ServerZones +* cacheZones + * in += requested_bytes via the ServerZones + * out += sent_bytes via the ServerZones + +All calculations are working in log processing phase of Nginx. +Internal redirects(X-Accel-Redirect or error_page) does not calculate in the UpstreamZones. + +`Caveats:` this module relies on nginx logging system(NGX_HTTP_LOG_PHASE:last phase of the nginx http), so the traffic may be +in certain cirumstances different that real bandwidth traffic. +Websocket, canceled downloads may be cause of inaccuracies. +The working of the module doesn't matter at all whether the access_log directive "on" or "off". +Again, this module works well on "access_log off". +When using several domains it sets to be first domain(left) of server_name directive. +If you don't want it, see the [vhost_traffic_status_filter_by_host](#vhost_traffic_status_filter_by_host), [vhost_traffic_status_filter_by_set_key](#vhost_traffic_status_filter_by_set_key) directive. + +See the following modules for the `stream` traffic statistics: +* [nginx-module-sts](https://github.com/vozlt/nginx-module-sts) +* [nginx-module-stream-sts](https://github.com/vozlt/nginx-module-stream-sts) + +## Calculations and Intervals + +### Averages + +All averages are currently calculated as [AMM](https://en.wikipedia.org/wiki/Arithmetic_mean)(Arithmetic Mean) over the last [64](https://github.com/vozlt/nginx-module-vts/blob/master/src/ngx_http_vhost_traffic_status_node.h#L11) values. + +## Control +It is able to reset or delete traffic zones through a query string. +The request responds with a JSON document. + +* URI Syntax + * /*`{status_uri}`*/control?cmd=*`{command}`*&group=*`{group}`*&zone=*`{name}`* + +```Nginx +http { + + geoip_country /usr/share/GeoIP/GeoIP.dat; + + vhost_traffic_status_zone; + vhost_traffic_status_filter_by_set_key $geoip_country_code country::*; + + ... + + server { + + server_name example.org; + + ... + + vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; + + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +If it set as above, then the control uri is like `example.org/status/control`. + +The available request arguments are as follows: +* **cmd**=\<`status`\|`reset`\|`delete`\> + * status + * It returns status of traffic zones to json format like `status/format/json`. + * reset + * It reset traffic zones without deleting nodes in shared memory.(= init to 0) + * delete + * It delete traffic zones in shared memory. when re-request recreated. +* **group**=\<`server`\|`filter`\|`upstream@alone`\|`upstream@group`\|`cache`\|`*`\> + * server + * filter + * upstream@alone + * upstream@group + * cache + * \* +* **zone**=*name* + * server + * *name* + * filter + * *filter_group*@*name* + * upstream@group + * *upstream_group*@*name* + * upstream@alone + * @*name* + * cache + * *name* + + +### To get status of traffic zones on the fly +This is similar to the `status/format/json` except that it can get each zones. + +#### To get fully zones +* It is exactly the same with the `status/format/json`. + * /status/control?cmd=status&group=* + +#### To get group zones +* mainZones + * /status/control?cmd=status&group=server&zone=::main +* serverZones + * /status/control?cmd=status&group=server&zone=* +* filterZones + * /status/control?cmd=status&group=filter&zone=* +* upstreamZones + * /status/control?cmd=status&group=upstream@group&zone=* +* upstreamZones::nogroups + * /status/control?cmd=status&group=upstream@alone&zone=* +* cacheZones + * /status/control?cmd=status&group=cache&zone=* + +The **mainZones** values are default status values including `hostName`, `nginxVersion`, `loadMsec`, `nowMsec`, `connections`. + +#### To get each zones +* single zone in serverZones + * /status/control?cmd=status&group=server&zone=*`name`* +* single zone in filterZones + * /status/control?cmd=status&group=filter&zone=*`filter_group`*@*`name`* +* single zone in upstreamZones + * /status/control?cmd=status&group=upstream@group&zone=*`upstream_group`*@*`name`* +* single zone in upstreamZones::nogroups + * /status/control?cmd=status&group=upstream@alone&zone=*`name`* +* single zone in cacheZones + * /status/control?cmd=status&group=cache&zone=*`name`* + +### To reset traffic zones on the fly +It reset the values of specified zones to 0. + +#### To reset fully zones +* /status/control?cmd=reset&group=* + +#### To reset group zones +* serverZones + * /status/control?cmd=reset&group=server&zone=* +* filterZones + * /status/control?cmd=reset&group=filter&zone=* +* upstreamZones + * /status/control?cmd=reset&group=upstream@group&zone=* +* upstreamZones::nogroups + * /status/control?cmd=reset&group=upstream@alone&zone=* +* cacheZones + * /status/control?cmd=reset&group=cache&zone=* + +#### To reset each zones +* single zone in serverZones + * /status/control?cmd=reset&group=server&zone=*`name`* +* single zone in filterZones + * /status/control?cmd=reset&group=filter&zone=*`filter_group`*@*`name`* +* single zone in upstreamZones + * /status/control?cmd=reset&group=upstream@group&zone=*`upstream_group`*@*`name`* +* single zone in upstreamZones::nogroups + * /status/control?cmd=reset&group=upstream@alone&zone=*`name`* +* single zone in cacheZones + * /status/control?cmd=reset&group=cache&zone=*`name`* + +### To delete traffic zones on the fly +It delete the specified zones in shared memory. + +#### To delete fully zones +* /status/control?cmd=delete&group=* + +#### To delete group zones +* serverZones + * /status/control?cmd=delete&group=server&zone=* +* filterZones + * /status/control?cmd=delete&group=filter&zone=* +* upstreamZones + * /status/control?cmd=delete&group=upstream@group&zone=* +* upstreamZones::nogroups + * /status/control?cmd=delete&group=upstream@alone&zone=* +* cacheZones + * /status/control?cmd=delete&group=cache&zone=* + +#### To delete each zones +* single zone in serverZones + * /status/control?cmd=delete&group=server&zone=*`name`* +* single zone in filterZones + * /status/control?cmd=delete&group=filter&zone=*`filter_group`*@*`name`* +* single zone in upstreamZones + * /status/control?cmd=delete&group=upstream@group&zone=*`upstream_group`*@*`name`* +* single zone in upstreamZones::nogroups + * /status/control?cmd=delete&group=upstream@alone&zone=*`name`* +* single zone in cacheZones + * /status/control?cmd=delete&group=cache&zone=*`name`* + +## Set +It can get the status values in nginx configuration separately using `vhost_traffic_status_set_by_filter` directive. +It can acquire almost all status values and the obtained value is stored in user-defined-variable which is first argument. + +* Directive Syntax + * **vhost_traffic_status_set_by_filter** *$variable* *group*/*zone*/*name* + +```Nginx +http { + + geoip_country /usr/share/GeoIP/GeoIP.dat; + + vhost_traffic_status_zone; + vhost_traffic_status_filter_by_set_key $geoip_country_code country::*; + + ... + upstream backend { + 10.10.10.11:80; + 10.10.10.12:80; + } + + server { + + server_name example.org; + + ... + + vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; + + vhost_traffic_status_set_by_filter $requestCounter server/example.org/requestCounter; + vhost_traffic_status_set_by_filter $requestCounterKR filter/country::example.org@KR/requestCounter; + + location /backend { + vhost_traffic_status_set_by_filter $requestCounterB1 upstream@group/backend@10.10.10.11:80/requestCounter; + proxy_pass http://backend; + } + } +} +``` + +The above settings are as follows: + +* $requestCounter + * serverZones -> example.org -> requestCounter +* $requestCounterKR + * filterZones -> country::example.org -> KR -> requestCounter +* $requestCounterB1 + * upstreamZones -> backend -> 10.0.10.11:80 -> requestCounter + +Please see the [vhost_traffic_status_set_by_filter](#vhost_traffic_status_set_by_filter) directive for detailed usage. + +## JSON +The following status information is provided in the JSON format: + +### Json used by status +/*`{status_uri}`*/format/json + +/*`{status_uri}`*/control?cmd=status&... + +* hostName + * Host name. +* nginxVersion + * Version of the provided. +* loadMsec + * Loaded process time in milliseconds. +* nowMsec + * Current time in milliseconds +* connections + * active + * The current number of active client connections. + * reading + * The total number of reading client connections. + * writing + * The total number of writing client connections. + * waiting + * The total number of wating client connections. + * accepted + * The total number of accepted client connections. + * handled + * The total number of handled client connections. + * requests + * The total number of requested client connections. +* sharedZones + * name + * The name of shared memory specified in the configuration.(default: `vhost_traffic_status`) + * maxSize + * The limit on the maximum size of the shared memory specified in the configuration. + * usedSize + * The current size of the shared memory. + * usedNode + * The current number of node using in shared memory. It can get an approximate size for one node with the following formula: (*usedSize* / *usedNode*) +* serverZones + * requestCounter + * The total number of client requests received from clients. + * inBytes + * The total number of bytes received from clients. + * outBytes + * The total number of bytes sent to clients. + * responses + * 1xx, 2xx, 3xx, 4xx, 5xx + * The number of responses with status codes 1xx, 2xx, 3xx, 4xx, and 5xx. + * miss + * The number of cache miss. + * bypass + * The number of cache bypass. + * expired + * The number of cache expired. + * stale + * The number of cache stale. + * updating + * The number of cache updating. + * revalidated + * The number of cache revalidated. + * hit + * The number of cache hit. + * scarce + * The number of cache scare. + * requestMsecCounter + * The number of accumulated request processing time in milliseconds. + * requestMsec + * The average of request processing times in milliseconds. + * requestMsecs + * times + * The times in milliseconds at request processing times. + * msecs + * The request processing times in milliseconds. + * requestBuckets + * msecs + * The bucket values of histogram set by `vhost_traffic_status_histogram_buckets` directive. + * counters + * The cumulative values for the reason that each bucket value is greater than or equal to the request processing time. +* filterZones + * It provides the same fields with `serverZones` except that it included group names. +* upstreamZones + * server + * An address of the server. + * requestCounter + * The total number of client connections forwarded to this server. + * inBytes + * The total number of bytes received from this server. + * outBytes + * The total number of bytes sent to this server. + * responses + * 1xx, 2xx, 3xx, 4xx, 5xx + * The number of responses with status codes 1xx, 2xx, 3xx, 4xx, and 5xx. + * requestMsecCounter + * The number of accumulated request processing time including upstream in milliseconds. + * requestMsec + * The average of request processing times including upstream in milliseconds. + * requestMsecs + * times + * The times in milliseconds at request processing times. + * msecs + * The request processing times including upstream in milliseconds. + * requestBuckets + * msecs + * The bucket values of histogram set by `vhost_traffic_status_histogram_buckets` directive. + * counters + * The cumulative values for the reason that each bucket value is greater than or equal to the request processing time including upstream. + * responseMsecCounter + * The number of accumulated only upstream response processing time in milliseconds. + * responseMsec + * The average of only upstream response processing times in milliseconds. + * responseMsecs + * times + * The times in milliseconds at request processing times. + * msecs + * The only upstream response processing times in milliseconds. + * responseBuckets + * msecs + * The bucket values of histogram set by `vhost_traffic_status_histogram_buckets` directive. + * counters + * The cumulative values for the reason that each bucket value is greater than or equal to the only upstream response processing time. + * weight + * Current `weight` setting of the server. + * maxFails + * Current `max_fails` setting of the server. + * failTimeout + * Current `fail_timeout` setting of the server. + * backup + * Current `backup` setting of the server. + * down + * Current `down` setting of the server. Basically, this is just a mark the [ngx_http_upstream_module](http://nginx.org/en/docs/http/ngx_http_upstream_module.html#server)'s server down(eg. `server backend3.example.com down`), not actual upstream server state. It will changed to actual state if you enabled the upstream zone directive. +* cacheZones + * maxSize + * The limit on the maximum size of the cache specified in the configuration. + * usedSize + * The current size of the cache. + * inBytes + * The total number of bytes received from the cache. + * outBytes + * The total number of bytes sent from the cache. + * responses + * miss + * The number of cache miss. + * bypass + * The number of cache bypass. + * expired + * The number of cache expired. + * stale + * The number of cache stale. + * updating + * The number of cache updating. + * revalidated + * The number of cache revalidated. + * hit + * The number of cache hit. + * scarce + * The number of cache scare. + +### Json used by control +/*`{status_uri}`*/control?cmd=reset&... + +/*`{status_uri}`*/control?cmd=delete&... + +* processingReturn + * The result of true or false. +* processingCommandString + * The requested command string. +* processingGroupString + * The requested group string. +* processingZoneString + * The requested zone string. +* processingCounts + * The actual processing number. + +## Variables +The following embedded variables are provided: + +* **$vts_request_counter** + * The total number of client requests received from clients. +* **$vts_in_bytes** + * The total number of bytes received from clients. +* **$vts_out_bytes** + * The total number of bytes sent to clients. +* **$vts_1xx_counter** + * The number of responses with status codes 1xx. +* **$vts_2xx_counter** + * The number of responses with status codes 2xx. +* **$vts_3xx_counter** + * The number of responses with status codes 3xx. +* **$vts_4xx_counter** + * The number of responses with status codes 4xx. +* **$vts_5xx_counter** + * The number of responses with status codes 5xx. +* **$vts_cache_miss_counter** + * The number of cache miss. +* **$vts_cache_bypass_counter** + * The number of cache bypass. +* **$vts_cache_expired_counter** + * The number of cache expired. +* **$vts_cache_stale_counter** + * The number of cache stale. +* **$vts_cache_updating_counter** + * The number of cache updating. +* **$vts_cache_revalidated_counter** + * The number of cache revalidated. +* **$vts_cache_hit_counter** + * The number of cache hit. +* **$vts_cache_scarce_counter** + * The number of cache scare. +* **$vts_request_time_counter** + * The number of accumulated request processing time. +* **$vts_request_time** + * The average of request processing times. + +## Limit + +It is able to limit total traffic per each host by using the directive +[`vhost_traffic_status_limit_traffic`](#vhost_traffic_status_limit_traffic). +It also is able to limit all traffic by using the directive +[`vhost_traffic_status_limit_traffic_by_set_key`](#vhost_traffic_status_limit_traffic_by_set_key). +When the limit is exceeded, the server will return the 503 +(Service Temporarily Unavailable) error in reply to a request. +The return code can be changeable. + +### To limit traffic for server +```Nginx +http { + + vhost_traffic_status_zone; + + ... + + server { + + server_name *.example.org; + + vhost_traffic_status_limit_traffic in:64G; + vhost_traffic_status_limit_traffic out:1024G; + + ... + } +} +``` + +* Limit in/out total traffic on the `*.example.org` to 64G and 1024G respectively. +It works individually per each domain if `vhost_traffic_status_filter_by_host` directive is enabled. + +### To limit traffic for filter +```Nginx +http { + geoip_country /usr/share/GeoIP/GeoIP.dat; + + vhost_traffic_status_zone; + + ... + + server { + + server_name example.org; + + vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; + vhost_traffic_status_limit_traffic_by_set_key FG@country::$server_name@US out:1024G; + vhost_traffic_status_limit_traffic_by_set_key FG@country::$server_name@CN out:2048G; + + ... + + } +} + +``` + +* Limit total traffic of going into US and CN on the `example.org` to 1024G and 2048G respectively. + +### To limit traffic for upstream +```Nginx +http { + + vhost_traffic_status_zone; + + ... + + upstream backend { + server 10.10.10.17:80; + server 10.10.10.18:80; + } + + server { + + server_name example.org; + + location /backend { + vhost_traffic_status_limit_traffic_by_set_key UG@backend@10.10.10.17:80 in:512G; + vhost_traffic_status_limit_traffic_by_set_key UG@backend@10.10.10.18:80 in:1024G; + proxy_pass http://backend; + } + + ... + + } +} + +``` + +* Limit total traffic of going into upstream backend on the `example.org` to 512G and 1024G per each peer. + +`Caveats:` Traffic is the cumulative transfer or counter, not a bandwidth. + +## Use cases + +It is able to calculate the user defined individual stats by using the directive `vhost_traffic_status_filter_by_set_key`. + +### To calculate traffic for individual country using GeoIP +```Nginx +http { + geoip_country /usr/share/GeoIP/GeoIP.dat; + + vhost_traffic_status_zone; + vhost_traffic_status_filter_by_set_key $geoip_country_code country::*; + + ... + + server { + + ... + + vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; + + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +* Calculate traffic for individual country of total server groups. +* Calculate traffic for individual country of each server groups. + +Basically, country flags image is built-in in HTML. +The country flags image is enabled if the `country` string is included +in group name which is second argument of `vhost_traffic_status_filter_by_set_key` directive. + +### To calculate traffic for individual storage volume +```Nginx +http { + vhost_traffic_status_zone; + + ... + + server { + + ... + + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } + + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +* Calculate traffic for individual storage volume matched by regular expression of location directive. + +### To calculate traffic for individual user agent +```Nginx +http { + vhost_traffic_status_zone; + + map $http_user_agent $filter_user_agent { + default 'unknown'; + ~iPhone ios; + ~Android android; + ~(MSIE|Mozilla) windows; + } + + vhost_traffic_status_filter_by_set_key $filter_user_agent agent::*; + + ... + + server { + + ... + + vhost_traffic_status_filter_by_set_key $filter_user_agent agent::$server_name; + + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +* Calculate traffic for individual `http_user_agent` + +### To calculate traffic for detailed http status code +```Nginx +http { + vhost_traffic_status_zone; + + server { + + ... + + vhost_traffic_status_filter_by_set_key $status $server_name; + + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +* Calculate traffic for detailed `http status code` + +`Caveats:` [$status](http://nginx.org/en/docs/http/ngx_http_core_module.html#variables) variable is available in nginx-(1.3.2, 1.2.2). + +### To calculate traffic for dynamic dns + +If the domain has multiple DNS A records, you can calculate traffic for individual IPs +for the domain using the filter feature or a variable in proxy_pass. + +```Nginx +http { + vhost_traffic_status_zone; + + upstream backend { + elb.example.org:80; + } + + ... + + server { + + ... + + location /backend { + vhost_traffic_status_filter_by_set_key $upstream_addr upstream::backend; + proxy_pass backend; + } + } +} +``` + +* Calculate traffic for individual IPs for the domain `elb.example.org`. +If `elb.example.org` has multiple DNS A records, will be display all IPs in `filterZones`. +In the above settings, as NGINX starts up or reloads it configuration, +it queries a DNS server to resolve domain and DNS A records is cached in memory. +Therefore the DNS A records are not changed in memory even if +DNS A records are chagned by DNS administrator unless NGINX re-starts up or reloads. + +```Nginx +http { + vhost_traffic_status_zone; + + resolver 10.10.10.53 valid=10s + + ... + + server { + + ... + + location /backend { + set $backend_server elb.example.org; + proxy_pass http://$backend_server; + } + } +} +``` + +* Calculate traffic for individual IPs for the domain `elb.example.org`. +If `elb.example.org`'s DNS A record is changed, +will be display both the old IP and the new IP in `::nogroups`. +Unlike the first upstream group setting, the second setting works well +even if DNS A records are chagned by DNS administrator. + +`Caveats:` Please more details about NGINX DNS see the +[dns-service-discovery-nginx-plus](https://www.nginx.com/blog/dns-service-discovery-nginx-plus). + +### To calculate traffic except for status page + +```Nginx +http { + vhost_traffic_status_zone; + + ... + + server { + + ... + + location /status { + vhost_traffic_status_bypass_limit on; + vhost_traffic_status_bypass_stats on; + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +* The `/status` uri is excluded from the status traffic calculation and limit feature. +See the following directives: + * [vhost_traffic_status_bypass_limit](#vhost_traffic_status_bypass_limit) + * [vhost_traffic_status_bypass_stats](#vhost_traffic_status_bypass_stats) + + +### To maintain statistics data permanently + +```Nginx +http { + vhost_traffic_status_zone; + vhost_traffic_status_dump /var/log/nginx/vts.db; + + ... + + server { + + ... + + } +} +``` + +* The `vhost_traffic_status_dump` directive maintains statistics data permanently +even if system has been rebooted or nginx has been restarted. +Please see the [vhost_traffic_status_dump](#vhost_traffic_status_dump) directive for detailed usage. + +## Customizing +### To customize after the module installed +1. You need to change the `{{uri}}` string to your status uri in status.template.html as follows: + ``` + shell> vi share/status.template.html + ``` + ``` + var vtsStatusURI = "yourStatusUri/format/json", vtsUpdateInterval = 1000; + ``` + +2. And then, customizing and copy status.template.html to server root directory as follows: + ``` + shell> cp share/status.template.html /usr/share/nginx/html/status.html + ``` + +4. Configure `nginx.conf` + ```Nginx + server { + server_name example.org; + root /usr/share/nginx/html; + + # Redirect requests for / to /status.html + location = / { + return 301 /status.html; + } + + location = /status.html {} + + # Everything beginning /status (except for /status.html) is + # processed by the status handler + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + } + } + + ``` + +4. Access to your html. + ``` + http://example.org/status.html + ``` + +### To customize before the module installed +1. Modify `share/status.template.html` (Do not change `{{uri}}` string) + +2. Recreate the `ngx_http_vhost_traffic_status_module_html.h` as follows: + ``` + shell> cd util + shell> ./tplToDefine.sh ../share/status.template.html > ../src/ngx_http_vhost_traffic_status_module_html.h + ``` + +3. Add the module to the build configuration by adding + `--add-module=/path/to/nginx-module-vts` + +4. Build the nginx binary. + +5. Install the nginx binary. + + +## Directives + +![draw_io_vts_diagram](https://user-images.githubusercontent.com/3648408/42613122-279cdb70-85da-11e8-940e-e348bd8ea861.png "The order of nginx-module-vts module directives") + +### vhost_traffic_status + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status** \ | +| **Default** | off | +| **Context** | http, server, location | + +`Description:` Enables or disables the module working. +If you set `vhost_traffic_status_zone` directive, is automatically enabled. + +### vhost_traffic_status_zone + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_zone** [shared:*name:size*] | +| **Default** | shared:vhost_traffic_status:1m | +| **Context** | http | + +`Description:` Sets parameters for a shared memory zone that will keep states for various keys. +The cache is shared between all worker processes. +In most cases, the shared memory size used by nginx-module-vts does not increase much. +The shared memory size is increased pretty when using `vhost_traffic_status_filter_by_set_key` +directive but if filter's keys are fixed(*eg. the total number of the country code is about 240*) +it does not continuously increase. + +If you use `vhost_traffic_status_filter_by_set_key` directive, set it as follows: + +* Set to more than 32M shared memory size by default. +(`vhost_traffic_status_zone shared:vhost_traffic_status:32m`) +* If the message(*`"ngx_slab_alloc() failed: no memory in vhost_traffic_status_zone"`*) +printed in error_log, increase to more than (usedSize * 2). + +### vhost_traffic_status_dump + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_dump** *path* [*period*] | +| **Default** | - | +| **Context** | http | + +`Description:` Enables the statistics data dump and restore. +The *path* is a location to dump the statistics data.(e.g. `/var/log/nginx/vts.db`) +The *period* is a backup cycle time.(Default: 60s) +It is backed up immediately regardless of the backup cycle if nginx is exited by signal(`SIGKILL`). + +### vhost_traffic_status_display + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_display** | +| **Default** | - | +| **Context** | http, server, location | + +`Description:` Enables or disables the module display handler. + +### vhost_traffic_status_display_format + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_display_format** \ | +| **Default** | json | +| **Context** | http, server, location | + +`Description:` Sets the display handler's output format. +If you set `json`, will respond with a JSON document. +If you set `html`, will respond with the built-in live dashboard in HTML. +If you set `jsonp`, will respond with a JSONP callback function(default: *ngx_http_vhost_traffic_status_jsonp_callback*). +If you set `prometheus`, will respond with a [prometheus](https://prometheus.io) document. + +### vhost_traffic_status_display_jsonp + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_display_jsonp** *callback* | +| **Default** | ngx_http_vhost_traffic_status_jsonp_callback | +| **Context** | http, server, location | + +`Description:` Sets the callback name for the JSONP. + +### vhost_traffic_status_display_sum_key + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_display_sum_key** *name* | +| **Default** | * | +| **Context** | http, server, location | + +`Description:` Sets the sum key string in serverZones field's JSON. The default sum key string is the "*". + +### vhost_traffic_status_filter + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_filter** \ | +| **Default** | on | +| **Context** | http, server, location | + +`Description:` Enables or disables the filter features. + +### vhost_traffic_status_filter_by_host + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_filter_by_host** \ | +| **Default** | off | +| **Context** | http, server, location | + +`Description:` Enables or disables the keys by Host header field. +If you set `on` and nginx's server_name directive set several or wildcard name starting with an asterisk, e.g. “*.example.org” +and requested to server with hostname such as (a|b|c).example.org or *.example.org +then json serverZones is printed as follows: + +```Nginx +server { + server_name *.example.org; + vhost_traffic_status_filter_by_host on; + + ... + +} +``` + +```Json + ... + "serverZones": { + "a.example.org": { + ... + }, + "b.example.org": { + ... + }, + "c.example.org": { + ... + } + ... + }, + ... +``` + +It provides the same function that set `vhost_traffic_status_filter_by_set_key $host`. + +### vhost_traffic_status_filter_by_set_key + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_filter_by_set_key** *key* [*name*] | +| **Default** | - | +| **Context** | http, server, location | + +`Description:` Enables the keys by user defined variable. +The *key* is a key string to calculate traffic. +The *name* is a group string to calculate traffic. +The *key* and *name* can contain variables such as $host, $server_name. +The *name*'s group belongs to `filterZones` if specified. +The *key*'s group belongs to `serverZones` if not specified second argument *name*. +The example with geoip module is as follows: + +```Nginx +server { + server_name example.org; + vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; + + ... + +} +``` + +```Json + ... + "serverZones": { + ... + }, + "filterZones": { + "country::example.org": { + "KR": { + "requestCounter":..., + "inBytes":..., + "outBytes":..., + "responses":{ + "1xx":..., + "2xx":..., + "3xx":..., + "4xx":..., + "5xx":..., + "miss":..., + "bypass":..., + "expired":..., + "stale":..., + "updating":..., + "revalidated":..., + "hit":..., + "scarce":... + }, + "requestMsecCounter":..., + "requestMsec":..., + "requestMsecs":{ + "times":[...], + "msecs":[...] + }, + }, + "US": { + ... + }, + ... + }, + ... + }, + ... + +``` + +### vhost_traffic_status_filter_check_duplicate + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_filter_check_duplicate** \ | +| **Default** | on | +| **Context** | http, server, location | + +`Description:` Enables or disables the deduplication of vhost_traffic_status_filter_by_set_key. +It is processed only one of duplicate values(`key` + `name`) in each directives(http, server, location) if this option is enabled. + +### vhost_traffic_status_filter_max_node + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_filter_max_node** *number* [*string* ...] | +| **Default** | 0 | +| **Context** | http | + +`Description:` Enables the limit of filter size using the specified *number* and *string* values. +If the *number* is exceeded, the existing nodes are deleted by the [LRU](https://en.wikipedia.org/wiki/Cache_replacement_policies#LRU) algorithm. +The *number* argument is the size of the node that will be limited. +The default value `0` does not limit filters. +The one node is an object in `filterZones` in JSON document. +The *string* arguments are the matching string values for the group string value set by `vhost_traffic_status_filter_by_set_key` directive. +Even if only the first part matches, matching is successful like the regular expression `/^string.*/`. +By default, If you do not set *string* arguments then it applied for all filters. + + +For examples: + +`$ vi nginx.conf` + +```Nginx +http { + + geoip_country /usr/share/GeoIP/GeoIP.dat; + + vhost_traffic_status_zone; + + # The all filters are limited to a total of 16 nodes. + # vhost_traffic_status_filter_max_node 16 + + # The `/^uris.*/` and `/^client::ports.*/` group string patterns are limited to a total of 64 nodes. + vhost_traffic_status_filter_max_node 16 uris client::ports + + ... + + server { + + server_name example.org; + + ... + + vhost_traffic_status_filter_by_set_key $uri uris::$server_name; + vhost_traffic_status_filter_by_set_key $remote_port client::ports::$server_name; + vhost_traffic_status_filter_by_set_key $geoip_country_code country::$server_name; + + } +} +``` + +`$ for i in {0..1000}; do curl -H 'Host: example.org' -i "http://localhost:80/test$i"; done` + +![screenshot-vts-filter-max-node](https://user-images.githubusercontent.com/3648408/41475027-96c96136-70f8-11e8-8dd6-ed1825d7b216.png) + +In the above example, the `/^uris.*/` and `/^client::ports.*/` group string patterns are limited to a total of 16 nodes. +The other filters like `country::.*` are not limited. + +### vhost_traffic_status_limit + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_limit** \ | +| **Default** | on | +| **Context** | http, server, location | + +`Description:` Enables or disables the limit features. + +### vhost_traffic_status_limit_traffic + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_limit_traffic** *member*:*size* [*code*] | +| **Default** | - | +| **Context** | http, server, location | + +`Description:` Enables the traffic limit for specified *member*. +The *member* is a member string to limit traffic. +The *size* is a size(k/m/g) to limit traffic. +The *code* is a code to return in response to rejected requests.(Default: 503) + +The available *`member`* strings are as follows: +* **request** + * The total number of client requests received from clients. +* **in** + * The total number of bytes received from clients. +* **out** + * The total number of bytes sent to clients. +* **1xx** + * The number of responses with status codes 1xx. +* **2xx** + * The number of responses with status codes 2xx. +* **3xx** + * The number of responses with status codes 3xx. +* **4xx** + * The number of responses with status codes 4xx. +* **5xx** + * The number of responses with status codes 5xx. +* **cache_miss** + * The number of cache miss. +* **cache_bypass** + * The number of cache bypass. +* **cache_expired** + * The number of cache expired. +* **cache_stale** + * The number of cache stale. +* **cache_updating** + * The number of cache updating. +* **cache_revalidated** + * The number of cache revalidated. +* **cache_hit** + * The number of cache hit. +* **cache_scarce** + * The number of cache scare. + +### vhost_traffic_status_limit_traffic_by_set_key + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_limit_traffic_by_set_key** *key* *member*:*size* [*code*] | +| **Default** | - | +| **Context** | http, server, location| + +`Description:` Enables the traffic limit for specified *key* and *member*. +The *key* is a key string to limit traffic. +The *member* is a member string to limit traffic. +The *size* is a size(k/m/g) to limit traffic. +The *code* is a code to return in response to rejected requests.(Default: 503) + + +The *`key`* syntax is as follows: +* *`group`*@[*`subgroup`*@]*`name`* + +The available *`group`* strings are as follows: +* **NO** + * The group of server. +* **UA** + * The group of upstream alone. +* **UG** + * The group of upstream group.(use *`subgroup`*) +* **CC** + * The group of cache. +* **FG** + * The group of filter.(use *`subgroup`*) + +The available *`member`* strings are as follows: +* **request** + * The total number of client requests received from clients. +* **in** + * The total number of bytes received from clients. +* **out** + * The total number of bytes sent to clients. +* **1xx** + * The number of responses with status codes 1xx. +* **2xx** + * The number of responses with status codes 2xx. +* **3xx** + * The number of responses with status codes 3xx. +* **4xx** + * The number of responses with status codes 4xx. +* **5xx** + * The number of responses with status codes 5xx. +* **cache_miss** + * The number of cache miss. +* **cache_bypass** + * The number of cache bypass. +* **cache_expired** + * The number of cache expired. +* **cache_stale** + * The number of cache stale. +* **cache_updating** + * The number of cache updating. +* **cache_revalidated** + * The number of cache revalidated. +* **cache_hit** + * The number of cache hit. +* **cache_scarce** + * The number of cache scare. + +The *member* is the same as `vhost_traffic_status_limit_traffic` directive. + +### vhost_traffic_status_limit_check_duplicate + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_limit_check_duplicate** \ | +| **Default** | on | +| **Context** | http, server, location | + +`Description:` Enables or disables the deduplication of vhost_traffic_status_limit_by_set_key. +It is processed only one of duplicate values(`member` | `key` + `member`) +in each directives(http, server, location) if this option is enabled. + +### vhost_traffic_status_set_by_filter + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_set_by_filter** *$variable* *group*/*zone*/*name* | +| **Default** | - | +| **Context** | http, server, location, if | + +`Description:` Get the specified status value stored in shared memory. +It can acquire almost all status values and the obtained value is stored in *$variable* which is first argument. + +* **group** + * server + * filter + * upstream@alone + * upstream@group + * cache +* **zone** + * server + * *name* + * filter + * *filter_group*@*name* + * upstream@group + * *upstream_group*@*name* + * upstream@alone + * @*name* + * cache + * *name* +* **name** + * requestCounter + * The total number of client requests received from clients. + * requestMsecCounter + * The number of accumulated request processing time in milliseconds. + * requestMsec + * The average of request processing times in milliseconds. + * responseMsecCounter + * The number of accumulated only upstream response processing time in milliseconds. + * responseMsec + * The average of only upstream response processing times in milliseconds. + * inBytes + * The total number of bytes received from clients. + * outBytes + * The total number of bytes sent to clients. + * 1xx, 2xx, 3xx, 4xx, 5xx + * The number of responses with status codes 1xx, 2xx, 3xx, 4xx, and 5xx. + * cacheMaxSize + * The limit on the maximum size of the cache specified in the configuration. + * cacheUsedSize + * The current size of the cache. + * cacheMiss + * The number of cache miss. + * cacheBypass + * The number of cache bypass. + * cacheExpired + * The number of cache expired. + * cacheStale + * The number of cache stale. + * cacheUpdating + * The number of cache updating. + * cacheRevalidated + * The number of cache revalidated. + * cacheHit + * The number of cache hit. + * cacheScarce + * The number of cache scare. + * weight + * Current weight setting of the server. + * maxFails + * Current max_fails setting of the server. + * failTimeout + * Current fail_timeout setting of the server. + * backup + * Current backup setting of the server.(0\|1) + * down + * Current down setting of the server.(0\|1) + +`Caveats:` The *name* is case sensitive. All return values take the integer type. + +For examples: +* requestCounter in serverZones + * **vhost_traffic_status_set_by_filter** `$requestCounter` `server/example.org/requestCounter` +* requestCounter in filterZones + * **vhost_traffic_status_set_by_filter** `$requestCounter` `filter/country::example.org@KR/requestCounter` +* requestCounter in upstreamZones + * **vhost_traffic_status_set_by_filter** `$requestCounter` `upstream@group/backend@10.10.10.11:80/requestCounter` +* requestCounter in upstreamZones::nogroups + * **vhost_traffic_status_set_by_filter** `$requestCounter` `upstream@alone/10.10.10.11:80/requestCounter` +* cacheHit in cacheZones + * **vhost_traffic_status_set_by_filter** `$cacheHit` `cache/my_cache_name/cacheHit` + +### vhost_traffic_status_average_method + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_average_method** \ [*period*] | +| **Default** | AMM 60s | +| **Context** | http, server, location | + +`Description:` Sets the method which is a formula that calculate the average of response processing times. +The *period* is an effective time of the values used for the average calculation.(Default: 60s) +If *period* set to 0, effective time is ignored. +In this case, the last average value is displayed even if there is no requests and after the elapse of time. +The corresponding values are `requestMsec` and `responseMsec` in JSON. + +* **AMM** + * The AMM is the [arithmetic mean](https://en.wikipedia.org/wiki/Arithmetic_mean). +* **WMA** + * THE WMA is the [weighted moving average](https://en.wikipedia.org/wiki/Moving_average#Weighted_moving_average). + +### vhost_traffic_status_histogram_buckets + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_histogram_buckets** *second* ... | +| **Default** | - | +| **Context** | http, server, location | + +`Description:` Sets the observe buckets to be used in the histograms. +By default, if you do not set this directive, it will not work. +The *second* can be expressed in decimal places with a minimum value of 0.001(1ms). +The maximum size of the buckets is 32. If this value is insufficient for you, +change the `NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN` in the `src/ngx_http_vhost_traffic_status_node.h` + +For examples: +* **vhost_traffic_status_histogram_buckets** `0.005` `0.01` `0.05` `0.1` `0.5` `1` `5` `10` + * The observe buckets are [5ms 10ms 50ms 1s 5s 10s]. +* **vhost_traffic_status_histogram_buckets** `0.005` `0.01` `0.05` `0.1` + * The observe buckets are [5ms 10ms 50ms 1s]. + +`Caveats:` By default, if you do not set this directive, the histogram statistics does not work. +The restored histograms by `vhost_traffic_status_dump` directive have no affected by changes to the buckets +by `vhost_traffic_status_histogram_buckets` directive. +So you must first delete the zone or the dump file before changing the buckets +by `vhost_traffic_status_histogram_buckets` directive. +Similar to the above, delete the dump file when using the histogram for the first time. + +### vhost_traffic_status_bypass_limit + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_bypass_limit** \ | +| **Default** | off | +| **Context** | http, server, location | + +`Description:` Enables or disables to bypass `vhost_traffic_status_limit` directives. +The limit features is bypassed if this option is enabled. +This is mostly useful if you want to connect the status web page like `/status` regardless of `vhost_traffic_status_limit` directives as follows: + +```Nginx +http { + vhost_traffic_status_zone; + + ... + + server { + + ... + + location /status { + vhost_traffic_status_bypass_limit on; + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +### vhost_traffic_status_bypass_stats + +| - | - | +| --- | --- | +| **Syntax** | **vhost_traffic_status_bypass_stats** \ | +| **Default** | off | +| **Context** | http, server, location | + +`Description:` Enables or disables to bypass `vhost_traffic_status`. +The traffic status stats features is bypassed if this option is enabled. +In other words, it is excluded from the traffic status stats. +This is mostly useful if you want to ignore your request in status web page like `/status` as follows: + +```Nginx +http { + vhost_traffic_status_zone; + + ... + + server { + + ... + + location /status { + vhost_traffic_status_bypass_stats on; + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } + } +} +``` + +## See Also +* Stream traffic status + * [nginx-module-sts](https://github.com/vozlt/nginx-module-sts) + * [nginx-module-stream-sts](https://github.com/vozlt/nginx-module-stream-sts) + +* Prometheus + * [nginx-vts-exporter](https://github.com/hnlq715/nginx-vts-exporter) + +* System protection + * [nginx-module-sysguard](https://github.com/vozlt/nginx-module-sysguard) + +## TODO + +## Donation +[![License](http://img.shields.io/badge/PAYPAL-DONATE-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=PWWSYKQ9VKH38&lc=KR¤cy_code=USD&bn=PP%2dDonationsBF%3abtn_donateCC_LG%2egif%3aNonHosted) + +## Author +YoungJoo.Kim(김영주) [] diff --git a/modules/ngx_http_vts/config b/modules/ngx_http_vts/config new file mode 100644 index 0000000..07a616d --- /dev/null +++ b/modules/ngx_http_vts/config @@ -0,0 +1,49 @@ +ngx_addon_name=ngx_http_vhost_traffic_status_module +have=NGX_STAT_STUB . auto/have + +HTTP_VTS_SRCS=" \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_module.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_variables.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_string.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_shm.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_node.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_filter.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_control.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_limit.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_json.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_prometheus.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_set.c \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_dump.c \ + " + +HTTP_VTS_DEPS=" \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_module.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_variables.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_string.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_shm.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_node.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_filter.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_control.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_limit.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_json.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_display_prometheus.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_set.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_dump.h \ + $ngx_addon_dir/src/ngx_http_vhost_traffic_status_module_html.h \ + " +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=$ngx_addon_name + ngx_module_srcs="$HTTP_VTS_SRCS" + ngx_module_deps="$HTTP_VTS_DEPS" + + . auto/module +else + HTTP_MODULES="$HTTP_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $HTTP_VTS_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $HTTP_VTS_DEPS" +fi + +# vi:set ft=sh ts=4 sw=4 et fdm=marker: diff --git a/modules/ngx_http_vts/share/status.compress.html b/modules/ngx_http_vts/share/status.compress.html new file mode 100644 index 0000000..fef8510 --- /dev/null +++ b/modules/ngx_http_vts/share/status.compress.html @@ -0,0 +1 @@ +nginx vhost traffic status monitor

Nginx Vhost Traffic Status

update interval: sec
diff --git a/modules/ngx_http_vts/share/status.template.html b/modules/ngx_http_vts/share/status.template.html new file mode 100644 index 0000000..fc8df4f --- /dev/null +++ b/modules/ngx_http_vts/share/status.template.html @@ -0,0 +1,844 @@ + + + + + IronFox Traffic Status Monitor + + + + + +

+ IronFox Traffic Status +

+ +
+ +
+ update interval: + + sec +
+ + + + + + diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.c new file mode 100644 index 0000000..7b7222f --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.c @@ -0,0 +1,675 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_control.h" +#include "ngx_http_vhost_traffic_status_display_json.h" +#include "ngx_http_vhost_traffic_status_display.h" + + +static void ngx_http_vhost_traffic_status_node_status_all( + ngx_http_vhost_traffic_status_control_t *control); +static void ngx_http_vhost_traffic_status_node_status_group( + ngx_http_vhost_traffic_status_control_t *control); +static void ngx_http_vhost_traffic_status_node_status_zone( + ngx_http_vhost_traffic_status_control_t *control); + +static ngx_int_t ngx_http_vhost_traffic_status_node_delete_get_nodes( + ngx_http_vhost_traffic_status_control_t *control, + ngx_array_t **nodes, ngx_rbtree_node_t *node); +static void ngx_http_vhost_traffic_status_node_delete_all( + ngx_http_vhost_traffic_status_control_t *control); +static void ngx_http_vhost_traffic_status_node_delete_group( + ngx_http_vhost_traffic_status_control_t *control); +static void ngx_http_vhost_traffic_status_node_delete_zone( + ngx_http_vhost_traffic_status_control_t *control); + +static void ngx_http_vhost_traffic_status_node_reset_all( + ngx_http_vhost_traffic_status_control_t *control, + ngx_rbtree_node_t *node); +static void ngx_http_vhost_traffic_status_node_reset_group( + ngx_http_vhost_traffic_status_control_t *control, + ngx_rbtree_node_t *node); +static void ngx_http_vhost_traffic_status_node_reset_zone( + ngx_http_vhost_traffic_status_control_t *control); + + +void +ngx_http_vhost_traffic_status_node_upstream_lookup( + ngx_http_vhost_traffic_status_control_t *control, + ngx_http_upstream_server_t *usn) +{ + ngx_int_t rc; + ngx_str_t key, usg, ush; + ngx_uint_t i, j; + ngx_http_upstream_server_t *us; + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_get_module_main_conf(control->r, ngx_http_upstream_module); + uscfp = umcf->upstreams.elts; + + key = *control->zone; + + if (control->group == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA) { + +#if nginx_version > 1007001 + usn->name = key; +#endif + + usn->weight = 0; + usn->max_fails = 0; + usn->fail_timeout = 0; + usn->down = 0; + usn->backup = 0; + control->count++; + return; + } + + usg = ush = key; + + rc = ngx_http_vhost_traffic_status_node_position_key(&usg, 0); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, + "node_upstream_lookup::node_position_key(\"%V\", 0) group not found", &usg); + return; + } + + rc = ngx_http_vhost_traffic_status_node_position_key(&ush, 1); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, + "node_upstream_lookup::node_position_key(\"%V\", 1) host not found", &ush); + return; + } + + for (i = 0; i < umcf->upstreams.nelts; i++) { + uscf = uscfp[i]; + + /* nogroups */ + if (uscf->servers == NULL && uscf->port != 0) { + continue; + } + + us = uscf->servers->elts; + + if (uscf->host.len == usg.len) { + if (ngx_strncmp(uscf->host.data, usg.data, usg.len) == 0) { + + for (j = 0; j < uscf->servers->nelts; j++) { + if (us[j].addrs->name.len == ush.len) { + if (ngx_strncmp(us[j].addrs->name.data, ush.data, ush.len) == 0) { + *usn = us[j]; + +#if nginx_version > 1007001 + usn->name = us[j].addrs->name; +#endif + + control->count++; + break; + } + } + } + + break; + } + } + } +} + + +void +ngx_http_vhost_traffic_status_node_control_range_set( + ngx_http_vhost_traffic_status_control_t *control) +{ + ngx_uint_t state; + + if (control->group == -1) { + state = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ALL; + + } else { + state = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ZONE; + + if (control->zone->len == 0) { + state = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_NONE; + + } else if (control->zone->len == 1) { + if (ngx_strncmp(control->zone->data, "*", 1) == 0) { + state = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_GROUP; + } + } + } + + control->range = state; +} + + +static void +ngx_http_vhost_traffic_status_node_status_all( + ngx_http_vhost_traffic_status_control_t *control) +{ + *control->buf = ngx_http_vhost_traffic_status_display_set(control->r, *control->buf); +} + + +static void +ngx_http_vhost_traffic_status_node_status_group( + ngx_http_vhost_traffic_status_control_t *control) +{ + u_char *o, *s; + ngx_str_t key; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + node = ctx->rbtree->root; + + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S); + + o = s = *control->buf; + + switch(control->group) { + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO: + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_S); + s = *control->buf; + *control->buf = ngx_http_vhost_traffic_status_display_set_server( + control->r, *control->buf, node); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA: + ngx_str_set(&key, "::nogroups"); + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_S, &key); + s = *control->buf; + *control->buf = ngx_http_vhost_traffic_status_display_set_upstream_alone( + control->r, *control->buf, node); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG: + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S); + s = *control->buf; + *control->buf = ngx_http_vhost_traffic_status_display_set_upstream_group( + control->r, *control->buf); + break; + +#if (NGX_HTTP_CACHE) + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC: + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE_S); + s = *control->buf; + *control->buf = ngx_http_vhost_traffic_status_display_set_cache( + control->r, *control->buf, node); + break; +#endif + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG: + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_FILTER_S); + s = *control->buf; + *control->buf = ngx_http_vhost_traffic_status_display_set_filter( + control->r, *control->buf, node); + break; + } + + if (s == *control->buf) { + *control->buf = o; + + } else { + (*control->buf)--; + + if (control->group == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA) { + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_E); + + } else { + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + } + + control->count++; + } + + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); +} + + +static void +ngx_http_vhost_traffic_status_node_status_zone( + ngx_http_vhost_traffic_status_control_t *control) +{ + u_char *o; + uint32_t hash; + ngx_int_t rc; + ngx_str_t key, dst; + ngx_rbtree_node_t *node; + ngx_http_upstream_server_t us; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + if (control->group == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO + && control->zone->len == 6 + && ngx_strncasecmp(control->zone->data, (u_char *) "::main", 6) == 0) + { + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S); + *control->buf = ngx_http_vhost_traffic_status_display_set_main(control->r, + *control->buf); + (*control->buf)--; + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + + control->count++; + + return; + } + + rc = ngx_http_vhost_traffic_status_node_generate_key(control->r->pool, &key, control->zone, + control->group); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, + "node_status_zone::node_generate_key(\"%V\") failed", &key); + return; + } + + hash = ngx_crc32_short(key.data, key.len); + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, &key, hash); + + if (node == NULL) { + return; + } + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (control->group != NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG + && control->group != NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA) + { + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S); + + o = *control->buf; + + } else { + o = *control->buf; + } + + dst.data = vtsn->data; + dst.len = vtsn->len; + + switch (control->group) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO: + *control->buf = ngx_http_vhost_traffic_status_display_set_server_node(control->r, + *control->buf, &key, vtsn); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG: + ngx_http_vhost_traffic_status_node_upstream_lookup(control, &us); + if (control->count) { +#if nginx_version > 1007001 + *control->buf = ngx_http_vhost_traffic_status_display_set_upstream_node(control->r, + *control->buf, &us, vtsn); +#else + (void) ngx_http_vhost_traffic_status_node_position_key(&dst, 1); + *control->buf = ngx_http_vhost_traffic_status_display_set_upstream_node(control->r, + *control->buf, &us, vtsn, &dst); +#endif + } + break; + +#if (NGX_HTTP_CACHE) + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC: + *control->buf = ngx_http_vhost_traffic_status_display_set_cache_node(control->r, + *control->buf, vtsn); + break; +#endif + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG: + (void) ngx_http_vhost_traffic_status_node_position_key(&dst, 2); + *control->buf = ngx_http_vhost_traffic_status_display_set_server_node(control->r, + *control->buf, &dst, vtsn); + break; + } + + if (o != *control->buf) { + (*control->buf)--; + + if (control->group != NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG + && control->group != NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA) + { + *control->buf = ngx_sprintf(*control->buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + } + + control->count++; + } +} + + +void +ngx_http_vhost_traffic_status_node_status( + ngx_http_vhost_traffic_status_control_t *control) +{ + switch (control->range) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ALL: + ngx_http_vhost_traffic_status_node_status_all(control); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_GROUP: + ngx_http_vhost_traffic_status_node_status_group(control); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ZONE: + ngx_http_vhost_traffic_status_node_status_zone(control); + break; + } +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_node_delete_get_nodes( + ngx_http_vhost_traffic_status_control_t *control, + ngx_array_t **nodes, ngx_rbtree_node_t *node) +{ + ngx_int_t rc; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_delete_t *delete; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if ((ngx_int_t) vtsn->stat_upstream.type == control->group) { + + if (*nodes == NULL) { + *nodes = ngx_array_create(control->r->pool, 1, + sizeof(ngx_http_vhost_traffic_status_delete_t)); + + if (*nodes == NULL) { + ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, + "node_delete_get_nodes::ngx_array_create() failed"); + return NGX_ERROR; + } + } + + delete = ngx_array_push(*nodes); + if (delete == NULL) { + ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, + "node_delete_get_nodes::ngx_array_push() failed"); + return NGX_ERROR; + } + + delete->node = node; + } + + rc = ngx_http_vhost_traffic_status_node_delete_get_nodes(control, nodes, node->left); + if (rc != NGX_OK) { + return rc; + } + + rc = ngx_http_vhost_traffic_status_node_delete_get_nodes(control, nodes, node->right); + if (rc != NGX_OK) { + return rc; + } + } + + return NGX_OK; +} + + +static void +ngx_http_vhost_traffic_status_node_delete_all( + ngx_http_vhost_traffic_status_control_t *control) +{ + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node, *sentinel; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(control->r, ngx_http_vhost_traffic_status_module); + + node = ctx->rbtree->root; + sentinel = ctx->rbtree->sentinel; + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + while (node != sentinel) { + + ngx_rbtree_delete(ctx->rbtree, node); + ngx_slab_free_locked(shpool, node); + + control->count++; + + node = ctx->rbtree->root; + } +} + + +static void +ngx_http_vhost_traffic_status_node_delete_group( + ngx_http_vhost_traffic_status_control_t *control) +{ + ngx_int_t rc; + ngx_uint_t n, i; + ngx_array_t *nodes; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_delete_t *deletes; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(control->r, ngx_http_vhost_traffic_status_module); + + node = ctx->rbtree->root; + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + nodes = NULL; + + rc = ngx_http_vhost_traffic_status_node_delete_get_nodes(control, &nodes, node); + + /* not found */ + if (nodes == NULL) { + return; + } + + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, control->r->connection->log, 0, + "node_delete_group::node_delete_get_nodes() failed"); + return; + } + + deletes = nodes->elts; + n = nodes->nelts; + + for (i = 0; i < n; i++) { + node = deletes[i].node; + + ngx_rbtree_delete(ctx->rbtree, node); + ngx_slab_free_locked(shpool, node); + + control->count++; + } +} + + +static void +ngx_http_vhost_traffic_status_node_delete_zone( + ngx_http_vhost_traffic_status_control_t *control) +{ + uint32_t hash; + ngx_int_t rc; + ngx_str_t key; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(control->r, ngx_http_vhost_traffic_status_module); + + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + rc = ngx_http_vhost_traffic_status_node_generate_key(control->r->pool, &key, control->zone, + control->group); + if (rc != NGX_OK) { + return; + } + + hash = ngx_crc32_short(key.data, key.len); + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, &key, hash); + + if (node != NULL) { + ngx_rbtree_delete(ctx->rbtree, node); + ngx_slab_free_locked(shpool, node); + + control->count++; + } +} + + +void +ngx_http_vhost_traffic_status_node_delete( + ngx_http_vhost_traffic_status_control_t *control) +{ + switch (control->range) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ALL: + ngx_http_vhost_traffic_status_node_delete_all(control); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_GROUP: + ngx_http_vhost_traffic_status_node_delete_group(control); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ZONE: + ngx_http_vhost_traffic_status_node_delete_zone(control); + break; + } + + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL, + ngx_http_vhost_traffic_status_boolean_to_string(1), + control->arg_cmd, control->arg_group, + control->arg_zone, control->count); +} + + +static void +ngx_http_vhost_traffic_status_node_reset_all( + ngx_http_vhost_traffic_status_control_t *control, + ngx_rbtree_node_t *node) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + ngx_http_vhost_traffic_status_node_zero(vtsn); + control->count++; + + ngx_http_vhost_traffic_status_node_reset_all(control, node->left); + ngx_http_vhost_traffic_status_node_reset_all(control, node->right); + } +} + + +static void +ngx_http_vhost_traffic_status_node_reset_group( + ngx_http_vhost_traffic_status_control_t *control, + ngx_rbtree_node_t *node) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if ((ngx_int_t) vtsn->stat_upstream.type == control->group) { + ngx_http_vhost_traffic_status_node_zero(vtsn); + control->count++; + } + + ngx_http_vhost_traffic_status_node_reset_group(control, node->left); + ngx_http_vhost_traffic_status_node_reset_group(control, node->right); + } +} + + +static void +ngx_http_vhost_traffic_status_node_reset_zone( + ngx_http_vhost_traffic_status_control_t *control) +{ + uint32_t hash; + ngx_int_t rc; + ngx_str_t key; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + rc = ngx_http_vhost_traffic_status_node_generate_key(control->r->pool, &key, control->zone, + control->group); + if (rc != NGX_OK) { + return; + } + + hash = ngx_crc32_short(key.data, key.len); + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, &key, hash); + + if (node != NULL) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + ngx_http_vhost_traffic_status_node_zero(vtsn); + control->count++; + } +} + + +void +ngx_http_vhost_traffic_status_node_reset( + ngx_http_vhost_traffic_status_control_t *control) +{ + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = ngx_http_get_module_main_conf(control->r, ngx_http_vhost_traffic_status_module); + + node = ctx->rbtree->root; + + switch (control->range) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ALL: + ngx_http_vhost_traffic_status_node_reset_all(control, node); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_GROUP: + ngx_http_vhost_traffic_status_node_reset_group(control, node); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ZONE: + ngx_http_vhost_traffic_status_node_reset_zone(control); + break; + } + + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL, + ngx_http_vhost_traffic_status_boolean_to_string(1), + control->arg_cmd, control->arg_group, + control->arg_zone, control->count); +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.h new file mode 100644 index 0000000..1111ba5 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_control.h @@ -0,0 +1,65 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_CONTROL_H_INCLUDED_ +#define _NGX_HTTP_VTS_CONTROL_H_INCLUDED_ + + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE 0 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS 1 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_DELETE 2 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_RESET 3 + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_NONE 0 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ALL 1 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_GROUP 2 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_ZONE 3 + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL "{" \ + "\"processingReturn\":%s," \ + "\"processingCommandString\":\"%V\"," \ + "\"processingGroupString\":\"%V\"," \ + "\"processingZoneString\":\"%V\"," \ + "\"processingCounts\":%ui" \ + "}" + + +typedef struct { + ngx_rbtree_node_t *node; +} ngx_http_vhost_traffic_status_delete_t; + + +typedef struct { + ngx_http_request_t *r; + ngx_uint_t command; + ngx_int_t group; + ngx_str_t *zone; + ngx_str_t *arg_cmd; + ngx_str_t *arg_group; + ngx_str_t *arg_zone; + ngx_str_t *arg_name; + ngx_uint_t range; + ngx_uint_t count; + u_char **buf; +} ngx_http_vhost_traffic_status_control_t; + + +void ngx_http_vhost_traffic_status_node_control_range_set( + ngx_http_vhost_traffic_status_control_t *control); +void ngx_http_vhost_traffic_status_node_status( + ngx_http_vhost_traffic_status_control_t *control); +void ngx_http_vhost_traffic_status_node_delete( + ngx_http_vhost_traffic_status_control_t *control); +void ngx_http_vhost_traffic_status_node_reset( + ngx_http_vhost_traffic_status_control_t *control); + +void ngx_http_vhost_traffic_status_node_upstream_lookup( + ngx_http_vhost_traffic_status_control_t *control, + ngx_http_upstream_server_t *us); + +#endif /* _NGX_HTTP_VTS_CONTROL_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.c new file mode 100644 index 0000000..c0d106a --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.c @@ -0,0 +1,678 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module_html.h" +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_shm.h" +#include "ngx_http_vhost_traffic_status_display_prometheus.h" +#include "ngx_http_vhost_traffic_status_display_json.h" +#include "ngx_http_vhost_traffic_status_display.h" +#include "ngx_http_vhost_traffic_status_control.h" + + +static ngx_int_t ngx_http_vhost_traffic_status_display_handler(ngx_http_request_t *r); +static ngx_int_t ngx_http_vhost_traffic_status_display_handler_control(ngx_http_request_t *r); +static ngx_int_t ngx_http_vhost_traffic_status_display_handler_default(ngx_http_request_t *r); + + +static ngx_int_t +ngx_http_vhost_traffic_status_display_handler(ngx_http_request_t *r) +{ + size_t len; + u_char *p; + ngx_int_t rc; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (!ctx->enable) { + return NGX_HTTP_NOT_IMPLEMENTED; + } + + if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { + return NGX_HTTP_NOT_ALLOWED; + } + + len = 0; + + p = (u_char *) ngx_strchr(r->uri.data, '/'); + + if (p) { + p = (u_char *) ngx_strchr(p + 1, '/'); + len = r->uri.len - (p - r->uri.data); + } + + /* control processing handler */ + if (p && len >= sizeof("/control") - 1) { + p = r->uri.data + r->uri.len - sizeof("/control") + 1; + if (ngx_strncasecmp(p, (u_char *) "/control", sizeof("/control") - 1) == 0) { + rc = ngx_http_vhost_traffic_status_display_handler_control(r); + goto done; + } + } + + /* default processing handler */ + rc = ngx_http_vhost_traffic_status_display_handler_default(r); + +done: + + return rc; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_display_handler_control(ngx_http_request_t *r) +{ + ngx_int_t size, rc; + ngx_str_t type, alpha, arg_cmd, arg_group, arg_zone; + ngx_buf_t *b; + ngx_chain_t out; + ngx_slab_pool_t *shpool; + ngx_http_vhost_traffic_status_control_t *control; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + /* init control */ + control = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_control_t)); + if (control == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + control->r = r; + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE; + control->group = -2; + + control->zone = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); + if (control->zone == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + control->arg_cmd = &arg_cmd; + control->arg_group = &arg_group; + control->arg_zone = &arg_zone; + control->range = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_NONE; + control->count = 0; + + arg_cmd.len = 0; + arg_group.len = 0; + arg_zone.len = 0; + + if (r->args.len) { + + if (ngx_http_arg(r, (u_char *) "cmd", 3, &arg_cmd) == NGX_OK) { + + if (arg_cmd.len == 6 && ngx_strncmp(arg_cmd.data, "status", 6) == 0) + { + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS; + } + else if (arg_cmd.len == 6 && ngx_strncmp(arg_cmd.data, "delete", 6) == 0) + { + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_DELETE; + } + else if (arg_cmd.len == 5 && ngx_strncmp(arg_cmd.data, "reset", 5) == 0) + { + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_RESET; + } + else + { + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE; + } + } + + if (ngx_http_arg(r, (u_char *) "group", 5, &arg_group) == NGX_OK) { + + if (arg_group.len == 1 && ngx_strncmp(arg_group.data, "*", 1) == 0) + { + control->group = -1; + } + else if (arg_group.len == 6 + && ngx_strncasecmp(arg_group.data, (u_char *) "server", 6) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + } + else if (arg_group.len == 14 + && ngx_strncasecmp(arg_group.data, (u_char *) "upstream@alone", 14) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA; + } + else if (arg_group.len == 14 + && ngx_strncasecmp(arg_group.data, (u_char *) "upstream@group", 14) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG; + } + else if (arg_group.len == 5 + && ngx_strncasecmp(arg_group.data, (u_char *) "cache", 5) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC; + } + else if (arg_group.len == 6 + && ngx_strncasecmp(arg_group.data, (u_char *) "filter", 6) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG; + } + else { + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE; + } + } + + if (ngx_http_arg(r, (u_char *) "zone", 4, &arg_zone) != NGX_OK) { + if (control->group != -1) { + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE; + } + + } else { + rc = ngx_http_vhost_traffic_status_copy_str(r->pool, control->zone, &arg_zone); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_control::copy_str() failed"); + } + + (void) ngx_http_vhost_traffic_status_replace_chrc(control->zone, '@', + NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR); + + ngx_str_set(&alpha, "[:alpha:]"); + + rc = ngx_http_vhost_traffic_status_replace_strc(control->zone, &alpha, '@'); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_control::replace_strc() failed"); + } + } + + ngx_http_vhost_traffic_status_node_control_range_set(control); + } + + if (control->command == NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS) { + size = ngx_http_vhost_traffic_status_display_get_size(r, + NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON); + if (size == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_control::display_get_size() failed"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + } else { + size = sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL) + + arg_cmd.len + arg_group.len + arg_zone.len + ngx_pagesize; + } + + ngx_str_set(&type, "application/json"); + + r->headers_out.content_type_len = type.len; + r->headers_out.content_type = type; + + if (r->method == NGX_HTTP_HEAD) { + r->headers_out.status = NGX_HTTP_OK; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + } + + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + control->buf = &b->last; + + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + switch (control->command) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS: + ngx_http_vhost_traffic_status_node_status(control); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_DELETE: + ngx_http_vhost_traffic_status_node_delete(control); + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_RESET: + ngx_http_vhost_traffic_status_node_reset(control); + break; + + default: + *control->buf = ngx_sprintf(*control->buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CONTROL, + ngx_http_vhost_traffic_status_boolean_to_string(0), + control->arg_cmd, control->arg_group, + control->arg_zone, control->count); + break; + } + + ngx_shmtx_unlock(&shpool->mutex); + + if (b->last == b->pos) { + b->last = ngx_sprintf(b->last, "{}"); + } + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = b->last - b->pos; + + b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */ + b->last_in_chain = 1; + + out.buf = b; + out.next = NULL; + + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + return ngx_http_output_filter(r, &out); +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_display_handler_default(ngx_http_request_t *r) +{ + size_t len; + u_char *o, *s; + ngx_str_t uri, type; + ngx_int_t size, format, rc; + ngx_buf_t *b; + ngx_chain_t out; + ngx_slab_pool_t *shpool; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (!ctx->enable) { + return NGX_HTTP_NOT_IMPLEMENTED; + } + + if (r->method != NGX_HTTP_GET && r->method != NGX_HTTP_HEAD) { + return NGX_HTTP_NOT_ALLOWED; + } + + uri = r->uri; + + format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE; + + if (uri.len == 1) { + if (ngx_strncmp(uri.data, "/", 1) == 0) { + uri.len = 0; + } + } + + o = (u_char *) r->uri.data; + s = o; + + len = r->uri.len; + + while(sizeof("/format/type") - 1 <= len) { + if (ngx_strncasecmp(s, (u_char *) "/format/", sizeof("/format/") - 1) == 0) { + uri.data = o; + uri.len = (o == s) ? 0 : (size_t) (s - o); + + s += sizeof("/format/") - 1; + + if (ngx_strncasecmp(s, (u_char *) "jsonp", sizeof("jsonp") - 1) == 0) { + format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP; + + } else if (ngx_strncasecmp(s, (u_char *) "json", sizeof("json") - 1) == 0) { + format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON; + + } else if (ngx_strncasecmp(s, (u_char *) "html", sizeof("html") - 1) == 0) { + format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_HTML; + + } else if (ngx_strncasecmp(s, (u_char *) "prometheus", sizeof("prometheus") - 1) == 0) { + format = NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS; + + } else { + s -= 2; + } + + if (format != NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE) { + break; + } + } + + if ((s = (u_char *) ngx_strchr(++s, '/')) == NULL) { + break; + } + + if (r->uri.len <= (size_t) (s - o)) { + break; + } + + len = r->uri.len - (size_t) (s - o); + } + + format = (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE) ? vtscf->format : format; + + rc = ngx_http_discard_request_body(r); + if (rc != NGX_OK) { + return rc; + } + + if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON) { + ngx_str_set(&type, "application/json"); + + } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP) { + ngx_str_set(&type, "application/javascript"); + + } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS) { + ngx_str_set(&type, "text/plain"); + + } else { + ngx_str_set(&type, "text/html"); + } + + r->headers_out.content_type_len = type.len; + r->headers_out.content_type = type; + + if (r->method == NGX_HTTP_HEAD) { + r->headers_out.status = NGX_HTTP_OK; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + } + + size = ngx_http_vhost_traffic_status_display_get_size(r, format); + if (size == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_default::display_get_size() failed"); + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + b = ngx_create_temp_buf(r->pool, size); + if (b == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON) { + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + ngx_shmtx_lock(&shpool->mutex); + b->last = ngx_http_vhost_traffic_status_display_set(r, b->last); + ngx_shmtx_unlock(&shpool->mutex); + + if (b->last == b->pos) { + b->last = ngx_sprintf(b->last, "{}"); + } + + } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP) { + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + ngx_shmtx_lock(&shpool->mutex); + b->last = ngx_sprintf(b->last, "%V", &vtscf->jsonp); + b->last = ngx_sprintf(b->last, "("); + b->last = ngx_http_vhost_traffic_status_display_set(r, b->last); + b->last = ngx_sprintf(b->last, ")"); + ngx_shmtx_unlock(&shpool->mutex); + + } else if (format == NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS) { + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + ngx_shmtx_lock(&shpool->mutex); + b->last = ngx_http_vhost_traffic_status_display_prometheus_set(r, b->last); + ngx_shmtx_unlock(&shpool->mutex); + + if (b->last == b->pos) { + b->last = ngx_sprintf(b->last, "#"); + } + + } + else { + b->last = ngx_sprintf(b->last, NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA, &uri, &uri); + } + + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_length_n = b->last - b->pos; + + b->last_buf = (r == r->main) ? 1 : 0; /* if subrequest 0 else 1 */ + b->last_in_chain = 1; + + out.buf = b; + out.next = NULL; + + rc = ngx_http_send_header(r); + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + + return ngx_http_output_filter(r, &out); +} + + +ngx_int_t +ngx_http_vhost_traffic_status_display_get_upstream_nelts(ngx_http_request_t *r) +{ + ngx_uint_t i, j, n; + ngx_http_upstream_server_t *us; +#if (NGX_HTTP_UPSTREAM_ZONE) + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; +#endif + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + uscfp = umcf->upstreams.elts; + + for (i = 0, j = 0, n = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + /* groups */ + if (uscf->servers && !uscf->port) { + us = uscf->servers->elts; + +#if (NGX_HTTP_UPSTREAM_ZONE) + if (uscf->shm_zone == NULL) { + goto not_supported; + } + + peers = uscf->peer.data; + + ngx_http_upstream_rr_peers_rlock(peers); + + for (peer = peers->peer; peer; peer = peer->next) { + n++; + } + + ngx_http_upstream_rr_peers_unlock(peers); + +not_supported: + +#endif + + for (j = 0; j < uscf->servers->nelts; j++) { + n += us[j].naddrs; + } + } + } + + return n; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_display_get_size(ngx_http_request_t *r, + ngx_int_t format) +{ + ngx_uint_t size, un; + ngx_http_vhost_traffic_status_shm_info_t *shm_info; + + shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + if (shm_info == NULL) { + return NGX_ERROR; + } + + ngx_http_vhost_traffic_status_shm_info(r, shm_info); + + /* allocate memory for the upstream groups even if upstream node not exists */ + un = shm_info->used_node + + (ngx_uint_t) ngx_http_vhost_traffic_status_display_get_upstream_nelts(r); + + size = 0; + + switch (format) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS: + size = sizeof(ngx_http_vhost_traffic_status_node_t) / NGX_PTR_SIZE + * NGX_ATOMIC_T_LEN * un /* values size */ + + (un * 1024) /* names size */ + + 4096; /* main size */ + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_HTML: + size = sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA) + ngx_pagesize; + break; + } + + if (size <= 0) { + size = shm_info->max_size; + } + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "vts::display_get_size(): size[%ui] used_size[%ui], used_node[%ui]", + size, shm_info->used_size, shm_info->used_node); + + return size; +} + + +u_char * +ngx_http_vhost_traffic_status_display_get_time_queue( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_uint_t offset) +{ + u_char *p, *s; + ngx_int_t i; + + if (q->front == q->rear) { + return (u_char *) ""; + } + + p = ngx_pcalloc(r->pool, q->len * NGX_INT_T_LEN); + if (p == NULL) { + return (u_char *) ""; + } + + s = p; + + for (i = q->front; i != q->rear; i = (i + 1) % q->len) { + s = ngx_sprintf(s, "%M,", *((ngx_msec_t *) ((char *) &(q->times[i]) + offset))); + } + + if (s > p) { + *(s - 1) = '\0'; + } + + return p; +} + + +u_char * +ngx_http_vhost_traffic_status_display_get_time_queue_times( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_time_queue_t *q) +{ + return ngx_http_vhost_traffic_status_display_get_time_queue(r, q, + offsetof(ngx_http_vhost_traffic_status_node_time_t, time)); +} + + +u_char * +ngx_http_vhost_traffic_status_display_get_time_queue_msecs( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_time_queue_t *q) +{ + return ngx_http_vhost_traffic_status_display_get_time_queue(r, q, + offsetof(ngx_http_vhost_traffic_status_node_time_t, msec)); +} + + +u_char * +ngx_http_vhost_traffic_status_display_get_histogram_bucket( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b, + ngx_uint_t offset, + const char *fmt) +{ + char *dst; + u_char *p, *s; + ngx_uint_t i, n; + + n = b->len; + + if (n == 0) { + return (u_char *) ""; + } + + p = ngx_pcalloc(r->pool, n * NGX_INT_T_LEN); + if (p == NULL) { + return (u_char *) ""; + } + + s = p; + + for (i = 0; i < n; i++) { + dst = (char *) &(b->buckets[i]) + offset; + + if (ngx_strncmp(fmt, "%M", 2) == 0) { + s = ngx_sprintf(s, fmt, *((ngx_msec_t *) dst)); + + } else if (ngx_strncmp(fmt, "%uA", 3) == 0) { + s = ngx_sprintf(s, fmt, *((ngx_atomic_uint_t *) dst)); + } + } + + if (s > p) { + *(s - 1) = '\0'; + } + + return p; +} + + +u_char * +ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b) +{ + return ngx_http_vhost_traffic_status_display_get_histogram_bucket(r, b, + offsetof(ngx_http_vhost_traffic_status_node_histogram_t, msec), "%M,"); +} + + +u_char * +ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b) +{ + return ngx_http_vhost_traffic_status_display_get_histogram_bucket(r, b, + offsetof(ngx_http_vhost_traffic_status_node_histogram_t, counter), "%uA,"); +} + + +char * +ngx_http_vhost_traffic_status_display(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_core_loc_conf_t *clcf; + + clcf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_core_module); + clcf->handler = ngx_http_vhost_traffic_status_display_handler; + + return NGX_CONF_OK; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.h new file mode 100644 index 0000000..d707823 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display.h @@ -0,0 +1,46 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_DISPLAY_H_INCLUDED_ +#define _NGX_HTTP_VTS_DISPLAY_H_INCLUDED_ + + +ngx_int_t ngx_http_vhost_traffic_status_display_get_upstream_nelts( + ngx_http_request_t *r); +ngx_int_t ngx_http_vhost_traffic_status_display_get_size( + ngx_http_request_t *r, ngx_int_t format); + +u_char *ngx_http_vhost_traffic_status_display_get_time_queue( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_uint_t offset); +u_char *ngx_http_vhost_traffic_status_display_get_time_queue_times( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_time_queue_t *q); +u_char *ngx_http_vhost_traffic_status_display_get_time_queue_msecs( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_time_queue_t *q); + +u_char *ngx_http_vhost_traffic_status_display_get_histogram_bucket( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b, + ngx_uint_t offset, const char *fmt); +u_char *ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b); +u_char *ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *q); + + + +char *ngx_http_vhost_traffic_status_display(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +#endif /* _NGX_HTTP_VTS_DISPLAY_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.c new file mode 100644 index 0000000..1f2ce2f --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.c @@ -0,0 +1,875 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_shm.h" +#include "ngx_http_vhost_traffic_status_filter.h" +#include "ngx_http_vhost_traffic_status_display_json.h" +#include "ngx_http_vhost_traffic_status_display.h" + + +u_char * +ngx_http_vhost_traffic_status_display_set_main(ngx_http_request_t *r, + u_char *buf) +{ + ngx_atomic_int_t ap, hn, ac, rq, rd, wr, wa; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_shm_info_t *shm_info; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + ap = *ngx_stat_accepted; + hn = *ngx_stat_handled; + ac = *ngx_stat_active; + rq = *ngx_stat_requests; + rd = *ngx_stat_reading; + wr = *ngx_stat_writing; + wa = *ngx_stat_waiting; + + shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + if (shm_info == NULL) { + return buf; + } + + ngx_http_vhost_traffic_status_shm_info(r, shm_info); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_MAIN, &ngx_cycle->hostname, + NGINX_VERSION, vtscf->start_msec, ngx_http_vhost_traffic_status_current_msec(), + ac, rd, wr, wa, ap, hn, rq, + shm_info->name, shm_info->max_size, + shm_info->used_size, shm_info->used_node); + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_server_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_int_t rc; + ngx_str_t tmp, dst; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + tmp = *key; + + (void) ngx_http_vhost_traffic_status_node_position_key(&tmp, 1); + + rc = ngx_http_vhost_traffic_status_escape_json_pool(r->pool, &dst, &tmp); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_set_server_node::escape_json_pool() failed"); + } + +#if (NGX_HTTP_CACHE) + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER, + &dst, vtsn->stat_request_counter, + vtsn->stat_in_bytes, + vtsn->stat_out_bytes, + vtsn->stat_1xx_counter, + vtsn->stat_2xx_counter, + vtsn->stat_3xx_counter, + vtsn->stat_4xx_counter, + vtsn->stat_5xx_counter, + vtsn->stat_cache_miss_counter, + vtsn->stat_cache_bypass_counter, + vtsn->stat_cache_expired_counter, + vtsn->stat_cache_stale_counter, + vtsn->stat_cache_updating_counter, + vtsn->stat_cache_revalidated_counter, + vtsn->stat_cache_hit_counter, + vtsn->stat_cache_scarce_counter, + vtsn->stat_request_time_counter, + ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period), + ngx_http_vhost_traffic_status_display_get_time_queue_times(r, + &vtsn->stat_request_times), + ngx_http_vhost_traffic_status_display_get_time_queue_msecs(r, + &vtsn->stat_request_times), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs(r, + &vtsn->stat_request_buckets), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters(r, + &vtsn->stat_request_buckets), + ngx_http_vhost_traffic_status_max_integer, + vtsn->stat_request_counter_oc, + vtsn->stat_in_bytes_oc, + vtsn->stat_out_bytes_oc, + vtsn->stat_1xx_counter_oc, + vtsn->stat_2xx_counter_oc, + vtsn->stat_3xx_counter_oc, + vtsn->stat_4xx_counter_oc, + vtsn->stat_5xx_counter_oc, + vtsn->stat_cache_miss_counter_oc, + vtsn->stat_cache_bypass_counter_oc, + vtsn->stat_cache_expired_counter_oc, + vtsn->stat_cache_stale_counter_oc, + vtsn->stat_cache_updating_counter_oc, + vtsn->stat_cache_revalidated_counter_oc, + vtsn->stat_cache_hit_counter_oc, + vtsn->stat_cache_scarce_counter_oc, + vtsn->stat_request_time_counter_oc); +#else + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER, + key, vtsn->stat_request_counter, + vtsn->stat_in_bytes, + vtsn->stat_out_bytes, + vtsn->stat_1xx_counter, + vtsn->stat_2xx_counter, + vtsn->stat_3xx_counter, + vtsn->stat_4xx_counter, + vtsn->stat_5xx_counter, + vtsn->stat_request_time_counter, + ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period), + ngx_http_vhost_traffic_status_display_get_time_queue_times(r, + &vtsn->stat_request_times), + ngx_http_vhost_traffic_status_display_get_time_queue_msecs(r, + &vtsn->stat_request_times), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs(r, + &vtsn->stat_request_buckets), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters(r, + &vtsn->stat_request_buckets), + ngx_http_vhost_traffic_status_max_integer, + vtsn->stat_request_counter_oc, + vtsn->stat_in_bytes_oc, + vtsn->stat_out_bytes_oc, + vtsn->stat_1xx_counter_oc, + vtsn->stat_2xx_counter_oc, + vtsn->stat_3xx_counter_oc, + vtsn->stat_4xx_counter_oc, + vtsn->stat_5xx_counter_oc, + vtsn->stat_request_time_counter_oc); +#endif + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_server(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn, ovtsn; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO) { + key.data = vtsn->data; + key.len = vtsn->len; + + ovtsn = vtscf->stats; + + buf = ngx_http_vhost_traffic_status_display_set_server_node(r, buf, &key, vtsn); + + /* calculates the sum */ + vtscf->stats.stat_request_counter += vtsn->stat_request_counter; + vtscf->stats.stat_in_bytes += vtsn->stat_in_bytes; + vtscf->stats.stat_out_bytes += vtsn->stat_out_bytes; + vtscf->stats.stat_1xx_counter += vtsn->stat_1xx_counter; + vtscf->stats.stat_2xx_counter += vtsn->stat_2xx_counter; + vtscf->stats.stat_3xx_counter += vtsn->stat_3xx_counter; + vtscf->stats.stat_4xx_counter += vtsn->stat_4xx_counter; + vtscf->stats.stat_5xx_counter += vtsn->stat_5xx_counter; + vtscf->stats.stat_request_time_counter += vtsn->stat_request_time_counter; + ngx_http_vhost_traffic_status_node_time_queue_merge( + &vtscf->stats.stat_request_times, + &vtsn->stat_request_times, vtscf->average_period); + + vtscf->stats.stat_request_counter_oc += vtsn->stat_request_counter_oc; + vtscf->stats.stat_in_bytes_oc += vtsn->stat_in_bytes_oc; + vtscf->stats.stat_out_bytes_oc += vtsn->stat_out_bytes_oc; + vtscf->stats.stat_1xx_counter_oc += vtsn->stat_1xx_counter_oc; + vtscf->stats.stat_2xx_counter_oc += vtsn->stat_2xx_counter_oc; + vtscf->stats.stat_3xx_counter_oc += vtsn->stat_3xx_counter_oc; + vtscf->stats.stat_4xx_counter_oc += vtsn->stat_4xx_counter_oc; + vtscf->stats.stat_5xx_counter_oc += vtsn->stat_5xx_counter_oc; + vtscf->stats.stat_request_time_counter_oc += vtsn->stat_request_time_counter_oc; + +#if (NGX_HTTP_CACHE) + vtscf->stats.stat_cache_miss_counter += + vtsn->stat_cache_miss_counter; + vtscf->stats.stat_cache_bypass_counter += + vtsn->stat_cache_bypass_counter; + vtscf->stats.stat_cache_expired_counter += + vtsn->stat_cache_expired_counter; + vtscf->stats.stat_cache_stale_counter += + vtsn->stat_cache_stale_counter; + vtscf->stats.stat_cache_updating_counter += + vtsn->stat_cache_updating_counter; + vtscf->stats.stat_cache_revalidated_counter += + vtsn->stat_cache_revalidated_counter; + vtscf->stats.stat_cache_hit_counter += + vtsn->stat_cache_hit_counter; + vtscf->stats.stat_cache_scarce_counter += + vtsn->stat_cache_scarce_counter; + + vtscf->stats.stat_cache_miss_counter_oc += + vtsn->stat_cache_miss_counter_oc; + vtscf->stats.stat_cache_bypass_counter_oc += + vtsn->stat_cache_bypass_counter_oc; + vtscf->stats.stat_cache_expired_counter_oc += + vtsn->stat_cache_expired_counter_oc; + vtscf->stats.stat_cache_stale_counter_oc += + vtsn->stat_cache_stale_counter_oc; + vtscf->stats.stat_cache_updating_counter_oc += + vtsn->stat_cache_updating_counter_oc; + vtscf->stats.stat_cache_revalidated_counter_oc += + vtsn->stat_cache_revalidated_counter_oc; + vtscf->stats.stat_cache_hit_counter_oc += + vtsn->stat_cache_hit_counter_oc; + vtscf->stats.stat_cache_scarce_counter_oc += + vtsn->stat_cache_scarce_counter_oc; +#endif + + ngx_http_vhost_traffic_status_add_oc((&ovtsn), (&vtscf->stats)); + } + + buf = ngx_http_vhost_traffic_status_display_set_server(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_set_server(r, buf, node->right); + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_filter_node(ngx_http_request_t *r, + u_char *buf, ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_str_t key; + + key.data = vtsn->data; + key.len = vtsn->len; + + (void) ngx_http_vhost_traffic_status_node_position_key(&key, 2); + + return ngx_http_vhost_traffic_status_display_set_server_node(r, buf, &key, vtsn); +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_filter(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_str_t key, filter; + ngx_uint_t i, j, n, rc; + ngx_array_t *filter_keys, *filter_nodes; + ngx_http_vhost_traffic_status_filter_key_t *keys; + ngx_http_vhost_traffic_status_filter_node_t *nodes; + + /* init array */ + filter_keys = NULL; + filter_nodes = NULL; + + rc = ngx_http_vhost_traffic_status_filter_get_keys(r, &filter_keys, node); + + if (filter_keys != NULL && rc == NGX_OK) { + keys = filter_keys->elts; + n = filter_keys->nelts; + + if (n > 1) { + ngx_qsort(keys, (size_t) n, + sizeof(ngx_http_vhost_traffic_status_filter_key_t), + ngx_http_traffic_status_filter_cmp_keys); + } + + ngx_memzero(&key, sizeof(ngx_str_t)); + + for (i = 0; i < n; i++) { + if (keys[i].key.len == key.len) { + if (ngx_strncmp(keys[i].key.data, key.data, key.len) == 0) { + continue; + } + } + key = keys[i].key; + + rc = ngx_http_vhost_traffic_status_filter_get_nodes(r, &filter_nodes, &key, node); + + if (filter_nodes != NULL && rc == NGX_OK) { + rc = ngx_http_vhost_traffic_status_escape_json_pool(r->pool, &filter, &keys[i].key); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_set_filter::escape_json_pool() failed"); + } + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_OBJECT_S, + &filter); + + nodes = filter_nodes->elts; + for (j = 0; j < filter_nodes->nelts; j++) { + buf = ngx_http_vhost_traffic_status_display_set_filter_node(r, buf, + nodes[j].node); + } + + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_OBJECT_E); + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT); + + /* destory array to prevent duplication */ + if (filter_nodes != NULL) { + filter_nodes = NULL; + } + } + + } + + /* destory array */ + for (i = 0; i < n; i++) { + if (keys[i].key.data != NULL) { + ngx_pfree(r->pool, keys[i].key.data); + } + } + if (filter_keys != NULL) { + filter_keys = NULL; + } + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_upstream_node(ngx_http_request_t *r, + u_char *buf, ngx_http_upstream_server_t *us, +#if nginx_version > 1007001 + ngx_http_vhost_traffic_status_node_t *vtsn +#else + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_str_t *name +#endif + ) +{ + ngx_int_t rc; + ngx_str_t key; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + +#if nginx_version > 1007001 + rc = ngx_http_vhost_traffic_status_escape_json_pool(r->pool, &key, &us->name); +#else + rc = ngx_http_vhost_traffic_status_escape_json_pool(r->pool, &key, name); +#endif + + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_set_upstream_node::escape_json_pool() failed"); + } + + if (vtsn != NULL) { + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM, + &key, vtsn->stat_request_counter, + vtsn->stat_in_bytes, vtsn->stat_out_bytes, + vtsn->stat_1xx_counter, vtsn->stat_2xx_counter, + vtsn->stat_3xx_counter, vtsn->stat_4xx_counter, + vtsn->stat_5xx_counter, + vtsn->stat_request_time_counter, + ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period), + ngx_http_vhost_traffic_status_display_get_time_queue_times(r, + &vtsn->stat_request_times), + ngx_http_vhost_traffic_status_display_get_time_queue_msecs(r, + &vtsn->stat_request_times), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs(r, + &vtsn->stat_request_buckets), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters(r, + &vtsn->stat_request_buckets), + vtsn->stat_upstream.response_time_counter, + ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_upstream.response_times, vtscf->average_method, + vtscf->average_period), + ngx_http_vhost_traffic_status_display_get_time_queue_times(r, + &vtsn->stat_upstream.response_times), + ngx_http_vhost_traffic_status_display_get_time_queue_msecs(r, + &vtsn->stat_upstream.response_times), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_msecs(r, + &vtsn->stat_upstream.response_buckets), + ngx_http_vhost_traffic_status_display_get_histogram_bucket_counters(r, + &vtsn->stat_upstream.response_buckets), + us->weight, us->max_fails, + us->fail_timeout, + ngx_http_vhost_traffic_status_boolean_to_string(us->backup), + ngx_http_vhost_traffic_status_boolean_to_string(us->down), + ngx_http_vhost_traffic_status_max_integer, + vtsn->stat_request_counter_oc, vtsn->stat_in_bytes_oc, + vtsn->stat_out_bytes_oc, vtsn->stat_1xx_counter_oc, + vtsn->stat_2xx_counter_oc, vtsn->stat_3xx_counter_oc, + vtsn->stat_4xx_counter_oc, vtsn->stat_5xx_counter_oc, + vtsn->stat_request_time_counter_oc, vtsn->stat_response_time_counter_oc); + + } else { + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM, + &key, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, + (ngx_msec_t) 0, + (u_char *) "", (u_char *) "", + (u_char *) "", (u_char *) "", + (ngx_atomic_uint_t) 0, + (ngx_msec_t) 0, + (u_char *) "", (u_char *) "", + (u_char *) "", (u_char *) "", + us->weight, us->max_fails, + us->fail_timeout, + ngx_http_vhost_traffic_status_boolean_to_string(us->backup), + ngx_http_vhost_traffic_status_boolean_to_string(us->down), + ngx_http_vhost_traffic_status_max_integer, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0, + (ngx_atomic_uint_t) 0, (ngx_atomic_uint_t) 0); + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_upstream_alone(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + unsigned type; + ngx_str_t key; + ngx_http_upstream_server_t us; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA; + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == type) { + key.len = vtsn->len; + key.data = vtsn->data; + + (void) ngx_http_vhost_traffic_status_node_position_key(&key, 1); + +#if nginx_version > 1007001 + us.name = key; +#endif + us.weight = 0; + us.max_fails = 0; + us.fail_timeout = 0; + us.down = 0; + us.backup = 0; + +#if nginx_version > 1007001 + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &us, vtsn); +#else + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &us, vtsn, &key); +#endif + } + + buf = ngx_http_vhost_traffic_status_display_set_upstream_alone(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_set_upstream_alone(r, buf, node->right); + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_upstream_group(ngx_http_request_t *r, + u_char *buf) +{ + size_t len; + u_char *p, *o, *s; + uint32_t hash; + unsigned type, zone; + ngx_int_t rc; + ngx_str_t key, dst; + ngx_uint_t i, j, k; + ngx_rbtree_node_t *node; + ngx_http_upstream_server_t *us, usn; +#if (NGX_HTTP_UPSTREAM_ZONE) + ngx_http_upstream_rr_peer_t *peer; + ngx_http_upstream_rr_peers_t *peers; +#endif + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + uscfp = umcf->upstreams.elts; + + len = 0; + for (i = 0; i < umcf->upstreams.nelts; i++) { + uscf = uscfp[i]; + len = ngx_max(uscf->host.len, len); + } + + dst.len = len + sizeof("@[ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255]:65535") - 1; + dst.data = ngx_pnalloc(r->pool, dst.len); + if (dst.data == NULL) { + return buf; + } + + p = dst.data; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + /* groups */ + if (uscf->servers && !uscf->port) { + us = uscf->servers->elts; + + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG; + + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_S, + &uscf->host); + s = buf; + + zone = 0; + +#if (NGX_HTTP_UPSTREAM_ZONE) + if (uscf->shm_zone == NULL) { + goto not_supported; + } + + zone = 1; + + peers = uscf->peer.data; + + ngx_http_upstream_rr_peers_rlock(peers); + + for (peer = peers->peer; peer; peer = peer->next) { + p = ngx_cpymem(p, uscf->host.data, uscf->host.len); + *p++ = NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR; + p = ngx_cpymem(p, peer->name.data, peer->name.len); + + dst.len = uscf->host.len + sizeof("@") - 1 + peer->name.len; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type); + if (rc != NGX_OK) { + ngx_http_upstream_rr_peers_unlock(peers); + return buf; + } + + hash = ngx_crc32_short(key.data, key.len); + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, &key, hash); + + usn.weight = peer->weight; + usn.max_fails = peer->max_fails; + usn.fail_timeout = peer->fail_timeout; + usn.backup = 0; + usn.down = (peer->fails >= peer->max_fails || peer->down); + +#if nginx_version > 1007001 + usn.name = peer->name; +#endif + + if (node != NULL) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; +#if nginx_version > 1007001 + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, vtsn); +#else + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, vtsn, &peer->name); +#endif + + } else { +#if nginx_version > 1007001 + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, NULL); +#else + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, NULL, &peer->name); +#endif + } + + p = dst.data; + } + + ngx_http_upstream_rr_peers_unlock(peers); + +not_supported: + +#endif + + for (j = 0; j < uscf->servers->nelts; j++) { + usn = us[j]; + + if (zone && usn.backup != 1) { + continue; + } + + /* for all A records */ + for (k = 0; k < usn.naddrs; k++) { + p = ngx_cpymem(p, uscf->host.data, uscf->host.len); + *p++ = NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR; + p = ngx_cpymem(p, usn.addrs[k].name.data, usn.addrs[k].name.len); + + dst.len = uscf->host.len + sizeof("@") - 1 + usn.addrs[k].name.len; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type); + if (rc != NGX_OK) { + return buf; + } + + hash = ngx_crc32_short(key.data, key.len); + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, &key, hash); + +#if nginx_version > 1007001 + usn.name = usn.addrs[k].name; +#endif + + if (node != NULL) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; +#if nginx_version > 1007001 + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, vtsn); +#else + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, vtsn, &usn.addrs[k].name); +#endif + + } else { +#if nginx_version > 1007001 + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, NULL); +#else + buf = ngx_http_vhost_traffic_status_display_set_upstream_node(r, buf, &usn, NULL, &usn.addrs[k].name); +#endif + } + + p = dst.data; + } + } + + if (s == buf) { + buf = o; + + } else { + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_E); + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT); + } + } + } + + /* alones */ + o = buf; + + ngx_str_set(&key, "::nogroups"); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_S, &key); + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_set_upstream_alone(r, buf, ctx->rbtree->root); + + if (s == buf) { + buf = o; + + } else { + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_E); + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT); + } + + return buf; +} + + +#if (NGX_HTTP_CACHE) + +u_char +*ngx_http_vhost_traffic_status_display_set_cache_node(ngx_http_request_t *r, + u_char *buf, ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_int_t rc; + ngx_str_t key, dst; + + dst.data = vtsn->data; + dst.len = vtsn->len; + + (void) ngx_http_vhost_traffic_status_node_position_key(&dst, 1); + + rc = ngx_http_vhost_traffic_status_escape_json_pool(r->pool, &key, &dst); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_set_cache_node::escape_json_pool() failed"); + } + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE, + &key, vtsn->stat_cache_max_size, + vtsn->stat_cache_used_size, + vtsn->stat_in_bytes, + vtsn->stat_out_bytes, + vtsn->stat_cache_miss_counter, + vtsn->stat_cache_bypass_counter, + vtsn->stat_cache_expired_counter, + vtsn->stat_cache_stale_counter, + vtsn->stat_cache_updating_counter, + vtsn->stat_cache_revalidated_counter, + vtsn->stat_cache_hit_counter, + vtsn->stat_cache_scarce_counter, + ngx_http_vhost_traffic_status_max_integer, + vtsn->stat_request_counter_oc, + vtsn->stat_in_bytes_oc, + vtsn->stat_out_bytes_oc, + vtsn->stat_1xx_counter_oc, + vtsn->stat_2xx_counter_oc, + vtsn->stat_3xx_counter_oc, + vtsn->stat_4xx_counter_oc, + vtsn->stat_5xx_counter_oc, + vtsn->stat_cache_miss_counter_oc, + vtsn->stat_cache_bypass_counter_oc, + vtsn->stat_cache_expired_counter_oc, + vtsn->stat_cache_stale_counter_oc, + vtsn->stat_cache_updating_counter_oc, + vtsn->stat_cache_revalidated_counter_oc, + vtsn->stat_cache_hit_counter_oc, + vtsn->stat_cache_scarce_counter_oc); + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_set_cache(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC) { + buf = ngx_http_vhost_traffic_status_display_set_cache_node(r, buf, vtsn); + } + + buf = ngx_http_vhost_traffic_status_display_set_cache(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_set_cache(r, buf, node->right); + } + + return buf; +} + +#endif + + +u_char * +ngx_http_vhost_traffic_status_display_set(ngx_http_request_t *r, + u_char *buf) +{ + u_char *o, *s; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + node = ctx->rbtree->root; + + /* init stats */ + ngx_memzero(&vtscf->stats, sizeof(vtscf->stats)); + ngx_http_vhost_traffic_status_node_time_queue_init(&vtscf->stats.stat_request_times); + + /* main & connections */ + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S); + + buf = ngx_http_vhost_traffic_status_display_set_main(r, buf); + + /* serverZones */ + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_S); + + buf = ngx_http_vhost_traffic_status_display_set_server(r, buf, node); + + buf = ngx_http_vhost_traffic_status_display_set_server_node(r, buf, &vtscf->sum_key, + &vtscf->stats); + + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT); + + /* filterZones */ + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_FILTER_S); + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_set_filter(r, buf, node); + + if (s == buf) { + buf = o; + + } else { + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT); + } + + /* upstreamZones */ + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S); + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_set_upstream_group(r, buf); + + if (s == buf) { + buf = o; + buf--; + + } else { + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + } + +#if (NGX_HTTP_CACHE) + /* cacheZones */ + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT); + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE_S); + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_set_cache(r, buf, node); + + if (s == buf) { + buf = o; + + } else { + buf--; + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + } +#endif + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E); + + return buf; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.h new file mode 100644 index 0000000..ffbf39c --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_json.h @@ -0,0 +1,262 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_DISPLAY_JSON_H_INCLUDED_ +#define _NGX_HTTP_VTS_DISPLAY_JSON_H_INCLUDED_ + + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_S "{" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_OBJECT_S "\"%V\":{" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_S "\"%V\":[" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_ARRAY_E "]" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_OBJECT_E "}" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_E "}" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_NEXT "," + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_MAIN "\"hostName\":\"%V\"," \ + "\"nginxVersion\":\"%s\"," \ + "\"loadMsec\":%M," \ + "\"nowMsec\":%M," \ + "\"connections\":{" \ + "\"active\":%uA," \ + "\"reading\":%uA," \ + "\"writing\":%uA," \ + "\"waiting\":%uA," \ + "\"accepted\":%uA," \ + "\"handled\":%uA," \ + "\"requests\":%uA" \ + "}," \ + "\"sharedZones\":{" \ + "\"name\":\"%V\"," \ + "\"maxSize\":%ui," \ + "\"usedSize\":%ui," \ + "\"usedNode\":%ui" \ + "}," + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER_S "\"serverZones\":{" + +#if (NGX_HTTP_CACHE) +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER "\"%V\":{" \ + "\"requestCounter\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"responses\":{" \ + "\"1xx\":%uA," \ + "\"2xx\":%uA," \ + "\"3xx\":%uA," \ + "\"4xx\":%uA," \ + "\"5xx\":%uA," \ + "\"miss\":%uA," \ + "\"bypass\":%uA," \ + "\"expired\":%uA," \ + "\"stale\":%uA," \ + "\"updating\":%uA," \ + "\"revalidated\":%uA," \ + "\"hit\":%uA," \ + "\"scarce\":%uA" \ + "}," \ + "\"requestMsecCounter\":%uA," \ + "\"requestMsec\":%M," \ + "\"requestMsecs\":{" \ + "\"times\":[%s]," \ + "\"msecs\":[%s]" \ + "}," \ + "\"requestBuckets\":{" \ + "\"msecs\":[%s]," \ + "\"counters\":[%s]" \ + "}," \ + "\"overCounts\":{" \ + "\"maxIntegerSize\":%s," \ + "\"requestCounter\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"1xx\":%uA," \ + "\"2xx\":%uA," \ + "\"3xx\":%uA," \ + "\"4xx\":%uA," \ + "\"5xx\":%uA," \ + "\"miss\":%uA," \ + "\"bypass\":%uA," \ + "\"expired\":%uA," \ + "\"stale\":%uA," \ + "\"updating\":%uA," \ + "\"revalidated\":%uA," \ + "\"hit\":%uA," \ + "\"scarce\":%uA," \ + "\"requestMsecCounter\":%uA" \ + "}" \ + "}," +#else +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_SERVER "\"%V\":{" \ + "\"requestCounter\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"responses\":{" \ + "\"1xx\":%uA," \ + "\"2xx\":%uA," \ + "\"3xx\":%uA," \ + "\"4xx\":%uA," \ + "\"5xx\":%uA" \ + "}," \ + "\"requestMsecCounter\":%uA," \ + "\"requestMsec\":%M," \ + "\"requestMsecs\":{" \ + "\"times\":[%s]," \ + "\"msecs\":[%s]" \ + "}," \ + "\"requestBuckets\":{" \ + "\"msecs\":[%s]," \ + "\"counters\":[%s]" \ + "}," \ + "\"overCounts\":{" \ + "\"maxIntegerSize\":%s," \ + "\"requestCounter\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"1xx\":%uA," \ + "\"2xx\":%uA," \ + "\"3xx\":%uA," \ + "\"4xx\":%uA," \ + "\"5xx\":%uA," \ + "\"requestMsecCounter\":%uA" \ + "}" \ + "}," +#endif + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_FILTER_S "\"filterZones\":{" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM_S "\"upstreamZones\":{" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_UPSTREAM "{\"server\":\"%V\"," \ + "\"requestCounter\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"responses\":{" \ + "\"1xx\":%uA," \ + "\"2xx\":%uA," \ + "\"3xx\":%uA," \ + "\"4xx\":%uA," \ + "\"5xx\":%uA" \ + "}," \ + "\"requestMsecCounter\":%uA," \ + "\"requestMsec\":%M," \ + "\"requestMsecs\":{" \ + "\"times\":[%s]," \ + "\"msecs\":[%s]" \ + "}," \ + "\"requestBuckets\":{" \ + "\"msecs\":[%s]," \ + "\"counters\":[%s]" \ + "}," \ + "\"responseMsecCounter\":%uA," \ + "\"responseMsec\":%M," \ + "\"responseMsecs\":{" \ + "\"times\":[%s]," \ + "\"msecs\":[%s]" \ + "}," \ + "\"responseBuckets\":{" \ + "\"msecs\":[%s]," \ + "\"counters\":[%s]" \ + "}," \ + "\"weight\":%ui," \ + "\"maxFails\":%ui," \ + "\"failTimeout\":%T," \ + "\"backup\":%s," \ + "\"down\":%s," \ + "\"overCounts\":{" \ + "\"maxIntegerSize\":%s," \ + "\"requestCounter\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"1xx\":%uA," \ + "\"2xx\":%uA," \ + "\"3xx\":%uA," \ + "\"4xx\":%uA," \ + "\"5xx\":%uA," \ + "\"requestMsecCounter\":%uA," \ + "\"responseMsecCounter\":%uA" \ + "}" \ + "}," + +#if (NGX_HTTP_CACHE) +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE_S "\"cacheZones\":{" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_JSON_FMT_CACHE "\"%V\":{" \ + "\"maxSize\":%uA," \ + "\"usedSize\":%uA," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"responses\":{" \ + "\"miss\":%uA," \ + "\"bypass\":%uA," \ + "\"expired\":%uA," \ + "\"stale\":%uA," \ + "\"updating\":%uA," \ + "\"revalidated\":%uA," \ + "\"hit\":%uA," \ + "\"scarce\":%uA" \ + "}," \ + "\"overCounts\":{" \ + "\"maxIntegerSize\":%s," \ + "\"inBytes\":%uA," \ + "\"outBytes\":%uA," \ + "\"miss\":%uA," \ + "\"bypass\":%uA," \ + "\"expired\":%uA," \ + "\"stale\":%uA," \ + "\"updating\":%uA," \ + "\"revalidated\":%uA," \ + "\"hit\":%uA," \ + "\"scarce\":%uA" \ + "}" \ + "}," +#endif + + +u_char *ngx_http_vhost_traffic_status_display_set_main( + ngx_http_request_t *r, u_char *buf); +u_char *ngx_http_vhost_traffic_status_display_set_server_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_set_server( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); +u_char *ngx_http_vhost_traffic_status_display_set_filter_node( + ngx_http_request_t *r, u_char *buf, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_set_filter( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); +u_char *ngx_http_vhost_traffic_status_display_set_upstream_node( + ngx_http_request_t *r, u_char *buf, + ngx_http_upstream_server_t *us, +#if nginx_version > 1007001 + ngx_http_vhost_traffic_status_node_t *vtsn +#else + ngx_http_vhost_traffic_status_node_t *vtsn, ngx_str_t *name +#endif + ); +u_char *ngx_http_vhost_traffic_status_display_set_upstream_alone( + ngx_http_request_t *r, u_char *buf, ngx_rbtree_node_t *node); +u_char *ngx_http_vhost_traffic_status_display_set_upstream_group( + ngx_http_request_t *r, u_char *buf); + +#if (NGX_HTTP_CACHE) +u_char *ngx_http_vhost_traffic_status_display_set_cache_node( + ngx_http_request_t *r, u_char *buf, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_set_cache( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); +#endif + +u_char *ngx_http_vhost_traffic_status_display_set(ngx_http_request_t *r, + u_char *buf); + + +#endif /* _NGX_HTTP_VTS_DISPLAY_JSON_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.c new file mode 100644 index 0000000..fac578e --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.c @@ -0,0 +1,557 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_shm.h" +#include "ngx_http_vhost_traffic_status_display_prometheus.h" + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_main(ngx_http_request_t *r, + u_char *buf) +{ + ngx_atomic_int_t ap, hn, ac, rq, rd, wr, wa; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_shm_info_t *shm_info; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + ap = *ngx_stat_accepted; + hn = *ngx_stat_handled; + ac = *ngx_stat_active; + rq = *ngx_stat_requests; + rd = *ngx_stat_reading; + wr = *ngx_stat_writing; + wa = *ngx_stat_waiting; + + shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + if (shm_info == NULL) { + return buf; + } + + ngx_http_vhost_traffic_status_shm_info(r, shm_info); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_MAIN, &ngx_cycle->hostname, + NGINX_VERSION, + (double) vtscf->start_msec / 1000, + ap, ac, hn, rd, rq, wa, wr, + shm_info->name, shm_info->max_size, + shm_info->used_size, shm_info->used_node); + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_server_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_str_t server; + ngx_uint_t i, n; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + server = *key; + + (void) ngx_http_vhost_traffic_status_node_position_key(&server, 1); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER, + &server, vtsn->stat_in_bytes, + &server, vtsn->stat_out_bytes, + &server, vtsn->stat_1xx_counter, + &server, vtsn->stat_2xx_counter, + &server, vtsn->stat_3xx_counter, + &server, vtsn->stat_4xx_counter, + &server, vtsn->stat_5xx_counter, + &server, vtsn->stat_request_counter, + &server, (double) vtsn->stat_request_time_counter / 1000, + &server, (double) ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period) / 1000); + + /* histogram */ + b = &vtsn->stat_request_buckets; + + n = b->len; + + if (n > 0) { + + /* histogram:bucket */ + for (i = 0; i < n; i++) { + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET, + &server, (double) b->buckets[i].msec / 1000, b->buckets[i].counter); + } + + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET_E, + &server, vtsn->stat_request_counter); + + /* histogram:sum */ + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_SUM, + &server, (double) vtsn->stat_request_time_counter / 1000); + + /* histogram:count */ + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_COUNT, + &server, vtsn->stat_request_counter); + } + +#if (NGX_HTTP_CACHE) + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_CACHE, + &server, vtsn->stat_cache_miss_counter, + &server, vtsn->stat_cache_bypass_counter, + &server, vtsn->stat_cache_expired_counter, + &server, vtsn->stat_cache_stale_counter, + &server, vtsn->stat_cache_updating_counter, + &server, vtsn->stat_cache_revalidated_counter, + &server, vtsn->stat_cache_hit_counter, + &server, vtsn->stat_cache_scarce_counter); +#endif + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_server(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO) { + key.data = vtsn->data; + key.len = vtsn->len; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_server_node(r, buf, &key, vtsn); + + /* calculates the sum */ + vtscf->stats.stat_request_counter += vtsn->stat_request_counter; + vtscf->stats.stat_in_bytes += vtsn->stat_in_bytes; + vtscf->stats.stat_out_bytes += vtsn->stat_out_bytes; + vtscf->stats.stat_1xx_counter += vtsn->stat_1xx_counter; + vtscf->stats.stat_2xx_counter += vtsn->stat_2xx_counter; + vtscf->stats.stat_3xx_counter += vtsn->stat_3xx_counter; + vtscf->stats.stat_4xx_counter += vtsn->stat_4xx_counter; + vtscf->stats.stat_5xx_counter += vtsn->stat_5xx_counter; + vtscf->stats.stat_request_time_counter += vtsn->stat_request_time_counter; + ngx_http_vhost_traffic_status_node_time_queue_merge( + &vtscf->stats.stat_request_times, + &vtsn->stat_request_times, vtscf->average_period); + +#if (NGX_HTTP_CACHE) + vtscf->stats.stat_cache_miss_counter += + vtsn->stat_cache_miss_counter; + vtscf->stats.stat_cache_bypass_counter += + vtsn->stat_cache_bypass_counter; + vtscf->stats.stat_cache_expired_counter += + vtsn->stat_cache_expired_counter; + vtscf->stats.stat_cache_stale_counter += + vtsn->stat_cache_stale_counter; + vtscf->stats.stat_cache_updating_counter += + vtsn->stat_cache_updating_counter; + vtscf->stats.stat_cache_revalidated_counter += + vtsn->stat_cache_revalidated_counter; + vtscf->stats.stat_cache_hit_counter += + vtsn->stat_cache_hit_counter; + vtscf->stats.stat_cache_scarce_counter += + vtsn->stat_cache_scarce_counter; +#endif + } + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_server(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_prometheus_set_server(r, buf, node->right); + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_filter_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_str_t filter, filter_name; + ngx_uint_t i, n; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + filter = filter_name = *key; + + (void) ngx_http_vhost_traffic_status_node_position_key(&filter, 1); + (void) ngx_http_vhost_traffic_status_node_position_key(&filter_name, 2); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER, + &filter, &filter_name, vtsn->stat_in_bytes, + &filter, &filter_name, vtsn->stat_out_bytes, + &filter, &filter_name, vtsn->stat_1xx_counter, + &filter, &filter_name, vtsn->stat_2xx_counter, + &filter, &filter_name, vtsn->stat_3xx_counter, + &filter, &filter_name, vtsn->stat_4xx_counter, + &filter, &filter_name, vtsn->stat_5xx_counter, + &filter, &filter_name, vtsn->stat_request_counter, + &filter, &filter_name, (double) vtsn->stat_request_time_counter / 1000, + &filter, &filter_name, + (double) ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period) / 1000); + + /* histogram */ + b = &vtsn->stat_request_buckets; + + n = b->len; + + if (n > 0) { + + /* histogram:bucket */ + for (i = 0; i < n; i++) { + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET, + &filter, &filter_name, (double) b->buckets[i].msec / 1000, + b->buckets[i].counter); + } + + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET_E, + &filter, &filter_name, vtsn->stat_request_counter); + + /* histogram:sum */ + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_SUM, + &filter, &filter_name, (double) vtsn->stat_request_time_counter / 1000); + + /* histogram:count */ + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_COUNT, + &filter, &filter_name, vtsn->stat_request_counter); + } + +#if (NGX_HTTP_CACHE) + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_CACHE, + &filter, &filter_name, vtsn->stat_cache_miss_counter, + &filter, &filter_name, vtsn->stat_cache_bypass_counter, + &filter, &filter_name, vtsn->stat_cache_expired_counter, + &filter, &filter_name, vtsn->stat_cache_stale_counter, + &filter, &filter_name, vtsn->stat_cache_updating_counter, + &filter, &filter_name, vtsn->stat_cache_revalidated_counter, + &filter, &filter_name, vtsn->stat_cache_hit_counter, + &filter, &filter_name, vtsn->stat_cache_scarce_counter); +#endif + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_filter(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) { + key.data = vtsn->data; + key.len = vtsn->len; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_filter_node(r, buf, &key, vtsn); + } + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_filter(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_prometheus_set_filter(r, buf, node->right); + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_upstream_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_str_t target, upstream, upstream_server; + ngx_uint_t i, n, len; + ngx_atomic_t time_counter; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + upstream = upstream_server = *key; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG) { + (void) ngx_http_vhost_traffic_status_node_position_key(&upstream, 1); + (void) ngx_http_vhost_traffic_status_node_position_key(&upstream_server, 2); + + } else if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA) { + ngx_str_set(&upstream, "::nogroups"); + (void) ngx_http_vhost_traffic_status_node_position_key(&upstream_server, 1); + } + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM, + &upstream, &upstream_server, vtsn->stat_in_bytes, + &upstream, &upstream_server, vtsn->stat_out_bytes, + &upstream, &upstream_server, vtsn->stat_1xx_counter, + &upstream, &upstream_server, vtsn->stat_2xx_counter, + &upstream, &upstream_server, vtsn->stat_3xx_counter, + &upstream, &upstream_server, vtsn->stat_4xx_counter, + &upstream, &upstream_server, vtsn->stat_5xx_counter, + &upstream, &upstream_server, vtsn->stat_request_counter, + &upstream, &upstream_server, (double) vtsn->stat_request_time_counter / 1000, + &upstream, &upstream_server, + (double) ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period) / 1000, + &upstream, &upstream_server, (double) vtsn->stat_upstream.response_time_counter / 1000, + &upstream, &upstream_server, + (double) ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_upstream.response_times, vtscf->average_method, + vtscf->average_period) / 1000); + + /* histogram */ + len = 2; + + while (len--) { + if (len > 0) { + b = &vtsn->stat_request_buckets; + time_counter = vtsn->stat_request_time_counter; + ngx_str_set(&target, "request"); + + } else { + b = &vtsn->stat_upstream.response_buckets; + time_counter = vtsn->stat_upstream.response_time_counter; + ngx_str_set(&target, "response"); + } + + n = b->len; + + if (n > 0) { + /* histogram:bucket */ + for (i = 0; i < n; i++) { + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET, + &target, &upstream, &upstream_server, (double) b->buckets[i].msec / 1000, + b->buckets[i].counter); + } + + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET_E, + &target, &upstream, &upstream_server, vtsn->stat_request_counter); + + /* histogram:sum */ + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_SUM, + &target, &upstream, &upstream_server, (double) time_counter / 1000); + + /* histogram:count */ + buf = ngx_sprintf(buf, + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_COUNT, + &target, &upstream, &upstream_server, vtsn->stat_request_counter); + } + + } + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_upstream(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG + || vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA) + { + key.data = vtsn->data; + key.len = vtsn->len; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_upstream_node(r, buf, &key, vtsn); + } + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_upstream(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_prometheus_set_upstream(r, buf, node->right); + } + + return buf; +} + + +#if (NGX_HTTP_CACHE) + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_cache_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_str_t cache; + + cache = *key; + + (void) ngx_http_vhost_traffic_status_node_position_key(&cache, 1); + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_CACHE, + &cache, vtsn->stat_cache_max_size, + &cache, vtsn->stat_cache_used_size, + &cache, vtsn->stat_in_bytes, + &cache, vtsn->stat_out_bytes, + &cache, vtsn->stat_cache_miss_counter, + &cache, vtsn->stat_cache_bypass_counter, + &cache, vtsn->stat_cache_expired_counter, + &cache, vtsn->stat_cache_stale_counter, + &cache, vtsn->stat_cache_updating_counter, + &cache, vtsn->stat_cache_revalidated_counter, + &cache, vtsn->stat_cache_hit_counter, + &cache, vtsn->stat_cache_scarce_counter); + + return buf; +} + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set_cache(ngx_http_request_t *r, + u_char *buf, ngx_rbtree_node_t *node) +{ + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC) { + key.data = vtsn->data; + key.len = vtsn->len; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_cache_node(r, buf, &key, vtsn); + } + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_cache(r, buf, node->left); + buf = ngx_http_vhost_traffic_status_display_prometheus_set_cache(r, buf, node->right); + } + + return buf; +} + +#endif + + +u_char * +ngx_http_vhost_traffic_status_display_prometheus_set(ngx_http_request_t *r, + u_char *buf) +{ + u_char *o, *s; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + node = ctx->rbtree->root; + + /* init stats */ + ngx_memzero(&vtscf->stats, sizeof(vtscf->stats)); + ngx_http_vhost_traffic_status_node_time_queue_init(&vtscf->stats.stat_request_times); + + /* main & connections */ + buf = ngx_http_vhost_traffic_status_display_prometheus_set_main(r, buf); + + /* serverZones */ + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_S); +#if (NGX_HTTP_CACHE) + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_CACHE_S); +#endif + buf = ngx_http_vhost_traffic_status_display_prometheus_set_server(r, buf, node); + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_server_node(r, buf, &vtscf->sum_key, + &vtscf->stats); + /* filterZones */ + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_S); +#if (NGX_HTTP_CACHE) + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_CACHE_S); +#endif + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_filter(r, buf, node); + + if (s == buf) { + buf = o; + } + + /* upstreamZones */ + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_S); + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_upstream(r, buf, node); + + if (s == buf) { + buf = o; + } + +#if (NGX_HTTP_CACHE) + /* cacheZones */ + o = buf; + + buf = ngx_sprintf(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_CACHE_S); + + s = buf; + + buf = ngx_http_vhost_traffic_status_display_prometheus_set_cache(r, buf, node); + + if (s == buf) { + buf = o; + } +#endif + + return buf; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.h new file mode 100644 index 0000000..d032e48 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_display_prometheus.h @@ -0,0 +1,305 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_DISPLAY_PROMETHEUS_H_INCLUDED_ +#define _NGX_HTTP_VTS_DISPLAY_PROMETHEUS_H_INCLUDED_ + + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_MAIN \ + "# HELP nginx_vts_info Nginx info\n" \ + "# TYPE nginx_vts_info gauge\n" \ + "nginx_vts_info{hostname=\"%V\",version=\"%s\"} 1\n" \ + "# HELP nginx_vts_start_time_seconds Nginx start time\n" \ + "# TYPE nginx_vts_start_time_seconds gauge\n" \ + "nginx_vts_start_time_seconds %.3f\n" \ + "# HELP nginx_vts_main_connections Nginx connections\n" \ + "# TYPE nginx_vts_main_connections gauge\n" \ + "nginx_vts_main_connections{status=\"accepted\"} %uA\n" \ + "nginx_vts_main_connections{status=\"active\"} %uA\n" \ + "nginx_vts_main_connections{status=\"handled\"} %uA\n" \ + "nginx_vts_main_connections{status=\"reading\"} %uA\n" \ + "nginx_vts_main_connections{status=\"requests\"} %uA\n" \ + "nginx_vts_main_connections{status=\"waiting\"} %uA\n" \ + "nginx_vts_main_connections{status=\"writing\"} %uA\n" \ + "# HELP nginx_vts_main_shm_usage_bytes Shared memory [%V] info\n" \ + "# TYPE nginx_vts_main_shm_usage_bytes gauge\n" \ + "nginx_vts_main_shm_usage_bytes{shared=\"max_size\"} %ui\n" \ + "nginx_vts_main_shm_usage_bytes{shared=\"used_size\"} %ui\n" \ + "nginx_vts_main_shm_usage_bytes{shared=\"used_node\"} %ui\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_S \ + "# HELP nginx_vts_server_bytes_total The request/response bytes\n" \ + "# TYPE nginx_vts_server_bytes_total counter\n" \ + "# HELP nginx_vts_server_requests_total The requests counter\n" \ + "# TYPE nginx_vts_server_requests_total counter\n" \ + "# HELP nginx_vts_server_request_seconds_total The request processing " \ + "time in seconds\n" \ + "# TYPE nginx_vts_server_request_seconds_total counter\n" \ + "# HELP nginx_vts_server_request_seconds The average of request " \ + "processing times in seconds\n" \ + "# TYPE nginx_vts_server_request_seconds gauge\n" \ + "# HELP nginx_vts_server_request_duration_seconds The histogram of " \ + "request processing time\n" \ + "# TYPE nginx_vts_server_request_duration_seconds histogram\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER \ + "nginx_vts_server_bytes_total{host=\"%V\",direction=\"in\"} %uA\n" \ + "nginx_vts_server_bytes_total{host=\"%V\",direction=\"out\"} %uA\n" \ + "nginx_vts_server_requests_total{host=\"%V\",code=\"1xx\"} %uA\n" \ + "nginx_vts_server_requests_total{host=\"%V\",code=\"2xx\"} %uA\n" \ + "nginx_vts_server_requests_total{host=\"%V\",code=\"3xx\"} %uA\n" \ + "nginx_vts_server_requests_total{host=\"%V\",code=\"4xx\"} %uA\n" \ + "nginx_vts_server_requests_total{host=\"%V\",code=\"5xx\"} %uA\n" \ + "nginx_vts_server_requests_total{host=\"%V\",code=\"total\"} %uA\n" \ + "nginx_vts_server_request_seconds_total{host=\"%V\"} %.3f\n" \ + "nginx_vts_server_request_seconds{host=\"%V\"} %.3f\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET \ + "nginx_vts_server_request_duration_seconds_bucket{host=\"%V\"," \ + "le=\"%.3f\"} %uA\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_BUCKET_E \ + "nginx_vts_server_request_duration_seconds_bucket{host=\"%V\"," \ + "le=\"+Inf\"} %uA\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_SUM \ + "nginx_vts_server_request_duration_seconds_sum{host=\"%V\"} %.3f\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_HISTOGRAM_COUNT \ + "nginx_vts_server_request_duration_seconds_count{host=\"%V\"} %uA\n" + +#if (NGX_HTTP_CACHE) +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_CACHE_S \ + "# HELP nginx_vts_server_cache_total The requests cache counter\n" \ + "# TYPE nginx_vts_server_cache_total counter\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_SERVER_CACHE \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"miss\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"bypass\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"expired\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"stale\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"updating\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"revalidated\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"hit\"} %uA\n" \ + "nginx_vts_server_cache_total{host=\"%V\",status=\"scarce\"} %uA\n" +#endif + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_S \ + "# HELP nginx_vts_filter_bytes_total The request/response bytes\n" \ + "# TYPE nginx_vts_filter_bytes_total counter\n" \ + "# HELP nginx_vts_filter_requests_total The requests counter\n" \ + "# TYPE nginx_vts_filter_requests_total counter\n" \ + "# HELP nginx_vts_filter_request_seconds_total The request processing " \ + "time in seconds counter\n" \ + "# TYPE nginx_vts_filter_request_seconds_total counter\n" \ + "# HELP nginx_vts_filter_request_seconds The average of request " \ + "processing times in seconds\n" \ + "# TYPE nginx_vts_filter_request_seconds gauge\n" \ + "# HELP nginx_vts_filter_request_duration_seconds The histogram of " \ + "request processing time\n" \ + "# TYPE nginx_vts_filter_request_duration_seconds histogram\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER \ + "nginx_vts_filter_bytes_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"in\"} %uA\n" \ + "nginx_vts_filter_bytes_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"out\"} %uA\n" \ + "nginx_vts_filter_requests_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"1xx\"} %uA\n" \ + "nginx_vts_filter_requests_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"2xx\"} %uA\n" \ + "nginx_vts_filter_requests_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"3xx\"} %uA\n" \ + "nginx_vts_filter_requests_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"4xx\"} %uA\n" \ + "nginx_vts_filter_requests_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"5xx\"} %uA\n" \ + "nginx_vts_filter_requests_total{filter=\"%V\",filter_name=\"%V\"," \ + "direction=\"total\"} %uA\n" \ + "nginx_vts_filter_request_seconds_total{filter=\"%V\"," \ + "filter_name=\"%V\"} %.3f\n" \ + "nginx_vts_filter_request_seconds{filter=\"%V\",filter_name=\"%V\"} %.3f\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET \ + "nginx_vts_filter_request_duration_seconds_bucket{filter=\"%V\"," \ + "filter_name=\"%V\",le=\"%.3f\"} %uA\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_BUCKET_E \ + "nginx_vts_filter_request_duration_seconds_bucket{filter=\"%V\"," \ + "filter_name=\"%V\",le=\"+Inf\"} %uA\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_SUM \ + "nginx_vts_filter_request_duration_seconds_sum{filter=\"%V\"," \ + "filter_name=\"%V\"} %.3f\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_HISTOGRAM_COUNT \ + "nginx_vts_filter_request_duration_seconds_count{filter=\"%V\"," \ + "filter_name=\"%V\"} %uA\n" + +#if (NGX_HTTP_CACHE) +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_CACHE_S \ + "# HELP nginx_vts_filter_cache_total The requests cache counter\n" \ + "# TYPE nginx_vts_filter_cache_total counter\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_FILTER_CACHE \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"miss\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"bypass\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"expired\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"stale\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"updating\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"revalidated\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"hit\"} %uA\n" \ + "nginx_vts_filter_cache_total{filter=\"%V\",filter_name=\"%V\"," \ + "status=\"scarce\"} %uA\n" +#endif + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_S \ + "# HELP nginx_vts_upstream_bytes_total The request/response bytes\n" \ + "# TYPE nginx_vts_upstream_bytes_total counter\n" \ + "# HELP nginx_vts_upstream_requests_total The upstream requests counter\n" \ + "# TYPE nginx_vts_upstream_requests_total counter\n" \ + "# HELP nginx_vts_upstream_request_seconds_total The request Processing " \ + "time including upstream in seconds\n" \ + "# TYPE nginx_vts_upstream_request_seconds_total counter\n" \ + "# HELP nginx_vts_upstream_request_seconds The average of request " \ + "processing times including upstream in seconds\n" \ + "# TYPE nginx_vts_upstream_request_seconds gauge\n" \ + "# HELP nginx_vts_upstream_response_seconds_total The only upstream " \ + "response processing time in seconds\n" \ + "# TYPE nginx_vts_upstream_response_seconds_total counter\n" \ + "# HELP nginx_vts_upstream_response_seconds The average of only " \ + "upstream response processing times in seconds\n" \ + "# TYPE nginx_vts_upstream_response_seconds gauge\n" \ + "# HELP nginx_vts_upstream_request_duration_seconds The histogram of " \ + "request processing time including upstream\n" \ + "# TYPE nginx_vts_upstream_request_duration_seconds histogram\n" \ + "# HELP nginx_vts_upstream_response_duration_seconds The histogram of " \ + "only upstream response processing time\n" \ + "# TYPE nginx_vts_upstream_response_duration_seconds histogram\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM \ + "nginx_vts_upstream_bytes_total{upstream=\"%V\",backend=\"%V\"," \ + "direction=\"in\"} %uA\n" \ + "nginx_vts_upstream_bytes_total{upstream=\"%V\",backend=\"%V\"," \ + "direction=\"out\"} %uA\n" \ + "nginx_vts_upstream_requests_total{upstream=\"%V\",backend=\"%V\"," \ + "code=\"1xx\"} %uA\n" \ + "nginx_vts_upstream_requests_total{upstream=\"%V\",backend=\"%V\"," \ + "code=\"2xx\"} %uA\n" \ + "nginx_vts_upstream_requests_total{upstream=\"%V\",backend=\"%V\"," \ + "code=\"3xx\"} %uA\n" \ + "nginx_vts_upstream_requests_total{upstream=\"%V\",backend=\"%V\"," \ + "code=\"4xx\"} %uA\n" \ + "nginx_vts_upstream_requests_total{upstream=\"%V\",backend=\"%V\"," \ + "code=\"5xx\"} %uA\n" \ + "nginx_vts_upstream_requests_total{upstream=\"%V\",backend=\"%V\"," \ + "code=\"total\"} %uA\n" \ + "nginx_vts_upstream_request_seconds_total{upstream=\"%V\"," \ + "backend=\"%V\"} %.3f\n" \ + "nginx_vts_upstream_request_seconds{upstream=\"%V\"," \ + "backend=\"%V\"} %.3f\n" \ + "nginx_vts_upstream_response_seconds_total{upstream=\"%V\"," \ + "backend=\"%V\"} %.3f\n" \ + "nginx_vts_upstream_response_seconds{upstream=\"%V\"," \ + "backend=\"%V\"} %.3f\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET \ + "nginx_vts_upstream_%V_duration_seconds_bucket{upstream=\"%V\"," \ + "backend=\"%V\",le=\"%.3f\"} %uA\n" + +#define \ + NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_BUCKET_E \ + "nginx_vts_upstream_%V_duration_seconds_bucket{upstream=\"%V\"," \ + "backend=\"%V\",le=\"+Inf\"} %uA\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_SUM \ + "nginx_vts_upstream_%V_duration_seconds_sum{upstream=\"%V\"," \ + "backend=\"%V\"} %.3f\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_UPSTREAM_HISTOGRAM_COUNT \ + "nginx_vts_upstream_%V_duration_seconds_count{upstream=\"%V\"," \ + "backend=\"%V\"} %uA\n" + + +#if (NGX_HTTP_CACHE) +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_CACHE_S \ + "# HELP nginx_vts_cache_usage_bytes THe cache zones info\n" \ + "# TYPE nginx_vts_cache_usage_bytes gauge\n" \ + "# HELP nginx_vts_cache_bytes_total The cache zones request/response " \ + "bytes\n" \ + "# TYPE nginx_vts_cache_bytes_total counter\n" \ + "# HELP nginx_vts_cache_requests_total The cache requests counter\n" \ + "# TYPE nginx_vts_cache_requests_total counter\n" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_PROMETHEUS_FMT_CACHE \ + "nginx_vts_cache_usage_bytes{cache_zone=\"%V\",cache_size=\"max\"} %uA\n" \ + "nginx_vts_cache_usage_bytes{cache_zone=\"%V\",cache_size=\"used\"} %uA\n" \ + "nginx_vts_cache_bytes_total{cache_zone=\"%V\",direction=\"in\"} %uA\n" \ + "nginx_vts_cache_bytes_total{cache_zone=\"%V\",direction=\"out\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\",status=\"miss\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\"," \ + "status=\"bypass\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\"," \ + "status=\"expired\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\"," \ + "status=\"stale\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\"," \ + "status=\"updating\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\"," \ + "status=\"revalidated\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\",status=\"hit\"} %uA\n" \ + "nginx_vts_cache_requests_total{cache_zone=\"%V\",status=\"scarce\"} %uA\n" +#endif + + +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_main( + ngx_http_request_t *r, u_char *buf); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_server_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_server( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_filter_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_filter( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_upstream_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_upstream( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); + +#if (NGX_HTTP_CACHE) +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_cache_node( + ngx_http_request_t *r, + u_char *buf, ngx_str_t *key, + ngx_http_vhost_traffic_status_node_t *vtsn); +u_char *ngx_http_vhost_traffic_status_display_prometheus_set_cache( + ngx_http_request_t *r, u_char *buf, + ngx_rbtree_node_t *node); +#endif + +u_char *ngx_http_vhost_traffic_status_display_prometheus_set(ngx_http_request_t *r, + u_char *buf); + + +#endif /* _NGX_HTTP_VTS_DISPLAY_PROMETHEUS_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.c new file mode 100644 index 0000000..76d4c75 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.c @@ -0,0 +1,439 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_dump.h" + + +static u_char NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD[] = { 0x53, 0x54, 0x56 }; + + +static ssize_t ngx_http_vhost_traffic_status_dump_header_read(ngx_file_t *file, + ngx_http_vhost_traffic_status_dump_header_t *file_header); +static ssize_t ngx_http_vhost_traffic_status_dump_header_write(ngx_event_t *ev, + ngx_file_t *file); +static void ngx_http_vhost_traffic_status_dump_node_write(ngx_event_t *ev, + ngx_file_t *file, ngx_rbtree_node_t *node); +static ngx_int_t ngx_http_vhost_traffic_status_dump_update_valid(ngx_event_t *ev); +static ngx_int_t ngx_http_vhost_traffic_status_dump_restore_add_node(ngx_event_t *ev, + ngx_http_vhost_traffic_status_node_t *ovtsn, ngx_str_t *key); + + +void +ngx_http_vhost_traffic_status_file_lock(ngx_file_t *file) +{ + ngx_err_t err = ngx_lock_fd(file->fd); + + if (err == 0) { + return; + } + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + ngx_lock_fd_n " \"%s\" failed", file->name.data); +} + + +void +ngx_http_vhost_traffic_status_file_unlock(ngx_file_t *file) +{ + ngx_err_t err = ngx_unlock_fd(file->fd); + + if (err == 0) { + return; + } + + ngx_log_error(NGX_LOG_ALERT, file->log, err, + ngx_unlock_fd_n " \"%s\" failed", file->name.data); +} + + +void +ngx_http_vhost_traffic_status_file_close(ngx_file_t *file) +{ + if (ngx_close_file(file->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, file->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", file->name.data); + } +} + + +static ssize_t +ngx_http_vhost_traffic_status_dump_header_read(ngx_file_t *file, + ngx_http_vhost_traffic_status_dump_header_t *file_header) +{ + ssize_t n; + + ngx_memzero(file_header, sizeof(ngx_http_vhost_traffic_status_dump_header_t)); + + n = ngx_read_file(file, (u_char *) file_header, + sizeof(ngx_http_vhost_traffic_status_dump_header_t), 0); + + return n; +} + + +static ssize_t +ngx_http_vhost_traffic_status_dump_header_write(ngx_event_t *ev, ngx_file_t *file) +{ + size_t len; + ssize_t n; + u_char *p; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_dump_header_t file_header; + + ctx = ev->data; + + ngx_memzero(&file_header, sizeof(ngx_http_vhost_traffic_status_dump_header_t)); + + len = (ctx->shm_name.len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE) + ? NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE - 1 + : ctx->shm_name.len; + + p = file_header.name; + p = ngx_cpymem(p, ctx->shm_name.data, len); + file_header.time = ngx_http_vhost_traffic_status_current_msec(); + file_header.version = nginx_version; + + n = ngx_write_fd(file->fd, &file_header, sizeof(ngx_http_vhost_traffic_status_dump_header_t)); + + return n; +} + + +static void +ngx_http_vhost_traffic_status_dump_node_write(ngx_event_t *ev, ngx_file_t *file, + ngx_rbtree_node_t *node) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ev->data; + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + (void) ngx_write_fd(file->fd, vtsn, sizeof(ngx_http_vhost_traffic_status_node_t)); + (void) ngx_write_fd(file->fd, vtsn->data, vtsn->len); + (void) ngx_write_fd(file->fd, NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD, + sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD)); + + ngx_http_vhost_traffic_status_dump_node_write(ev, file, node->left); + ngx_http_vhost_traffic_status_dump_node_write(ev, file, node->right); + } +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_dump_update_valid(ngx_event_t *ev) +{ + size_t len; + ssize_t n; + ngx_fd_t fd; + ngx_int_t rc; + ngx_msec_t current_msec; + ngx_file_t file; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_dump_header_t file_header; + + ctx = ev->data; + + fd = ngx_open_file(ctx->dump_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", ctx->dump_file.data); + return NGX_OK; + } + + file.fd = fd; + file.name = ctx->dump_file; + file.log = ev->log; + + n = ngx_http_vhost_traffic_status_dump_header_read(&file, &file_header); + + ngx_http_vhost_traffic_status_file_close(&file); + + if (n != sizeof(ngx_http_vhost_traffic_status_dump_header_t)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_update_valid::dump_header_read() size:%z failed", n); + return NGX_OK; + } + + len = (ctx->shm_name.len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE) + ? NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE - 1 + : ctx->shm_name.len; + + if (ngx_strncmp(ctx->shm_name.data, file_header.name, len) != 0) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_update_valid::dump_header_read() name[%z]:\"%s\" failed", + len, file_header.name); + return NGX_OK; + } + + current_msec = ngx_http_vhost_traffic_status_current_msec(); + + rc = ((current_msec - file_header.time) > ctx->dump_period) ? NGX_OK : NGX_ERROR; + + return rc; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_dump_execute(ngx_event_t *ev) +{ + u_char *name; + ssize_t n; + ngx_fd_t fd; + ngx_file_t file; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = ev->data; + + name = ctx->dump_file.data; + + fd = ngx_open_file(name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, NGX_FILE_DEFAULT_ACCESS); + + if (fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_ALERT, ev->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", name); + return NGX_ERROR; + } + + file.fd = fd; + file.name = ctx->dump_file; + file.log = ev->log; + + ngx_http_vhost_traffic_status_file_lock(&file); + + n = ngx_http_vhost_traffic_status_dump_header_write(ev, &file); + if (n != sizeof(ngx_http_vhost_traffic_status_dump_header_t)) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "dump_execute::dump_header_write() failed"); + + ngx_http_vhost_traffic_status_file_unlock(&file); + ngx_http_vhost_traffic_status_file_close(&file); + + return NGX_ERROR; + } + + ngx_http_vhost_traffic_status_dump_node_write(ev, &file, ctx->rbtree->root); + + ngx_http_vhost_traffic_status_file_unlock(&file); + ngx_http_vhost_traffic_status_file_close(&file); + + return NGX_OK; +} + + +void +ngx_http_vhost_traffic_status_dump_handler(ngx_event_t *ev) +{ + ngx_int_t rc; + + if (ngx_exiting) { + return; + } + + rc = ngx_http_vhost_traffic_status_dump_update_valid(ev); + if (rc != NGX_OK) { + goto invalid; + } + + rc = ngx_http_vhost_traffic_status_dump_execute(ev); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "dump_handler::dump_header_execute() failed"); + } + +invalid: + + ngx_add_timer(ev, 1000); +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_dump_restore_add_node(ngx_event_t *ev, + ngx_http_vhost_traffic_status_node_t *ovtsn, ngx_str_t *key) +{ + size_t size; + uint32_t hash; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ev->data; + + if (key->len == 0) { + return NGX_ERROR; + } + + shpool = (ngx_slab_pool_t *) ctx->shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + /* find node */ + hash = ngx_crc32_short(key->data, key->len); + + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, key, hash); + + /* copy node */ + if (node == NULL) { + size = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_vhost_traffic_status_node_t, data) + + key->len; + + node = ngx_slab_alloc_locked(shpool, size); + if (node == NULL) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "dump_restore_add_node::ngx_slab_alloc_locked() failed"); + + ngx_shmtx_unlock(&shpool->mutex); + return NGX_ERROR; + } + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + node->key = hash; + + *vtsn = *ovtsn; + + ngx_memcpy(vtsn->data, key->data, key->len); + + ngx_rbtree_insert(ctx->rbtree, node); + } + + ngx_shmtx_unlock(&shpool->mutex); + + return NGX_OK; +} + + +void +ngx_http_vhost_traffic_status_dump_restore(ngx_event_t *ev) +{ + off_t offset; + size_t len; + ssize_t n; + u_char *buf, *pad; + ngx_fd_t fd; + ngx_str_t key; + ngx_int_t rc; + ngx_file_t file; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t vtsn; + ngx_http_vhost_traffic_status_dump_header_t file_header; + + ctx = ev->data; + + fd = ngx_open_file(ctx->dump_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN, 0); + if (fd == NGX_INVALID_FILE) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", ctx->dump_file.data); + return; + } + + file.fd = fd; + file.name = ctx->dump_file; + file.log = ev->log; + + n = ngx_http_vhost_traffic_status_dump_header_read(&file, &file_header); + + if (n != sizeof(ngx_http_vhost_traffic_status_dump_header_t)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::dump_header_read() size:%z failed", n); + ngx_http_vhost_traffic_status_file_close(&file); + return; + } + + len = (ctx->shm_name.len >= NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE) + ? NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE - 1 + : ctx->shm_name.len; + + if (ngx_strncmp(ctx->shm_name.data, file_header.name, len) != 0) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::dump_header_read() name[%z]:\"%s\" failed", + len, file_header.name); + ngx_http_vhost_traffic_status_file_close(&file); + return; + } + + buf = ngx_pcalloc(ngx_cycle->pool, NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE); + pad = ngx_pcalloc(ngx_cycle->pool, sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD)); + if (buf == NULL || pad == NULL) { + ngx_log_error(NGX_LOG_ALERT, ev->log, 0, + "dump_restore::ngx_pcalloc() failed"); + ngx_http_vhost_traffic_status_file_close(&file); + return; + } + + offset = n; + + for ( ;; ) { + ngx_memzero(buf, NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE); + + /* read: node */ + n = ngx_read_file(&file, (u_char *) &vtsn, + sizeof(ngx_http_vhost_traffic_status_node_t), offset); + + if (n == NGX_ERROR || n == 0 + || n != sizeof(ngx_http_vhost_traffic_status_node_t)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::ngx_read_file() node size:%z failed", n); + break; + } + + if (vtsn.len > NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE) { + offset += vtsn.len + sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD); + continue; + } + + /* read: data */ + offset += n; + n = ngx_read_file(&file, buf, vtsn.len, offset); + if (n != vtsn.len) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::ngx_read_file() read:%z, data:%z failed", + n, vtsn.len); + break; + } + + /* read: pad */ + offset += n; + n = ngx_read_file(&file, pad, + sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD), + offset); + if (n == NGX_ERROR || n == 0 + || n != sizeof(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD)) + { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::ngx_read_file() pad size:%z failed", n); + break; + } + + if (ngx_memcmp(NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_PAD, pad, n) != 0) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::ngx_read_file() pad does not match"); + break; + } + + /* push: node */ + key.len = vtsn.len; + key.data = buf; + + rc = ngx_http_vhost_traffic_status_dump_restore_add_node(ev, &vtsn, &key); + if (rc != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, + "dump_restore::dump_restore_add_node() failed"); + break; + } + + offset += n; + } + + ngx_http_vhost_traffic_status_file_close(&file); +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.h new file mode 100644 index 0000000..c79bd1f --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_dump.h @@ -0,0 +1,33 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_DUMP_H_INCLUDED_ +#define _NGX_HTTP_VTS_DUMP_H_INCLUDED_ + + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE 128 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_DATA_BUF_SIZE 1024 + + +typedef struct { + u_char name[NGX_HTTP_VHOST_TRAFFIC_STATUS_DUMP_HEADER_NAME_SIZE]; + ngx_msec_t time; + ngx_uint_t version; +} ngx_http_vhost_traffic_status_dump_header_t; + + +void ngx_http_vhost_traffic_status_file_lock(ngx_file_t *file); +void ngx_http_vhost_traffic_status_file_unlock(ngx_file_t *file); +void ngx_http_vhost_traffic_status_file_close(ngx_file_t *file); + +ngx_int_t ngx_http_vhost_traffic_status_dump_execute(ngx_event_t *ev); +void ngx_http_vhost_traffic_status_dump_handler(ngx_event_t *ev); +void ngx_http_vhost_traffic_status_dump_restore(ngx_event_t *ev); + + +#endif /* _NGX_HTTP_VTS_DUMP_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.c new file mode 100644 index 0000000..d11a141 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.c @@ -0,0 +1,377 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_filter.h" + + +int ngx_libc_cdecl +ngx_http_traffic_status_filter_cmp_hashs(const void *one, const void *two) +{ + ngx_http_vhost_traffic_status_filter_uniq_t *first = + (ngx_http_vhost_traffic_status_filter_uniq_t *) one; + ngx_http_vhost_traffic_status_filter_uniq_t *second = + (ngx_http_vhost_traffic_status_filter_uniq_t *) two; + + return (first->hash - second->hash); +} + + +int ngx_libc_cdecl +ngx_http_traffic_status_filter_cmp_keys(const void *one, const void *two) +{ + ngx_http_vhost_traffic_status_filter_key_t *first = + (ngx_http_vhost_traffic_status_filter_key_t *) one; + ngx_http_vhost_traffic_status_filter_key_t *second = + (ngx_http_vhost_traffic_status_filter_key_t *) two; + + return (int) ngx_strcmp(first->key.data, second->key.data); +} + + +ngx_int_t +ngx_http_vhost_traffic_status_filter_unique(ngx_pool_t *pool, ngx_array_t **keys) +{ + uint32_t hash; + u_char *p; + ngx_str_t key; + ngx_uint_t i, n; + ngx_array_t *uniqs, *filter_keys; + ngx_http_vhost_traffic_status_filter_t *filter, *filters; + ngx_http_vhost_traffic_status_filter_uniq_t *filter_uniqs; + + if (*keys == NULL) { + return NGX_OK; + } + + uniqs = ngx_array_create(pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_uniq_t)); + if (uniqs == NULL) { + return NGX_ERROR; + } + + /* init array */ + filter_keys = NULL; + filter_uniqs = NULL; + + filters = (*keys)->elts; + n = (*keys)->nelts; + + for (i = 0; i < n; i++) { + key.len = filters[i].filter_key.value.len + + filters[i].filter_name.value.len; + key.data = ngx_pcalloc(pool, key.len); + if (key.data == NULL) { + return NGX_ERROR; + } + + p = key.data; + p = ngx_cpymem(p, filters[i].filter_key.value.data, + filters[i].filter_key.value.len); + ngx_memcpy(p, filters[i].filter_name.value.data, + filters[i].filter_name.value.len); + hash = ngx_crc32_short(key.data, key.len); + + filter_uniqs = ngx_array_push(uniqs); + if (filter_uniqs == NULL) { + return NGX_ERROR; + } + + filter_uniqs->hash = hash; + filter_uniqs->index = i; + + if (p != NULL) { + ngx_pfree(pool, key.data); + } + } + + filter_uniqs = uniqs->elts; + n = uniqs->nelts; + + ngx_qsort(filter_uniqs, (size_t) n, + sizeof(ngx_http_vhost_traffic_status_filter_uniq_t), + ngx_http_traffic_status_filter_cmp_hashs); + + hash = 0; + for (i = 0; i < n; i++) { + if (filter_uniqs[i].hash == hash) { + continue; + } + + hash = filter_uniqs[i].hash; + + if (filter_keys == NULL) { + filter_keys = ngx_array_create(pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_t)); + if (filter_keys == NULL) { + return NGX_ERROR; + } + } + + filter = ngx_array_push(filter_keys); + if (filter == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(filter, &filters[filter_uniqs[i].index], + sizeof(ngx_http_vhost_traffic_status_filter_t)); + + } + + if ((*keys)->nelts != filter_keys->nelts) { + *keys = filter_keys; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_filter_get_keys(ngx_http_request_t *r, + ngx_array_t **filter_keys, ngx_rbtree_node_t *node) +{ + ngx_int_t rc; + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_filter_key_t *keys; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) { + key.data = vtsn->data; + key.len = vtsn->len; + + rc = ngx_http_vhost_traffic_status_node_position_key(&key, 1); + if (rc != NGX_OK) { + goto next; + } + + if (*filter_keys == NULL) { + *filter_keys = ngx_array_create(r->pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_key_t)); + + if (*filter_keys == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "filter_get_keys::ngx_array_create() failed"); + return NGX_ERROR; + } + } + + keys = ngx_array_push(*filter_keys); + if (keys == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "filter_get_keys::ngx_array_push() failed"); + return NGX_ERROR; + } + + keys->key.len = key.len; + /* 1 byte for terminating '\0' for ngx_strcmp() */ + keys->key.data = ngx_pcalloc(r->pool, key.len + 1); + if (keys->key.data == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "filter_get_keys::ngx_pcalloc() failed"); + } + + ngx_memcpy(keys->key.data, key.data, key.len); + } +next: + rc = ngx_http_vhost_traffic_status_filter_get_keys(r, filter_keys, node->left); + if (rc != NGX_OK) { + return rc; + } + + rc = ngx_http_vhost_traffic_status_filter_get_keys(r, filter_keys, node->right); + if (rc != NGX_OK) { + return rc; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_filter_get_nodes(ngx_http_request_t *r, + ngx_array_t **filter_nodes, ngx_str_t *name, + ngx_rbtree_node_t *node) +{ + ngx_int_t rc; + ngx_str_t key; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_filter_node_t *nodes; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) { + key.data = vtsn->data; + key.len = vtsn->len; + + rc = ngx_http_vhost_traffic_status_node_position_key(&key, 1); + if (rc != NGX_OK) { + goto next; + } + + if (name->len != key.len) { + goto next; + } + + if (ngx_strncmp(name->data, key.data, key.len) != 0) { + goto next; + } + + if (*filter_nodes == NULL) { + *filter_nodes = ngx_array_create(r->pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_node_t)); + + if (*filter_nodes == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "filter_get_nodes::ngx_array_create() failed"); + return NGX_ERROR; + } + } + + nodes = ngx_array_push(*filter_nodes); + if (nodes == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "filter_get_nodes::ngx_array_push() failed"); + return NGX_ERROR; + } + + nodes->node = vtsn; + } +next: + rc = ngx_http_vhost_traffic_status_filter_get_nodes(r, filter_nodes, name, node->left); + if (rc != NGX_OK) { + return rc; + } + + rc = ngx_http_vhost_traffic_status_filter_get_nodes(r, filter_nodes, name, node->right); + if (rc != NGX_OK) { + return rc; + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_filter_max_node_match(ngx_http_request_t *r, + ngx_str_t *filter) +{ + ngx_uint_t i, n; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_filter_match_t *matches; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (ctx->filter_max_node_matches == NULL) { + return NGX_OK; + } + + matches = ctx->filter_max_node_matches->elts; + n = ctx->filter_max_node_matches->nelts; + + /* disabled */ + if (n == 0) { + return NGX_OK; + } + + for (i = 0; i < n; i++) { + if (ngx_strncmp(filter->data, matches[i].match.data, matches[i].match.len) == 0) { + return NGX_OK; + } + } + + return NGX_ERROR; +} + + +char * +ngx_http_vhost_traffic_status_filter_by_set_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf; + + ngx_str_t *value, name; + ngx_array_t *filter_keys; + ngx_http_compile_complex_value_t ccv; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_filter_t *filter; + + ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "empty key pattern"); + return NGX_CONF_ERROR; + } + + filter_keys = (cf->cmd_type == NGX_HTTP_MAIN_CONF) ? ctx->filter_keys : vtscf->filter_keys; + if (filter_keys == NULL) { + filter_keys = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_t)); + if (filter_keys == NULL) { + return NGX_CONF_ERROR; + } + } + + filter = ngx_array_push(filter_keys); + if (filter == NULL) { + return NGX_CONF_ERROR; + } + + /* first argument process */ + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &filter->filter_key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* second argument process */ + if (cf->args->nelts == 3) { + name = value[2]; + + } else { + ngx_str_set(&name, ""); + } + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &name; + ccv.complex_value = &filter->filter_name; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (cf->cmd_type == NGX_HTTP_MAIN_CONF) { + ctx->filter_keys = filter_keys; + + } else { + vtscf->filter_keys = filter_keys; + } + + return NGX_CONF_OK; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.h new file mode 100644 index 0000000..895c536 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_filter.h @@ -0,0 +1,59 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_FILTER_H_INCLUDED_ +#define _NGX_HTTP_VTS_FILTER_H_INCLUDED_ + + +typedef struct { + ngx_http_complex_value_t filter_key; + ngx_http_complex_value_t filter_name; +} ngx_http_vhost_traffic_status_filter_t; + + +typedef struct { + ngx_str_t key; +} ngx_http_vhost_traffic_status_filter_key_t; + + +typedef struct { + uint32_t hash; + ngx_uint_t index; +} ngx_http_vhost_traffic_status_filter_uniq_t; + + +typedef struct { + ngx_http_vhost_traffic_status_node_t *node; +} ngx_http_vhost_traffic_status_filter_node_t; + + +typedef struct { + ngx_str_t match; +} ngx_http_vhost_traffic_status_filter_match_t; + + +int ngx_libc_cdecl ngx_http_traffic_status_filter_cmp_hashs( + const void *one, const void *two); +int ngx_libc_cdecl ngx_http_traffic_status_filter_cmp_keys( + const void *one, const void *two); +ngx_int_t ngx_http_vhost_traffic_status_filter_unique( + ngx_pool_t *pool, ngx_array_t **keys); +ngx_int_t ngx_http_vhost_traffic_status_filter_get_keys( + ngx_http_request_t *r, ngx_array_t **filter_keys, + ngx_rbtree_node_t *node); +ngx_int_t ngx_http_vhost_traffic_status_filter_get_nodes( + ngx_http_request_t *r, ngx_array_t **filter_nodes, + ngx_str_t *name, ngx_rbtree_node_t *node); +ngx_int_t ngx_http_vhost_traffic_status_filter_max_node_match( + ngx_http_request_t *r, ngx_str_t *filter); + +char *ngx_http_vhost_traffic_status_filter_by_set_key(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +#endif /* _NGX_HTTP_VTS_FILTER_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.c new file mode 100644 index 0000000..abf6c2b --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.c @@ -0,0 +1,475 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_filter.h" +#include "ngx_http_vhost_traffic_status_limit.h" + + +ngx_int_t +ngx_http_vhost_traffic_status_limit_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http vts limit handler"); + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (!ctx->enable || !vtscf->limit || vtscf->bypass_limit) { + return NGX_DECLINED; + } + + /* limit traffic of server */ + rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, ctx->limit_traffics); + if (rc != NGX_DECLINED) { + return rc; + } + + rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, vtscf->limit_traffics); + if (rc != NGX_DECLINED) { + return rc; + } + + /* limit traffic of filter */ + rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, ctx->limit_filter_traffics); + if (rc != NGX_DECLINED) { + return rc; + } + + rc = ngx_http_vhost_traffic_status_limit_handler_traffic(r, vtscf->limit_filter_traffics); + if (rc != NGX_DECLINED) { + return rc; + } + + return NGX_DECLINED; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_limit_handler_traffic(ngx_http_request_t *r, + ngx_array_t *traffics) +{ + unsigned type; + ngx_str_t variable, key, dst; + ngx_int_t rc; + ngx_uint_t i, n; + ngx_atomic_t traffic_used; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_limit_t *limits; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + rc = NGX_DECLINED; + + if (traffics == NULL) { + return rc; + } + + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + limits = traffics->elts; + n = traffics->nelts; + + for (i = 0; i < n; i++) { + if (limits[i].variable.value.len <= 0) { + continue; + } + + /* init */ + traffic_used = 0; + variable.len = 0; + key.len = 0; + dst.len = 0; + type = limits[i].type; + + if (ngx_http_complex_value(r, &limits[i].variable, &variable) != NGX_OK) { + goto done; + } + + if (variable.len == 0) { + continue; + } + + /* traffic of filter */ + if (limits[i].key.value.len > 0) { + if (ngx_http_complex_value(r, &limits[i].key, &key) != NGX_OK) { + goto done; + } + + if (key.len == 0) { + continue; + } + + node = ngx_http_vhost_traffic_status_find_node(r, &key, type, 0); + + if (node == NULL) { + continue; + } + + vtscf->node_caches[type] = node; + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + traffic_used = (ngx_atomic_t) ngx_http_vhost_traffic_status_node_member(vtsn, &variable); + + /* traffic of server */ + } else { + ngx_http_vhost_traffic_status_find_name(r, &dst); + + if (ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type) + != NGX_OK || key.len == 0) + { + goto done; + } + + node = ngx_http_vhost_traffic_status_find_node(r, &key, type, 0); + + if (node == NULL) { + continue; + } + + vtscf->node_caches[type] = node; + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + traffic_used = (ngx_atomic_t) ngx_http_vhost_traffic_status_node_member(vtsn, &variable); + } + + if (traffic_used > limits[i].size) { + rc = limits[i].code; + goto done; + } + } + +done: + + ngx_shmtx_unlock(&shpool->mutex); + + return rc; +} + + +char * +ngx_http_vhost_traffic_status_limit_traffic(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf; + + u_char *p; + off_t size; + ngx_str_t *value, s; + ngx_array_t *limit_traffics; + ngx_http_compile_complex_value_t ccv; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_limit_t *traffic; + + ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic() empty value pattern"); + return NGX_CONF_ERROR; + } + + if (value[1].len > 5 && ngx_strstrn(value[1].data, "$vts_", 5 - 1)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic() $vts_* is not allowed here"); + return NGX_CONF_ERROR; + } + + p = (u_char *) ngx_strchr(value[1].data, ':'); + if (p == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic() empty size pattern"); + return NGX_CONF_ERROR; + } + + s.data = p + 1; + s.len = value[1].data + value[1].len - s.data; + + size = ngx_parse_offset(&s); + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_traffic() invalid limit size \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + limit_traffics = (cf->cmd_type == NGX_HTTP_MAIN_CONF) + ? ctx->limit_traffics + : vtscf->limit_traffics; + if (limit_traffics == NULL) { + limit_traffics = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_vhost_traffic_status_limit_t)); + if (limit_traffics == NULL) { + return NGX_CONF_ERROR; + } + } + + traffic = ngx_array_push(limit_traffics); + if (traffic == NULL) { + return NGX_CONF_ERROR; + } + + value[1].len = p - value[1].data; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &traffic->variable; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + traffic->size = (ngx_atomic_t) size; + + traffic->code = (cf->args->nelts == 3) + ? (ngx_uint_t) ngx_atoi(value[2].data, value[2].len) + : NGX_HTTP_SERVICE_UNAVAILABLE; + + traffic->type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + + traffic->key.value.len = 0; + + if (cf->cmd_type == NGX_HTTP_MAIN_CONF) { + ctx->limit_traffics = limit_traffics; + + } else { + vtscf->limit_traffics = limit_traffics; + } + + return NGX_CONF_OK; +} + + +char * +ngx_http_vhost_traffic_status_limit_traffic_by_set_key(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf; + + u_char *p; + off_t size; + ngx_str_t *value, s, alpha; + ngx_array_t *limit_traffics; + ngx_http_compile_complex_value_t ccv; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_limit_t *traffic; + + ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + value = cf->args->elts; + if (value[1].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic_by_set_key() empty key pattern"); + return NGX_CONF_ERROR; + } + + if (value[2].len == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic_by_set_key() empty value pattern"); + return NGX_CONF_ERROR; + } + + if (value[2].len > 5 && ngx_strstrn(value[2].data, "$vts_", 5 - 1)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_traffic_by_set_key() $vts_* is not allowed here"); + return NGX_CONF_ERROR; + } + + p = (u_char *) ngx_strchr(value[2].data, ':'); + if (p == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "limit_traffic_by_set_key() empty size pattern"); + return NGX_CONF_ERROR; + } + + s.data = p + 1; + s.len = value[2].data + value[2].len - s.data; + + size = ngx_parse_offset(&s); + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_traffic_by_set_key() invalid limit size \"%V\"", &value[2]); + return NGX_CONF_ERROR; + } + + limit_traffics = (cf->cmd_type == NGX_HTTP_MAIN_CONF) + ? ctx->limit_filter_traffics + : vtscf->limit_filter_traffics; + if (limit_traffics == NULL) { + limit_traffics = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_vhost_traffic_status_limit_t)); + if (limit_traffics == NULL) { + return NGX_CONF_ERROR; + } + } + + traffic = ngx_array_push(limit_traffics); + if (traffic == NULL) { + return NGX_CONF_ERROR; + } + + /* set key to be limited */ + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + (void) ngx_http_vhost_traffic_status_replace_chrc(&value[1], '@', + NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR); + ngx_str_set(&alpha, "[:alpha:]"); + if (ngx_http_vhost_traffic_status_replace_strc(&value[1], &alpha, '@') != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "limit_traffic_by_set_key()::replace_strc() failed"); + } + + ccv.cf = cf; + ccv.value = &value[1]; + ccv.complex_value = &traffic->key; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* set member to be limited */ + value[2].len = p - value[2].data; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &traffic->variable; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + traffic->size = (ngx_atomic_t) size; + + traffic->code = (cf->args->nelts == 4) + ? (ngx_uint_t) ngx_atoi(value[3].data, value[3].len) + : NGX_HTTP_SERVICE_UNAVAILABLE; + + traffic->type = ngx_http_vhost_traffic_status_string_to_group(value[1].data); + + if (cf->cmd_type == NGX_HTTP_MAIN_CONF) { + ctx->limit_filter_traffics = limit_traffics; + + } else { + vtscf->limit_filter_traffics = limit_traffics; + } + + return NGX_CONF_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_limit_traffic_unique(ngx_pool_t *pool, ngx_array_t **keys) +{ + uint32_t hash; + u_char *p; + ngx_str_t key; + ngx_uint_t i, n; + ngx_array_t *uniqs, *traffic_keys; + ngx_http_vhost_traffic_status_limit_t *traffic, *traffics; + ngx_http_vhost_traffic_status_filter_uniq_t *traffic_uniqs; + + if (*keys == NULL) { + return NGX_OK; + } + + uniqs = ngx_array_create(pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_uniq_t)); + if (uniqs == NULL) { + return NGX_ERROR; + } + + /* init array */ + traffic_keys = NULL; + traffic_uniqs = NULL; + + traffics = (*keys)->elts; + n = (*keys)->nelts; + + for (i = 0; i < n; i++) { + key.len = traffics[i].key.value.len + + traffics[i].variable.value.len; + key.data = ngx_pcalloc(pool, key.len); + if (key.data == NULL) { + return NGX_ERROR; + } + + p = key.data; + p = ngx_cpymem(p, traffics[i].key.value.data, + traffics[i].key.value.len); + ngx_memcpy(p, traffics[i].variable.value.data, + traffics[i].variable.value.len); + hash = ngx_crc32_short(key.data, key.len); + + traffic_uniqs = ngx_array_push(uniqs); + if (traffic_uniqs == NULL) { + return NGX_ERROR; + } + + traffic_uniqs->hash = hash; + traffic_uniqs->index = i; + + if (p != NULL) { + ngx_pfree(pool, key.data); + } + } + + traffic_uniqs = uniqs->elts; + n = uniqs->nelts; + + ngx_qsort(traffic_uniqs, (size_t) n, + sizeof(ngx_http_vhost_traffic_status_filter_uniq_t), + ngx_http_traffic_status_filter_cmp_hashs); + + hash = 0; + for (i = 0; i < n; i++) { + if (traffic_uniqs[i].hash == hash) { + continue; + } + + hash = traffic_uniqs[i].hash; + + if (traffic_keys == NULL) { + traffic_keys = ngx_array_create(pool, 1, + sizeof(ngx_http_vhost_traffic_status_limit_t)); + if (traffic_keys == NULL) { + return NGX_ERROR; + } + } + + traffic = ngx_array_push(traffic_keys); + if (traffic == NULL) { + return NGX_ERROR; + } + + ngx_memcpy(traffic, &traffics[traffic_uniqs[i].index], + sizeof(ngx_http_vhost_traffic_status_limit_t)); + + } + + if ((*keys)->nelts != traffic_keys->nelts) { + *keys = traffic_keys; + } + + return NGX_OK; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.h new file mode 100644 index 0000000..3d2f50e --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_limit.h @@ -0,0 +1,34 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_LIMIT_H_INCLUDED_ +#define _NGX_HTTP_VTS_LIMIT_H_INCLUDED_ + + +typedef struct { + ngx_http_complex_value_t key; + ngx_http_complex_value_t variable; + ngx_atomic_t size; + ngx_uint_t code; + unsigned type; /* unsigned type:5 */ +} ngx_http_vhost_traffic_status_limit_t; + + +ngx_int_t ngx_http_vhost_traffic_status_limit_handler(ngx_http_request_t *r); +ngx_int_t ngx_http_vhost_traffic_status_limit_handler_traffic(ngx_http_request_t *r, + ngx_array_t *traffics); + +ngx_int_t ngx_http_vhost_traffic_status_limit_traffic_unique( + ngx_pool_t *pool, ngx_array_t **keys); +char *ngx_http_vhost_traffic_status_limit_traffic(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +char *ngx_http_vhost_traffic_status_limit_traffic_by_set_key(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +#endif /* _NGX_HTTP_VTS_LIMIT_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.c new file mode 100644 index 0000000..bbb41eb --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.c @@ -0,0 +1,1104 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_variables.h" +#include "ngx_http_vhost_traffic_status_shm.h" +#include "ngx_http_vhost_traffic_status_filter.h" +#include "ngx_http_vhost_traffic_status_limit.h" +#include "ngx_http_vhost_traffic_status_display.h" +#include "ngx_http_vhost_traffic_status_set.h" +#include "ngx_http_vhost_traffic_status_dump.h" + + +static ngx_int_t ngx_http_vhost_traffic_status_handler(ngx_http_request_t *r); + +static void ngx_http_vhost_traffic_status_rbtree_insert_value( + ngx_rbtree_node_t *temp, ngx_rbtree_node_t *node, + ngx_rbtree_node_t *sentinel); +static ngx_int_t ngx_http_vhost_traffic_status_init_zone( + ngx_shm_zone_t *shm_zone, void *data); +static char *ngx_http_vhost_traffic_status_zone(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_vhost_traffic_status_dump(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_vhost_traffic_status_filter_max_node(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_vhost_traffic_status_average_method(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); +static char *ngx_http_vhost_traffic_status_histogram_buckets(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + +static ngx_int_t ngx_http_vhost_traffic_status_preconfiguration(ngx_conf_t *cf); +static ngx_int_t ngx_http_vhost_traffic_status_init(ngx_conf_t *cf); +static void *ngx_http_vhost_traffic_status_create_main_conf(ngx_conf_t *cf); +static char *ngx_http_vhost_traffic_status_init_main_conf(ngx_conf_t *cf, + void *conf); +static void *ngx_http_vhost_traffic_status_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_vhost_traffic_status_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_vhost_traffic_status_init_worker(ngx_cycle_t *cycle); +static void ngx_http_vhost_traffic_status_exit_worker(ngx_cycle_t *cycle); + + +static ngx_conf_enum_t ngx_http_vhost_traffic_status_display_format[] = { + { ngx_string("json"), NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON }, + { ngx_string("html"), NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_HTML }, + { ngx_string("jsonp"), NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP }, + { ngx_string("prometheus"), NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS }, + { ngx_null_string, 0 } +}; + + +static ngx_conf_enum_t ngx_http_vhost_traffic_status_average_method_post[] = { + { ngx_string("AMM"), NGX_HTTP_VHOST_TRAFFIC_STATUS_AVERAGE_METHOD_AMM }, + { ngx_string("WMA"), NGX_HTTP_VHOST_TRAFFIC_STATUS_AVERAGE_METHOD_WMA }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_vhost_traffic_status_commands[] = { + + { ngx_string("vhost_traffic_status"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, enable), + NULL }, + + { ngx_string("vhost_traffic_status_filter"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, filter), + NULL }, + + { ngx_string("vhost_traffic_status_filter_by_host"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, filter_host), + NULL }, + + { ngx_string("vhost_traffic_status_filter_check_duplicate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, filter_check_duplicate), + NULL }, + + { ngx_string("vhost_traffic_status_filter_by_set_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_vhost_traffic_status_filter_by_set_key, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_filter_max_node"), + NGX_HTTP_MAIN_CONF|NGX_CONF_1MORE, + ngx_http_vhost_traffic_status_filter_max_node, + 0, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_limit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, limit), + NULL }, + + { ngx_string("vhost_traffic_status_limit_check_duplicate"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, limit_check_duplicate), + NULL }, + + { ngx_string("vhost_traffic_status_limit_traffic"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_vhost_traffic_status_limit_traffic, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_limit_traffic_by_set_key"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE23, + ngx_http_vhost_traffic_status_limit_traffic_by_set_key, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_zone"), + NGX_HTTP_MAIN_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, + ngx_http_vhost_traffic_status_zone, + 0, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_dump"), + NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE12, + ngx_http_vhost_traffic_status_dump, + 0, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_display"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_NOARGS|NGX_CONF_TAKE1, + ngx_http_vhost_traffic_status_display, + 0, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_display_format"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, format), + &ngx_http_vhost_traffic_status_display_format }, + + { ngx_string("vhost_traffic_status_display_jsonp"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, jsonp), + NULL }, + + { ngx_string("vhost_traffic_status_display_sum_key"), + NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, sum_key), + NULL }, + + { ngx_string("vhost_traffic_status_set_by_filter"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF + |NGX_HTTP_LIF_CONF|NGX_CONF_TAKE2, + ngx_http_vhost_traffic_status_set_by_filter, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_average_method"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, + ngx_http_vhost_traffic_status_average_method, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_histogram_buckets"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE, + ngx_http_vhost_traffic_status_histogram_buckets, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("vhost_traffic_status_bypass_limit"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, bypass_limit), + NULL }, + + { ngx_string("vhost_traffic_status_bypass_stats"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_vhost_traffic_status_loc_conf_t, bypass_stats), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_vhost_traffic_status_module_ctx = { + ngx_http_vhost_traffic_status_preconfiguration, /* preconfiguration */ + ngx_http_vhost_traffic_status_init, /* postconfiguration */ + + ngx_http_vhost_traffic_status_create_main_conf, /* create main configuration */ + ngx_http_vhost_traffic_status_init_main_conf, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_vhost_traffic_status_create_loc_conf, /* create location configuration */ + ngx_http_vhost_traffic_status_merge_loc_conf, /* merge location configuration */ +}; + + +ngx_module_t ngx_http_vhost_traffic_status_module = { + NGX_MODULE_V1, + &ngx_http_vhost_traffic_status_module_ctx, /* module context */ + ngx_http_vhost_traffic_status_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + ngx_http_vhost_traffic_status_init_worker, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + ngx_http_vhost_traffic_status_exit_worker, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_vhost_traffic_status_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http vts handler"); + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (!ctx->enable || !vtscf->enable || vtscf->bypass_stats) { + return NGX_DECLINED; + } + if (vtscf->shm_zone == NULL) { + return NGX_DECLINED; + } + + rc = ngx_http_vhost_traffic_status_shm_add_server(r); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "handler::shm_add_server() failed"); + } + + rc = ngx_http_vhost_traffic_status_shm_add_upstream(r); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "handler::shm_add_upstream() failed"); + } + + rc = ngx_http_vhost_traffic_status_shm_add_filter(r); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "handler::shm_add_filter() failed"); + } + +#if (NGX_HTTP_CACHE) + rc = ngx_http_vhost_traffic_status_shm_add_cache(r); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "handler::shm_add_cache() failed"); + } +#endif + + return NGX_DECLINED; +} + + +ngx_msec_t +ngx_http_vhost_traffic_status_current_msec(void) +{ + time_t sec; + ngx_uint_t msec; + struct timeval tv; + + ngx_gettimeofday(&tv); + + sec = tv.tv_sec; + msec = tv.tv_usec / 1000; + + return (ngx_msec_t) sec * 1000 + msec; +} + + +ngx_msec_int_t +ngx_http_vhost_traffic_status_request_time(ngx_http_request_t *r) +{ + ngx_time_t *tp; + ngx_msec_int_t ms; + + tp = ngx_timeofday(); + + ms = (ngx_msec_int_t) + ((tp->sec - r->start_sec) * 1000 + (tp->msec - r->start_msec)); + return ngx_max(ms, 0); +} + + +ngx_msec_int_t +ngx_http_vhost_traffic_status_upstream_response_time(ngx_http_request_t *r) +{ + ngx_uint_t i; + ngx_msec_int_t ms; + ngx_http_upstream_state_t *state; + + state = r->upstream_states->elts; + + i = 0; + ms = 0; + for ( ;; ) { + if (state[i].status) { + +#if !defined(nginx_version) || nginx_version < 1009001 + ms += (ngx_msec_int_t) + (state[i].response_sec * 1000 + state[i].response_msec); +#else + ms += state[i].response_time; +#endif + + } + if (++i == r->upstream_states->nelts) { + break; + } + } + return ngx_max(ms, 0); +} + + +static void +ngx_http_vhost_traffic_status_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_rbtree_node_t **p; + ngx_http_vhost_traffic_status_node_t *vtsn, *vtsnt; + + for ( ;; ) { + + if (node->key < temp->key) { + + p = &temp->left; + + } else if (node->key > temp->key) { + + p = &temp->right; + + } else { /* node->key == temp->key */ + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + vtsnt = (ngx_http_vhost_traffic_status_node_t *) &temp->color; + + p = (ngx_memn2cmp(vtsn->data, vtsnt->data, vtsn->len, vtsnt->len) < 0) + ? &temp->left + : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_init_zone(ngx_shm_zone_t *shm_zone, void *data) +{ + ngx_http_vhost_traffic_status_ctx_t *octx = data; + + size_t len; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *sentinel; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = shm_zone->data; + + if (octx) { + ctx->rbtree = octx->rbtree; + return NGX_OK; + } + + shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; + + if (shm_zone->shm.exists) { + ctx->rbtree = shpool->data; + return NGX_OK; + } + + ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); + if (ctx->rbtree == NULL) { + return NGX_ERROR; + } + + shpool->data = ctx->rbtree; + + sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); + if (sentinel == NULL) { + return NGX_ERROR; + } + + ngx_rbtree_init(ctx->rbtree, sentinel, + ngx_http_vhost_traffic_status_rbtree_insert_value); + + len = sizeof(" in vhost_traffic_status_zone \"\"") + shm_zone->shm.name.len; + + shpool->log_ctx = ngx_slab_alloc(shpool, len); + if (shpool->log_ctx == NULL) { + return NGX_ERROR; + } + + ngx_sprintf(shpool->log_ctx, " in vhost_traffic_status_zone \"%V\"%Z", + &shm_zone->shm.name); + + return NGX_OK; +} + + +static char * +ngx_http_vhost_traffic_status_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + u_char *p; + ssize_t size; + ngx_str_t *value, name, s; + ngx_uint_t i; + ngx_shm_zone_t *shm_zone; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + value = cf->args->elts; + + ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + ctx->enable = 1; + + ngx_str_set(&name, NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_SHM_NAME); + + size = NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_SHM_SIZE; + + for (i = 1; i < cf->args->nelts; i++) { + if (ngx_strncmp(value[i].data, "shared:", 7) == 0) { + + name.data = value[i].data + 7; + + p = (u_char *) ngx_strchr(name.data, ':'); + if (p == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid shared size \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + name.len = p - name.data; + + s.data = p + 1; + s.len = value[i].data + value[i].len - s.data; + + size = ngx_parse_size(&s); + if (size == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid shared size \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + if (size < (ssize_t) (8 * ngx_pagesize)) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "shared \"%V\" is too small", &value[i]); + return NGX_CONF_ERROR; + } + + continue; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid parameter \"%V\"", &value[i]); + return NGX_CONF_ERROR; + } + + shm_zone = ngx_shared_memory_add(cf, &name, size, + &ngx_http_vhost_traffic_status_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + if (shm_zone->data) { + ctx = shm_zone->data; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "vhost_traffic_status: \"%V\" is already bound to key", + &name); + + return NGX_CONF_ERROR; + } + + ctx->shm_zone = shm_zone; + ctx->shm_name = name; + ctx->shm_size = size; + shm_zone->init = ngx_http_vhost_traffic_status_init_zone; + shm_zone->data = ctx; + + return NGX_CONF_OK; +} + + +static char * +ngx_http_vhost_traffic_status_dump(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx = conf; + + ngx_int_t rc; + ngx_str_t *value; + + value = cf->args->elts; + + ctx->dump = 1; + + ctx->dump_file = value[1]; + + /* second argument process */ + if (cf->args->nelts == 3) { + rc = ngx_parse_time(&value[2], 0); + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[2]); + goto invalid; + } + ctx->dump_period = (ngx_msec_t) rc; + } + + return NGX_CONF_OK; + +invalid: + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_vhost_traffic_status_filter_max_node(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx = conf; + + ngx_str_t *value; + ngx_int_t n; + ngx_uint_t i; + ngx_array_t *filter_max_node_matches; + ngx_http_vhost_traffic_status_filter_match_t *matches; + + filter_max_node_matches = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_match_t)); + if (filter_max_node_matches == NULL) { + goto invalid; + } + + value = cf->args->elts; + + n = ngx_atoi(value[1].data, value[1].len); + if (n < 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid number of filter_max_node \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + ctx->filter_max_node = (ngx_uint_t) n; + + /* arguments process */ + for (i = 2; i < cf->args->nelts; i++) { + matches = ngx_array_push(filter_max_node_matches); + if (matches == NULL) { + goto invalid; + } + + matches->match.data = value[i].data; + matches->match.len = value[i].len; + } + + ctx->filter_max_node_matches = filter_max_node_matches; + + return NGX_CONF_OK; + +invalid: + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_vhost_traffic_status_average_method(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf; + + char *rv; + ngx_int_t rc; + ngx_str_t *value; + + value = cf->args->elts; + + cmd->offset = offsetof(ngx_http_vhost_traffic_status_loc_conf_t, average_method); + cmd->post = &ngx_http_vhost_traffic_status_average_method_post; + + rv = ngx_conf_set_enum_slot(cf, cmd, conf); + if (rv != NGX_CONF_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[1]); + goto invalid; + } + + /* second argument process */ + if (cf->args->nelts == 3) { + rc = ngx_parse_time(&value[2], 0); + if (rc == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[2]); + goto invalid; + } + vtscf->average_period = (ngx_msec_t) rc; + } + + return NGX_CONF_OK; + +invalid: + + return NGX_CONF_ERROR; +} + + +static char * +ngx_http_vhost_traffic_status_histogram_buckets(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf; + + ngx_str_t *value; + ngx_int_t n; + ngx_uint_t i; + ngx_array_t *histogram_buckets; + ngx_http_vhost_traffic_status_node_histogram_t *buckets; + + histogram_buckets = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_vhost_traffic_status_node_histogram_t)); + if (histogram_buckets == NULL) { + goto invalid; + } + + value = cf->args->elts; + + /* arguments process */ + for (i = 1; i < cf->args->nelts; i++) { + if (i > NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "histogram bucket size exceeds %d", + NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN); + break; + } + + n = ngx_atofp(value[i].data, value[i].len, 3); + if (n == NGX_ERROR || n == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid parameter \"%V\"", &value[i]); + goto invalid; + } + + buckets = ngx_array_push(histogram_buckets); + if (buckets == NULL) { + goto invalid; + } + + buckets->msec = (ngx_msec_int_t) n; + } + + vtscf->histogram_buckets = histogram_buckets; + + return NGX_CONF_OK; + +invalid: + + return NGX_CONF_ERROR; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_preconfiguration(ngx_conf_t *cf) +{ + return ngx_http_vhost_traffic_status_add_variables(cf); +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http vts init"); + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + /* limit handler */ + h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_vhost_traffic_status_limit_handler; + + /* set handler */ + h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_vhost_traffic_status_set_handler; + + /* vts handler */ + h = ngx_array_push(&cmcf->phases[NGX_HTTP_LOG_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_vhost_traffic_status_handler; + + return NGX_OK; +} + + +static void * +ngx_http_vhost_traffic_status_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_vhost_traffic_status_ctx_t)); + if (ctx == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * ctx->rbtree = { NULL, ... }; + * ctx->filter_keys = { NULL, ... }; + * ctx->limit_traffics = { NULL, ... }; + * ctx->limit_filter_traffics = { NULL, ... }; + * + * ctx->filter_max_node_matches = { NULL, ... }; + * ctx->filter_max_node = 0; + * + * ctx->enable = 0; + * ctx->filter_check_duplicate = 0; + * ctx->limit_check_duplicate = 0; + * ctx->shm_zone = { NULL, ... }; + * ctx->shm_name = { 0, NULL }; + * ctx->shm_size = 0; + * + * ctx->dump = 0; + * ctx->dump_file = { 0, NULL }; + * ctx->dump_period = 0; + * ctx->dump_event = { NULL, ... }; + */ + + ctx->filter_max_node = NGX_CONF_UNSET_UINT; + ctx->enable = NGX_CONF_UNSET; + ctx->filter_check_duplicate = NGX_CONF_UNSET; + ctx->limit_check_duplicate = NGX_CONF_UNSET; + ctx->dump = NGX_CONF_UNSET; + ctx->dump_period = NGX_CONF_UNSET_MSEC; + + return ctx; +} + + +static char * +ngx_http_vhost_traffic_status_init_main_conf(ngx_conf_t *cf, void *conf) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx = conf; + + ngx_int_t rc; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http vts init main conf"); + + vtscf = ngx_http_conf_get_module_loc_conf(cf, ngx_http_vhost_traffic_status_module); + + if (vtscf->filter_check_duplicate != 0) { + rc = ngx_http_vhost_traffic_status_filter_unique(cf->pool, &ctx->filter_keys); + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "init_main_conf::filter_unique() failed"); + return NGX_CONF_ERROR; + } + } + + if (vtscf->limit_check_duplicate != 0) { + rc = ngx_http_vhost_traffic_status_limit_traffic_unique(cf->pool, &ctx->limit_traffics); + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "init_main_conf::limit_traffic_unique(server) failed"); + return NGX_CONF_ERROR; + } + + rc = ngx_http_vhost_traffic_status_limit_traffic_unique(cf->pool, + &ctx->limit_filter_traffics); + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "init_main_conf::limit_traffic_unique(filter) failed"); + return NGX_CONF_ERROR; + } + } + + ngx_conf_init_uint_value(ctx->filter_max_node, 0); + ngx_conf_init_value(ctx->enable, 0); + ngx_conf_init_value(ctx->filter_check_duplicate, vtscf->filter_check_duplicate); + ngx_conf_init_value(ctx->limit_check_duplicate, vtscf->limit_check_duplicate); + ngx_conf_init_value(ctx->dump, 0); + ngx_conf_merge_msec_value(ctx->dump_period, ctx->dump_period, + NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_DUMP_PERIOD * 1000); + + return NGX_CONF_OK; +} + + +static void * +ngx_http_vhost_traffic_status_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_vhost_traffic_status_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->shm_zone = { NULL, ... }; + * conf->shm_name = { 0, NULL }; + * conf->enable = 0; + * conf->filter = 0; + * conf->filter_host = 0; + * conf->filter_check_duplicate = 0; + * conf->filter_keys = { NULL, ... }; + * conf->filter_vars = { NULL, ... }; + * + * conf->limit = 0; + * conf->limit_check_duplicate = 0; + * conf->limit_traffics = { NULL, ... }; + * conf->limit_filter_traffics = { NULL, ... }; + * + * conf->stats = { 0, ... }; + * conf->start_msec = 0; + * conf->format = 0; + * conf->jsonp = { 0, NULL }; + * conf->sum_key = { 0, NULL }; + * conf->average_method = 0; + * conf->average_period = 0; + * conf->histogram_buckets = { NULL, ... }; + * conf->bypass_limit = 0; + * conf->bypass_stats = 0; + */ + + conf->shm_zone = NGX_CONF_UNSET_PTR; + conf->enable = NGX_CONF_UNSET; + conf->filter = NGX_CONF_UNSET; + conf->filter_host = NGX_CONF_UNSET; + conf->filter_check_duplicate = NGX_CONF_UNSET; + conf->filter_vars = NGX_CONF_UNSET_PTR; + + conf->limit = NGX_CONF_UNSET; + conf->limit_check_duplicate = NGX_CONF_UNSET; + + conf->start_msec = ngx_http_vhost_traffic_status_current_msec(); + conf->format = NGX_CONF_UNSET; + conf->average_method = NGX_CONF_UNSET; + conf->average_period = NGX_CONF_UNSET_MSEC; + conf->histogram_buckets = NGX_CONF_UNSET_PTR; + conf->bypass_limit = NGX_CONF_UNSET; + conf->bypass_stats = NGX_CONF_UNSET; + + conf->node_caches = ngx_pcalloc(cf->pool, sizeof(ngx_rbtree_node_t *) + * (NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG + 1)); + conf->node_caches[NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO] = NULL; + conf->node_caches[NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA] = NULL; + conf->node_caches[NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG] = NULL; + conf->node_caches[NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC] = NULL; + conf->node_caches[NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG] = NULL; + + return conf; +} + + +static char * +ngx_http_vhost_traffic_status_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_vhost_traffic_status_loc_conf_t *prev = parent; + ngx_http_vhost_traffic_status_loc_conf_t *conf = child; + + ngx_int_t rc; + ngx_str_t name; + ngx_shm_zone_t *shm_zone; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cf->log, 0, + "http vts merge loc conf"); + + ctx = ngx_http_conf_get_module_main_conf(cf, ngx_http_vhost_traffic_status_module); + + if (!ctx->enable) { + return NGX_CONF_OK; + } + + if (conf->filter_keys == NULL) { + conf->filter_keys = prev->filter_keys; + + } else { + if (conf->filter_check_duplicate == NGX_CONF_UNSET) { + conf->filter_check_duplicate = ctx->filter_check_duplicate; + } + if (conf->filter_check_duplicate != 0) { + rc = ngx_http_vhost_traffic_status_filter_unique(cf->pool, &conf->filter_keys); + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "mere_loc_conf::filter_unique() failed"); + return NGX_CONF_ERROR; + } + } + } + + if (conf->limit_traffics == NULL) { + conf->limit_traffics = prev->limit_traffics; + + } else { + if (conf->limit_check_duplicate == NGX_CONF_UNSET) { + conf->limit_check_duplicate = ctx->limit_check_duplicate; + } + + if (conf->limit_check_duplicate != 0) { + rc = ngx_http_vhost_traffic_status_limit_traffic_unique(cf->pool, + &conf->limit_traffics); + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "mere_loc_conf::limit_traffic_unique(server) failed"); + return NGX_CONF_ERROR; + } + } + } + + if (conf->limit_filter_traffics == NULL) { + conf->limit_filter_traffics = prev->limit_filter_traffics; + + } else { + if (conf->limit_check_duplicate == NGX_CONF_UNSET) { + conf->limit_check_duplicate = ctx->limit_check_duplicate; + } + + if (conf->limit_check_duplicate != 0) { + rc = ngx_http_vhost_traffic_status_limit_traffic_unique(cf->pool, + &conf->limit_filter_traffics); + if (rc != NGX_OK) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "mere_loc_conf::limit_traffic_unique(filter) failed"); + return NGX_CONF_ERROR; + } + } + } + + ngx_conf_merge_ptr_value(conf->shm_zone, prev->shm_zone, NULL); + ngx_conf_merge_value(conf->enable, prev->enable, 1); + ngx_conf_merge_value(conf->filter, prev->filter, 1); + ngx_conf_merge_value(conf->filter_host, prev->filter_host, 0); + ngx_conf_merge_value(conf->filter_check_duplicate, prev->filter_check_duplicate, 1); + ngx_conf_merge_value(conf->limit, prev->limit, 1); + ngx_conf_merge_value(conf->limit_check_duplicate, prev->limit_check_duplicate, 1); + ngx_conf_merge_ptr_value(conf->filter_vars, prev->filter_vars, NULL); + + ngx_conf_merge_value(conf->format, prev->format, + NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON); + ngx_conf_merge_str_value(conf->jsonp, prev->jsonp, + NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_JSONP); + ngx_conf_merge_str_value(conf->sum_key, prev->sum_key, + NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_SUM_KEY); + ngx_conf_merge_value(conf->average_method, prev->average_method, + NGX_HTTP_VHOST_TRAFFIC_STATUS_AVERAGE_METHOD_AMM); + ngx_conf_merge_msec_value(conf->average_period, prev->average_period, + NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_AVG_PERIOD * 1000); + ngx_conf_merge_ptr_value(conf->histogram_buckets, prev->histogram_buckets, NULL); + + ngx_conf_merge_value(conf->bypass_limit, prev->bypass_limit, 0); + ngx_conf_merge_value(conf->bypass_stats, prev->bypass_stats, 0); + + name = ctx->shm_name; + + shm_zone = ngx_shared_memory_add(cf, &name, 0, + &ngx_http_vhost_traffic_status_module); + if (shm_zone == NULL) { + return NGX_CONF_ERROR; + } + + conf->shm_zone = shm_zone; + conf->shm_name = name; + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_init_worker(ngx_cycle_t *cycle) +{ + ngx_event_t *dump_event; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "http vts init worker"); + + ctx = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_vhost_traffic_status_module); + + if (ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "vts::init_worker(): is bypassed due to no http block in configure file"); + return NGX_OK; + } + + if (!(ctx->enable & ctx->dump) || ctx->rbtree == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "vts::init_worker(): is bypassed"); + return NGX_OK; + } + + /* dumper */ + dump_event = &ctx->dump_event; + dump_event->handler = ngx_http_vhost_traffic_status_dump_handler; + dump_event->log = ngx_cycle->log; + dump_event->data = ctx; + ngx_add_timer(dump_event, 1000); + + /* restore */ + ngx_http_vhost_traffic_status_dump_restore(dump_event); + + return NGX_OK; +} + + +static void +ngx_http_vhost_traffic_status_exit_worker(ngx_cycle_t *cycle) +{ + ngx_event_t *dump_event; + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "http vts exit worker"); + + ctx = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_vhost_traffic_status_module); + + if (ctx == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "vts::exit_worker(): is bypassed due to no http block in configure file"); + return; + } + + if (!(ctx->enable & ctx->dump) || ctx->rbtree == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, cycle->log, 0, + "vts::exit_worker(): is bypassed"); + return; + } + + /* dump */ + dump_event = &ctx->dump_event; + dump_event->log = ngx_cycle->log; + dump_event->data = ctx; + ngx_http_vhost_traffic_status_dump_execute(dump_event); +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.h new file mode 100644 index 0000000..129172e --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module.h @@ -0,0 +1,303 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_MODULE_H_INCLUDED_ +#define _NGX_HTTP_VTS_MODULE_H_INCLUDED_ + + +#include +#include +#include +#include + +#include "ngx_http_vhost_traffic_status_string.h" +#include "ngx_http_vhost_traffic_status_node.h" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO 0 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA 1 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG 2 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC 3 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG 4 + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAMS (u_char *) "NO\0UA\0UG\0CC\0FG\0" + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_NONE 0 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_FIND 1 + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR (u_char) 0x1f + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_NONE 0 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSON 1 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_HTML 2 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_JSONP 3 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_FORMAT_PROMETHEUS 4 + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_AVERAGE_METHOD_AMM 0 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_AVERAGE_METHOD_WMA 1 + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_SHM_NAME "ngx_http_vhost_traffic_status" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_SHM_SIZE 0xfffff +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_JSONP "ngx_http_vhost_traffic_status_jsonp_callback" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_SUM_KEY "*" +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_AVG_PERIOD 60 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_DUMP_PERIOD 60 + +#define ngx_http_vhost_traffic_status_add_rc(s, n) { \ + if(s < 200) {n->stat_1xx_counter++;} \ + else if(s < 300) {n->stat_2xx_counter++;} \ + else if(s < 400) {n->stat_3xx_counter++;} \ + else if(s < 500) {n->stat_4xx_counter++;} \ + else {n->stat_5xx_counter++;} \ +} + +#if (NGX_HTTP_CACHE) + +#if !defined(nginx_version) || nginx_version < 1005007 +#define ngx_http_vhost_traffic_status_add_cc(s, n) { \ + if(s == NGX_HTTP_CACHE_MISS) {n->stat_cache_miss_counter++;} \ + else if(s == NGX_HTTP_CACHE_BYPASS) {n->stat_cache_bypass_counter++;} \ + else if(s == NGX_HTTP_CACHE_EXPIRED) {n->stat_cache_expired_counter++;} \ + else if(s == NGX_HTTP_CACHE_STALE) {n->stat_cache_stale_counter++;} \ + else if(s == NGX_HTTP_CACHE_UPDATING) {n->stat_cache_updating_counter++;} \ + else if(s == NGX_HTTP_CACHE_HIT) {n->stat_cache_hit_counter++;} \ + else if(s == NGX_HTTP_CACHE_SCARCE) {n->stat_cache_scarce_counter++;} \ +} +#else +#define ngx_http_vhost_traffic_status_add_cc(s, n) { \ + if(s == NGX_HTTP_CACHE_MISS) { \ + n->stat_cache_miss_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_BYPASS) { \ + n->stat_cache_bypass_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_EXPIRED) { \ + n->stat_cache_expired_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_STALE) { \ + n->stat_cache_stale_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_UPDATING) { \ + n->stat_cache_updating_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_REVALIDATED) { \ + n->stat_cache_revalidated_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_HIT) { \ + n->stat_cache_hit_counter++; \ + } \ + else if(s == NGX_HTTP_CACHE_SCARCE) { \ + n->stat_cache_scarce_counter++; \ + } \ +} +#endif + +#endif + +#if (NGX_HTTP_CACHE) +#define ngx_http_vhost_traffic_status_add_oc(o, c) { \ + if (o->stat_request_counter > c->stat_request_counter) { \ + c->stat_request_counter_oc++; \ + } \ + if (o->stat_in_bytes > c->stat_in_bytes) { \ + c->stat_in_bytes_oc++; \ + } \ + if (o->stat_out_bytes > c->stat_out_bytes) { \ + c->stat_out_bytes_oc++; \ + } \ + if (o->stat_1xx_counter > c->stat_1xx_counter) { \ + c->stat_1xx_counter_oc++; \ + } \ + if (o->stat_2xx_counter > c->stat_2xx_counter) { \ + c->stat_2xx_counter_oc++; \ + } \ + if (o->stat_3xx_counter > c->stat_3xx_counter) { \ + c->stat_3xx_counter_oc++; \ + } \ + if (o->stat_4xx_counter > c->stat_4xx_counter) { \ + c->stat_4xx_counter_oc++; \ + } \ + if (o->stat_5xx_counter > c->stat_5xx_counter) { \ + c->stat_5xx_counter_oc++; \ + } \ + if (o->stat_request_time_counter > c->stat_request_time_counter) { \ + c->stat_request_time_counter_oc++; \ + } \ + if (o->stat_cache_miss_counter > c->stat_cache_miss_counter) { \ + c->stat_cache_miss_counter_oc++; \ + } \ + if (o->stat_cache_bypass_counter > c->stat_cache_bypass_counter) { \ + c->stat_cache_bypass_counter_oc++; \ + } \ + if (o->stat_cache_expired_counter > c->stat_cache_expired_counter) { \ + c->stat_cache_expired_counter_oc++; \ + } \ + if (o->stat_cache_stale_counter > c->stat_cache_stale_counter) { \ + c->stat_cache_stale_counter_oc++; \ + } \ + if (o->stat_cache_updating_counter > c->stat_cache_updating_counter) { \ + c->stat_cache_updating_counter_oc++; \ + } \ + if (o->stat_cache_revalidated_counter > c->stat_cache_revalidated_counter) \ + { \ + c->stat_cache_revalidated_counter_oc++; \ + } \ + if (o->stat_cache_hit_counter > c->stat_cache_hit_counter) { \ + c->stat_cache_hit_counter_oc++; \ + } \ + if (o->stat_cache_scarce_counter > c->stat_cache_scarce_counter) { \ + c->stat_cache_scarce_counter_oc++; \ + } \ +} +#else +#define ngx_http_vhost_traffic_status_add_oc(o, c) { \ + if (o->stat_request_counter > c->stat_request_counter) { \ + c->stat_request_counter_oc++; \ + } \ + if (o->stat_in_bytes > c->stat_in_bytes) { \ + c->stat_in_bytes_oc++; \ + } \ + if (o->stat_out_bytes > c->stat_out_bytes) { \ + c->stat_out_bytes_oc++; \ + } \ + if (o->stat_1xx_counter > c->stat_1xx_counter) { \ + c->stat_1xx_counter_oc++; \ + } \ + if (o->stat_2xx_counter > c->stat_2xx_counter) { \ + c->stat_2xx_counter_oc++; \ + } \ + if (o->stat_3xx_counter > c->stat_3xx_counter) { \ + c->stat_3xx_counter_oc++; \ + } \ + if (o->stat_4xx_counter > c->stat_4xx_counter) { \ + c->stat_4xx_counter_oc++; \ + } \ + if (o->stat_5xx_counter > c->stat_5xx_counter) { \ + c->stat_5xx_counter_oc++; \ + } \ + if (o->stat_request_time_counter > c->stat_request_time_counter) { \ + c->stat_request_time_counter_oc++; \ + } \ +} +#endif + +#define ngx_http_vhost_traffic_status_group_to_string(n) (u_char *) ( \ + (n > 4) \ + ? NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAMS \ + : NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAMS + 3 * n \ +) + +#define ngx_http_vhost_traffic_status_string_to_group(s) (unsigned) ( \ +{ \ + unsigned n = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; \ + if (*s == 'N' && *(s + 1) == 'O') { \ + n = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; \ + } else if (*s == 'U' && *(s + 1) == 'A') { \ + n = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA; \ + } else if (*s == 'U' && *(s + 1) == 'G') { \ + n = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG; \ + } else if (*s == 'C' && *(s + 1) == 'C') { \ + n = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC; \ + } else if (*s == 'F' && *(s + 1) == 'G') { \ + n = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG; \ + } \ + n; \ +} \ +) + +#define ngx_http_vhost_traffic_status_max_integer (NGX_ATOMIC_T_LEN < 12) \ + ? "4294967295" \ + : "18446744073709551615" + +#define ngx_http_vhost_traffic_status_boolean_to_string(b) (b) ? "true" : "false" + +#define ngx_http_vhost_traffic_status_triangle(n) (unsigned) ( \ + n * (n + 1) / 2 \ +) + + +typedef struct { + ngx_rbtree_t *rbtree; + + /* array of ngx_http_vhost_traffic_status_filter_t */ + ngx_array_t *filter_keys; + + /* array of ngx_http_vhost_traffic_status_limit_t */ + ngx_array_t *limit_traffics; + + /* array of ngx_http_vhost_traffic_status_limit_t */ + ngx_array_t *limit_filter_traffics; + + /* array of ngx_http_vhost_traffic_status_filter_match_t */ + ngx_array_t *filter_max_node_matches; + + ngx_uint_t filter_max_node; + + ngx_flag_t enable; + ngx_flag_t filter_check_duplicate; + ngx_flag_t limit_check_duplicate; + ngx_shm_zone_t *shm_zone; + ngx_str_t shm_name; + ssize_t shm_size; + + ngx_flag_t dump; + ngx_str_t dump_file; + ngx_msec_t dump_period; + ngx_event_t dump_event; +} ngx_http_vhost_traffic_status_ctx_t; + + +typedef struct { + ngx_shm_zone_t *shm_zone; + ngx_str_t shm_name; + ngx_flag_t enable; + ngx_flag_t filter; + ngx_flag_t filter_host; + ngx_flag_t filter_check_duplicate; + + /* array of ngx_http_vhost_traffic_status_filter_t */ + ngx_array_t *filter_keys; + + /* array of ngx_http_vhost_traffic_status_filter_variable_t */ + ngx_array_t *filter_vars; + + ngx_flag_t limit; + ngx_flag_t limit_check_duplicate; + + /* array of ngx_http_vhost_traffic_status_limit_t */ + ngx_array_t *limit_traffics; + + /* array of ngx_http_vhost_traffic_status_limit_t */ + ngx_array_t *limit_filter_traffics; + + ngx_http_vhost_traffic_status_node_t stats; + ngx_msec_t start_msec; + ngx_flag_t format; + ngx_str_t jsonp; + ngx_str_t sum_key; + + ngx_flag_t average_method; + ngx_msec_t average_period; + + /* array of ngx_http_vhost_traffic_status_node_histogram_t */ + ngx_array_t *histogram_buckets; + + ngx_flag_t bypass_limit; + ngx_flag_t bypass_stats; + + ngx_rbtree_node_t **node_caches; +} ngx_http_vhost_traffic_status_loc_conf_t; + + +ngx_msec_t ngx_http_vhost_traffic_status_current_msec(void); +ngx_msec_int_t ngx_http_vhost_traffic_status_request_time(ngx_http_request_t *r); +ngx_msec_int_t ngx_http_vhost_traffic_status_upstream_response_time(ngx_http_request_t *r); + +extern ngx_module_t ngx_http_vhost_traffic_status_module; + + +#endif /* _NGX_HTTP_VTS_MODULE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module_html.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module_html.h new file mode 100644 index 0000000..a918b2f --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_module_html.h @@ -0,0 +1,8078 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_MODULE_HTML_H_INCLUDED_ +#define _NGX_HTTP_VTS_MODULE_HTML_H_INCLUDED_ + + +static char NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA[] = { +0x3c, 0x21, 0x64, 0x6f, 0x63, 0x74, 0x79, 0x70, 0x65, 0x20, 0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x3c, +0x68, 0x74, 0x6d, 0x6c, 0x20, 0x6c, 0x61, 0x6e, 0x67, 0x3d, 0x65, 0x6e, 0x3e, 0x3c, 0x68, 0x65, +0x61, 0x64, 0x3e, 0x3c, 0x6d, 0x65, 0x74, 0x61, 0x20, 0x63, 0x68, 0x61, 0x72, 0x73, 0x65, 0x74, +0x3d, 0x75, 0x74, 0x66, 0x2d, 0x38, 0x3e, 0x3c, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x6e, 0x67, +0x69, 0x6e, 0x78, 0x20, 0x76, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, +0x63, 0x20, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x20, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, +0x3c, 0x2f, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x3e, 0x20, 0x3c, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, +0x62, 0x6f, 0x64, 0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, +0x77, 0x68, 0x69, 0x74, 0x65, 0x3b, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x62, 0x6c, 0x61, 0x63, +0x6b, 0x3b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x66, 0x61, 0x6d, 0x69, 0x6c, 0x79, 0x3a, 0x48, 0x65, +0x6c, 0x76, 0x65, 0x74, 0x69, 0x63, 0x61, 0x2c, 0x41, 0x72, 0x69, 0x61, 0x6c, 0x2c, 0x73, 0x61, +0x6e, 0x73, 0x2d, 0x73, 0x65, 0x72, 0x69, 0x66, 0x7d, 0x68, 0x31, 0x7b, 0x6d, 0x61, 0x72, 0x67, +0x69, 0x6e, 0x3a, 0x2e, 0x35, 0x65, 0x6d, 0x20, 0x30, 0x20, 0x30, 0x20, 0x30, 0x7d, 0x68, 0x32, +0x7b, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x2e, 0x38, 0x65, 0x6d, 0x20, 0x30, 0x20, 0x2e, +0x33, 0x65, 0x6d, 0x20, 0x30, 0x7d, 0x68, 0x33, 0x7b, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, +0x2e, 0x35, 0x65, 0x6d, 0x20, 0x30, 0x20, 0x2e, 0x33, 0x65, 0x6d, 0x20, 0x30, 0x7d, 0x74, 0x61, +0x62, 0x6c, 0x65, 0x7b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x2e, 0x38, +0x65, 0x6d, 0x3b, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x3a, 0x2e, 0x35, 0x65, 0x6d, 0x20, 0x30, +0x3b, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x2d, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, +0x3a, 0x63, 0x6f, 0x6c, 0x6c, 0x61, 0x70, 0x73, 0x65, 0x3b, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, +0x2d, 0x62, 0x6f, 0x74, 0x74, 0x6f, 0x6d, 0x3a, 0x31, 0x70, 0x78, 0x20, 0x23, 0x44, 0x45, 0x44, +0x20, 0x73, 0x6f, 0x6c, 0x69, 0x64, 0x7d, 0x74, 0x68, 0x65, 0x61, 0x64, 0x20, 0x74, 0x68, 0x7b, +0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, 0x65, 0x6d, 0x3b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x23, 0x44, 0x45, 0x44, 0x3b, 0x70, 0x61, +0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x2e, 0x31, 0x65, 0x6d, 0x20, 0x2e, 0x33, 0x65, 0x6d, 0x3b, +0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x2e, 0x32, 0x65, 0x6d, 0x20, 0x73, 0x6f, 0x6c, 0x69, +0x64, 0x20, 0x23, 0x46, 0x46, 0x46, 0x7d, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x72, 0x2e, +0x6f, 0x64, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x23, +0x66, 0x35, 0x66, 0x35, 0x66, 0x35, 0x7d, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x68, 0x7b, +0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, 0x3a, 0x6c, 0x65, 0x66, 0x74, 0x7d, +0x74, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x64, 0x7b, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, +0x31, 0x2e, 0x32, 0x65, 0x6d, 0x3b, 0x74, 0x65, 0x78, 0x74, 0x2d, 0x61, 0x6c, 0x69, 0x67, 0x6e, +0x3a, 0x72, 0x69, 0x67, 0x68, 0x74, 0x7d, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x74, 0x64, 0x2e, +0x6b, 0x65, 0x79, 0x7b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x31, 0x65, +0x6d, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x23, 0x44, 0x45, +0x44, 0x3b, 0x70, 0x61, 0x64, 0x64, 0x69, 0x6e, 0x67, 0x3a, 0x2e, 0x31, 0x65, 0x6d, 0x20, 0x2e, +0x33, 0x65, 0x6d, 0x3b, 0x62, 0x6f, 0x72, 0x64, 0x65, 0x72, 0x3a, 0x2e, 0x32, 0x65, 0x6d, 0x20, +0x73, 0x6f, 0x6c, 0x69, 0x64, 0x20, 0x23, 0x46, 0x46, 0x46, 0x7d, 0x64, 0x69, 0x76, 0x2e, 0x75, +0x70, 0x64, 0x61, 0x74, 0x65, 0x7b, 0x6d, 0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x74, 0x6f, 0x70, +0x3a, 0x33, 0x32, 0x70, 0x78, 0x3b, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x23, 0x36, 0x39, 0x36, +0x39, 0x36, 0x39, 0x7d, 0x64, 0x69, 0x76, 0x2e, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x7b, 0x6d, +0x61, 0x72, 0x67, 0x69, 0x6e, 0x2d, 0x74, 0x6f, 0x70, 0x3a, 0x31, 0x36, 0x70, 0x78, 0x7d, 0x61, +0x3a, 0x6c, 0x69, 0x6e, 0x6b, 0x7b, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x23, 0x36, 0x36, 0x66, +0x3b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x2e, 0x37, 0x65, 0x6d, 0x7d, +0x61, 0x3a, 0x76, 0x69, 0x73, 0x69, 0x74, 0x65, 0x64, 0x7b, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, +0x23, 0x36, 0x36, 0x66, 0x3b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x2e, +0x37, 0x65, 0x6d, 0x7d, 0x61, 0x3a, 0x61, 0x63, 0x74, 0x69, 0x76, 0x65, 0x7b, 0x63, 0x6f, 0x6c, +0x6f, 0x72, 0x3a, 0x23, 0x32, 0x32, 0x32, 0x3b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, +0x65, 0x3a, 0x2e, 0x37, 0x65, 0x6d, 0x7d, 0x61, 0x3a, 0x68, 0x6f, 0x76, 0x65, 0x72, 0x7b, 0x63, +0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x23, 0x30, 0x30, 0x30, 0x3b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x63, 0x6f, 0x6c, 0x6f, 0x72, 0x3a, 0x23, 0x65, 0x30, 0x65, 0x38, +0x66, 0x66, 0x3b, 0x66, 0x6f, 0x6e, 0x74, 0x2d, 0x73, 0x69, 0x7a, 0x65, 0x3a, 0x2e, 0x37, 0x65, +0x6d, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x7b, 0x77, 0x69, 0x64, 0x74, 0x68, 0x3a, 0x31, 0x36, +0x70, 0x78, 0x3b, 0x68, 0x65, 0x69, 0x67, 0x68, 0x74, 0x3a, 0x31, 0x31, 0x70, 0x78, 0x3b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x3a, 0x75, 0x72, 0x6c, 0x28, 0x22, 0x64, +0x61, 0x74, 0x61, 0x3a, 0x69, 0x6d, 0x61, 0x67, 0x65, 0x2f, 0x70, 0x6e, 0x67, 0x3b, 0x62, 0x61, +0x73, 0x65, 0x36, 0x34, 0x2c, 0x69, 0x56, 0x42, 0x4f, 0x52, 0x77, 0x30, 0x4b, 0x47, 0x67, 0x6f, +0x41, 0x41, 0x41, 0x41, 0x4e, 0x53, 0x55, 0x68, 0x45, 0x55, 0x67, 0x41, 0x41, 0x41, 0x51, 0x41, +0x41, 0x41, 0x41, 0x43, 0x77, 0x43, 0x41, 0x59, 0x41, 0x41, 0x41, 0x44, 0x67, 0x7a, 0x37, 0x43, +0x6e, 0x41, 0x41, 0x41, 0x41, 0x43, 0x58, 0x42, 0x49, 0x57, 0x58, 0x4d, 0x41, 0x41, 0x41, 0x37, +0x45, 0x41, 0x41, 0x41, 0x4f, 0x78, 0x41, 0x47, 0x56, 0x4b, 0x77, 0x34, 0x62, 0x41, 0x41, 0x41, +0x67, 0x41, 0x45, 0x6c, 0x45, 0x51, 0x56, 0x52, 0x34, 0x6e, 0x4b, 0x79, 0x64, 0x64, 0x35, 0x77, +0x64, 0x56, 0x64, 0x6e, 0x48, 0x76, 0x7a, 0x50, 0x33, 0x37, 0x74, 0x31, 0x65, 0x6b, 0x73, 0x30, +0x6d, 0x75, 0x30, 0x6d, 0x57, 0x64, 0x45, 0x71, 0x6b, 0x64, 0x77, 0x67, 0x64, 0x36, 0x56, 0x4a, +0x65, 0x51, 0x4f, 0x53, 0x46, 0x55, 0x41, 0x57, 0x6b, 0x69, 0x74, 0x52, 0x49, 0x55, 0x41, 0x48, +0x42, 0x55, 0x42, 0x53, 0x44, 0x38, 0x41, 0x49, 0x69, 0x49, 0x41, 0x49, 0x4b, 0x41, 0x6f, 0x49, +0x59, 0x53, 0x67, 0x52, 0x70, 0x45, 0x51, 0x68, 0x56, 0x49, 0x45, 0x43, 0x4b, 0x70, 0x4a, 0x43, +0x45, 0x4a, 0x4b, 0x52, 0x75, 0x74, 0x74, 0x2b, 0x5a, 0x55, 0x39, 0x38, 0x2f, 0x7a, 0x70, 0x6d, +0x35, 0x39, 0x2b, 0x35, 0x75, 0x51, 0x46, 0x2f, 0x66, 0x2b, 0x58, 0x7a, 0x6d, 0x4d, 0x33, 0x50, +0x6e, 0x33, 0x6a, 0x4f, 0x6e, 0x50, 0x63, 0x39, 0x7a, 0x6e, 0x76, 0x49, 0x37, 0x7a, 0x77, 0x32, +0x73, 0x74, 0x66, 0x77, 0x6e, 0x78, 0x37, 0x6b, 0x2f, 0x57, 0x6d, 0x43, 0x6a, 0x79, 0x41, 0x42, +0x67, 0x44, 0x45, 0x51, 0x69, 0x35, 0x49, 0x2b, 0x33, 0x62, 0x34, 0x55, 0x78, 0x5a, 0x52, 0x67, +0x6a, 0x41, 0x56, 0x44, 0x4b, 0x2f, 0x56, 0x5a, 0x56, 0x67, 0x77, 0x47, 0x55, 0x50, 0x77, 0x30, +0x77, 0x76, 0x4d, 0x2f, 0x37, 0x44, 0x4a, 0x44, 0x35, 0x63, 0x5a, 0x38, 0x66, 0x43, 0x58, 0x38, +0x76, 0x2b, 0x74, 0x39, 0x76, 0x74, 0x57, 0x67, 0x72, 0x4f, 0x6a, 0x73, 0x37, 0x30, 0x2f, 0x4a, +0x43, 0x43, 0x46, 0x61, 0x76, 0x57, 0x34, 0x63, 0x70, 0x4b, 0x38, 0x4e, 0x49, 0x58, 0x37, 0x2f, +0x2f, 0x62, 0x6d, 0x6f, 0x54, 0x2f, 0x4f, 0x70, 0x30, 0x49, 0x50, 0x4c, 0x6c, 0x67, 0x54, 0x33, +0x75, 0x67, 0x62, 0x66, 0x2b, 0x67, 0x2f, 0x36, 0x66, 0x63, 0x75, 0x37, 0x7a, 0x50, 0x4e, 0x75, +0x56, 0x59, 0x57, 0x4d, 0x6d, 0x35, 0x4c, 0x46, 0x6f, 0x4e, 0x75, 0x55, 0x5a, 0x4f, 0x43, 0x62, +0x63, 0x67, 0x38, 0x4f, 0x2f, 0x55, 0x63, 0x55, 0x31, 0x71, 0x39, 0x35, 0x6b, 0x74, 0x78, 0x63, +0x61, 0x49, 0x44, 0x59, 0x51, 0x43, 0x56, 0x41, 0x52, 0x78, 0x42, 0x4a, 0x36, 0x42, 0x56, 0x6a, +0x58, 0x69, 0x45, 0x38, 0x71, 0x62, 0x79, 0x4e, 0x72, 0x67, 0x4e, 0x43, 0x39, 0x4c, 0x36, 0x74, +0x41, 0x53, 0x63, 0x6a, 0x36, 0x5a, 0x69, 0x5a, 0x66, 0x4a, 0x64, 0x31, 0x4f, 0x68, 0x73, 0x54, +0x34, 0x37, 0x77, 0x2b, 0x59, 0x4d, 0x41, 0x48, 0x61, 0x32, 0x34, 0x73, 0x47, 0x30, 0x47, 0x43, +0x45, 0x77, 0x43, 0x67, 0x46, 0x51, 0x6f, 0x44, 0x57, 0x36, 0x65, 0x39, 0x4e, 0x30, 0x52, 0x67, +0x6e, 0x5a, 0x36, 0x36, 0x6a, 0x6f, 0x31, 0x2b, 0x66, 0x6a, 0x41, 0x45, 0x47, 0x31, 0x5a, 0x66, +0x2b, 0x2f, 0x73, 0x73, 0x76, 0x33, 0x64, 0x57, 0x59, 0x6b, 0x6e, 0x50, 0x6a, 0x34, 0x59, 0x64, +0x54, 0x31, 0x48, 0x78, 0x69, 0x61, 0x37, 0x47, 0x2b, 0x54, 0x45, 0x4a, 0x5a, 0x4b, 0x67, 0x69, +0x77, 0x31, 0x71, 0x5a, 0x74, 0x31, 0x34, 0x44, 0x79, 0x64, 0x50, 0x66, 0x48, 0x33, 0x79, 0x32, +0x67, 0x4f, 0x35, 0x6b, 0x67, 0x77, 0x47, 0x41, 0x51, 0x42, 0x6f, 0x7a, 0x79, 0x30, 0x36, 0x77, +0x4d, 0x79, 0x68, 0x67, 0x69, 0x5a, 0x52, 0x44, 0x47, 0x6e, 0x5a, 0x45, 0x79, 0x43, 0x47, 0x58, +0x49, 0x68, 0x56, 0x44, 0x78, 0x77, 0x34, 0x61, 0x53, 0x37, 0x67, 0x74, 0x68, 0x69, 0x43, 0x4c, +0x51, 0x75, 0x72, 0x69, 0x6e, 0x68, 0x62, 0x66, 0x44, 0x49, 0x30, 0x7a, 0x68, 0x48, 0x4c, 0x36, +0x4a, 0x4a, 0x67, 0x66, 0x73, 0x30, 0x37, 0x66, 0x76, 0x41, 0x33, 0x7a, 0x2b, 0x71, 0x76, 0x4f, +0x7a, 0x4b, 0x64, 0x66, 0x7a, 0x57, 0x73, 0x56, 0x34, 0x72, 0x76, 0x70, 0x72, 0x47, 0x37, 0x65, +0x32, 0x50, 0x30, 0x58, 0x57, 0x47, 0x43, 0x34, 0x32, 0x42, 0x33, 0x50, 0x46, 0x38, 0x4f, 0x55, +0x63, 0x73, 0x50, 0x4e, 0x6d, 0x48, 0x50, 0x61, 0x62, 0x39, 0x64, 0x44, 0x54, 0x54, 0x6a, 0x4a, +0x37, 0x68, 0x33, 0x33, 0x33, 0x6d, 0x38, 0x79, 0x38, 0x66, 0x77, 0x62, 0x51, 0x42, 0x67, 0x6a, +0x47, 0x2f, 0x4f, 0x71, 0x58, 0x64, 0x41, 0x74, 0x44, 0x4e, 0x70, 0x63, 0x6c, 0x69, 0x68, 0x54, +0x47, 0x47, 0x4a, 0x51, 0x79, 0x43, 0x4b, 0x4f, 0x51, 0x43, 0x73, 0x63, 0x38, 0x79, 0x68, 0x53, +0x75, 0x77, 0x74, 0x38, 0x4c, 0x42, 0x64, 0x6b, 0x51, 0x74, 0x74, 0x38, 0x4d, 0x49, 0x6c, 0x58, +0x61, 0x59, 0x46, 0x55, 0x30, 0x67, 0x46, 0x39, 0x54, 0x50, 0x74, 0x74, 0x76, 0x39, 0x76, 0x2f, +0x4e, 0x6f, 0x37, 0x74, 0x58, 0x4d, 0x66, 0x6e, 0x6f, 0x46, 0x67, 0x43, 0x30, 0x74, 0x53, 0x67, +0x56, 0x41, 0x74, 0x4d, 0x4a, 0x41, 0x6b, 0x30, 0x6d, 0x49, 0x37, 0x42, 0x57, 0x6b, 0x73, 0x74, +0x4a, 0x6a, 0x42, 0x46, 0x6b, 0x4c, 0x68, 0x5a, 0x59, 0x4b, 0x54, 0x42, 0x43, 0x59, 0x4f, 0x4f, +0x59, 0x44, 0x51, 0x38, 0x2f, 0x37, 0x46, 0x35, 0x79, 0x39, 0x64, 0x55, 0x41, 0x57, 0x47, 0x4d, +0x49, 0x6a, 0x4f, 0x48, 0x79, 0x77, 0x7a, 0x58, 0x4b, 0x61, 0x4c, 0x52, 0x52, 0x4b, 0x4b, 0x74, +0x51, 0x52, 0x71, 0x47, 0x4d, 0x52, 0x47, 0x70, 0x2f, 0x4e, 0x51, 0x71, 0x70, 0x4a, 0x54, 0x50, +0x75, 0x6d, 0x45, 0x46, 0x62, 0x57, 0x78, 0x73, 0x2f, 0x2f, 0x65, 0x6c, 0x50, 0x58, 0x66, 0x31, +0x47, 0x59, 0x37, 0x51, 0x42, 0x4b, 0x51, 0x6d, 0x55, 0x4a, 0x69, 0x4d, 0x46, 0x56, 0x6b, 0x70, +0x79, 0x55, 0x6d, 0x4b, 0x45, 0x34, 0x4a, 0x67, 0x78, 0x46, 0x72, 0x6c, 0x46, 0x44, 0x30, 0x49, +0x4c, 0x59, 0x68, 0x33, 0x7a, 0x38, 0x4c, 0x30, 0x50, 0x38, 0x78, 0x4e, 0x67, 0x2f, 0x74, 0x56, +0x58, 0x73, 0x34, 0x45, 0x43, 0x63, 0x51, 0x64, 0x6f, 0x61, 0x69, 0x6f, 0x31, 0x68, 0x30, 0x31, +0x53, 0x57, 0x4b, 0x4e, 0x34, 0x2b, 0x68, 0x58, 0x46, 0x6d, 0x6a, 0x5a, 0x4a, 0x50, 0x71, 0x39, +0x51, 0x55, 0x69, 0x4b, 0x56, 0x6f, 0x6b, 0x35, 0x4b, 0x52, 0x73, 0x2b, 0x59, 0x77, 0x65, 0x4e, +0x52, 0x77, 0x4f, 0x72, 0x72, 0x74, 0x75, 0x61, 0x35, 0x71, 0x4a, 0x5a, 0x44, 0x56, 0x70, 0x55, +0x54, 0x35, 0x69, 0x4d, 0x65, 0x62, 0x64, 0x6d, 0x65, 0x45, 0x2b, 0x56, 0x53, 0x48, 0x67, 0x6a, +0x50, 0x34, 0x4a, 0x70, 0x76, 0x62, 0x6b, 0x51, 0x59, 0x69, 0x7a, 0x51, 0x47, 0x72, 0x52, 0x78, +0x78, 0x61, 0x32, 0x76, 0x52, 0x31, 0x6e, 0x4c, 0x76, 0x35, 0x4c, 0x76, 0x49, 0x41, 0x69, 0x32, +0x33, 0x54, 0x58, 0x66, 0x39, 0x31, 0x78, 0x70, 0x6a, 0x44, 0x46, 0x6d, 0x74, 0x75, 0x57, 0x39, +0x6a, 0x44, 0x38, 0x64, 0x58, 0x68, 0x6f, 0x52, 0x61, 0x63, 0x2f, 0x2f, 0x36, 0x62, 0x73, 0x36, +0x72, 0x7a, 0x71, 0x43, 0x56, 0x49, 0x6c, 0x41, 0x43, 0x49, 0x79, 0x56, 0x47, 0x53, 0x6a, 0x36, +0x39, 0x2b, 0x79, 0x46, 0x6f, 0x61, 0x79, 0x4f, 0x38, 0x34, 0x59, 0x5a, 0x30, 0x2f, 0x4c, 0x43, +0x57, 0x6a, 0x4e, 0x5a, 0x6b, 0x6a, 0x4a, 0x74, 0x6f, 0x71, 0x7a, 0x55, 0x32, 0x75, 0x57, 0x72, +0x74, 0x6e, 0x69, 0x6b, 0x46, 0x57, 0x74, 0x4e, 0x35, 0x36, 0x36, 0x30, 0x41, 0x31, 0x4e, 0x58, +0x56, 0x75, 0x66, 0x4a, 0x46, 0x69, 0x34, 0x48, 0x39, 0x77, 0x53, 0x57, 0x67, 0x2f, 0x57, 0x2b, +0x56, 0x77, 0x6a, 0x59, 0x32, 0x59, 0x76, 0x31, 0x76, 0x6b, 0x6e, 0x50, 0x56, 0x71, 0x6c, 0x55, +0x59, 0x59, 0x4d, 0x73, 0x7a, 0x7a, 0x67, 0x42, 0x72, 0x6e, 0x65, 0x51, 0x77, 0x78, 0x70, 0x55, +0x78, 0x42, 0x72, 0x54, 0x47, 0x65, 0x69, 0x47, 0x45, 0x55, 0x75, 0x6d, 0x39, 0x46, 0x51, 0x4b, +0x6b, 0x35, 0x47, 0x2f, 0x76, 0x76, 0x30, 0x2b, 0x6e, 0x67, 0x72, 0x50, 0x48, 0x4a, 0x4c, 0x52, +0x72, 0x73, 0x54, 0x62, 0x41, 0x57, 0x4d, 0x39, 0x67, 0x78, 0x71, 0x4a, 0x74, 0x67, 0x44, 0x59, +0x5a, 0x4e, 0x43, 0x48, 0x61, 0x57, 0x50, 0x2f, 0x4d, 0x6e, 0x52, 0x66, 0x4e, 0x37, 0x71, 0x5a, +0x32, 0x50, 0x64, 0x78, 0x33, 0x6e, 0x78, 0x4d, 0x32, 0x31, 0x6c, 0x69, 0x30, 0x44, 0x74, 0x41, +0x61, 0x74, 0x48, 0x61, 0x30, 0x4b, 0x47, 0x56, 0x49, 0x54, 0x6e, 0x58, 0x78, 0x44, 0x64, 0x35, +0x6e, 0x54, 0x4c, 0x69, 0x51, 0x45, 0x45, 0x48, 0x56, 0x73, 0x44, 0x39, 0x51, 0x4e, 0x6d, 0x45, +0x55, 0x6a, 0x37, 0x2f, 0x38, 0x49, 0x6c, 0x78, 0x2b, 0x54, 0x54, 0x2f, 0x36, 0x51, 0x32, 0x75, +0x73, 0x30, 0x71, 0x41, 0x56, 0x67, 0x56, 0x4a, 0x6b, 0x6c, 0x43, 0x4b, 0x55, 0x30, 0x6f, 0x31, +0x6a, 0x30, 0x62, 0x56, 0x37, 0x78, 0x67, 0x78, 0x75, 0x6d, 0x46, 0x66, 0x46, 0x41, 0x31, 0x65, +0x4e, 0x35, 0x64, 0x52, 0x54, 0x39, 0x79, 0x58, 0x36, 0x63, 0x44, 0x4e, 0x73, 0x6c, 0x4f, 0x64, +0x62, 0x6f, 0x38, 0x62, 0x53, 0x30, 0x4e, 0x54, 0x41, 0x53, 0x34, 0x73, 0x6a, 0x72, 0x6d, 0x68, +0x65, 0x68, 0x56, 0x61, 0x47, 0x76, 0x4a, 0x43, 0x63, 0x66, 0x4f, 0x51, 0x32, 0x5a, 0x4c, 0x4d, +0x42, 0x70, 0x78, 0x79, 0x7a, 0x41, 0x7a, 0x4e, 0x6e, 0x4c, 0x65, 0x4c, 0x68, 0x58, 0x30, 0x79, +0x6e, 0x4c, 0x56, 0x4c, 0x63, 0x4e, 0x71, 0x6d, 0x46, 0x77, 0x39, 0x35, 0x38, 0x6b, 0x72, 0x2f, +0x73, 0x65, 0x79, 0x49, 0x52, 0x47, 0x59, 0x77, 0x31, 0x62, 0x76, 0x69, 0x4d, 0x63, 0x58, 0x30, +0x31, 0x78, 0x76, 0x47, 0x77, 0x4e, 0x76, 0x37, 0x65, 0x49, 0x72, 0x58, 0x6c, 0x74, 0x6e, 0x74, +0x6d, 0x51, 0x37, 0x66, 0x69, 0x36, 0x6f, 0x50, 0x63, 0x41, 0x42, 0x6f, 0x4c, 0x78, 0x6f, 0x2b, +0x4e, 0x38, 0x75, 0x57, 0x56, 0x74, 0x53, 0x68, 0x66, 0x58, 0x6d, 0x6f, 0x6e, 0x54, 0x4b, 0x55, +0x76, 0x50, 0x2b, 0x4f, 0x65, 0x32, 0x66, 0x2b, 0x35, 0x41, 0x4d, 0x69, 0x47, 0x54, 0x76, 0x5a, +0x76, 0x37, 0x4a, 0x4a, 0x6f, 0x5a, 0x5a, 0x45, 0x79, 0x78, 0x4e, 0x70, 0x56, 0x57, 0x43, 0x75, +0x49, 0x65, 0x73, 0x46, 0x6f, 0x51, 0x61, 0x36, 0x79, 0x43, 0x32, 0x73, 0x6a, 0x37, 0x4a, 0x49, +0x59, 0x45, 0x30, 0x58, 0x59, 0x4b, 0x49, 0x4b, 0x57, 0x46, 0x67, 0x70, 0x79, 0x79, 0x32, 0x4a, +0x58, 0x72, 0x4d, 0x54, 0x50, 0x48, 0x45, 0x75, 0x37, 0x4a, 0x46, 0x70, 0x72, 0x70, 0x4a, 0x56, +0x49, 0x4c, 0x5a, 0x48, 0x47, 0x58, 0x59, 0x55, 0x57, 0x43, 0x43, 0x4f, 0x51, 0x57, 0x74, 0x4a, +0x61, 0x30, 0x77, 0x6f, 0x43, 0x73, 0x6c, 0x6e, 0x58, 0x68, 0x54, 0x56, 0x72, 0x31, 0x36, 0x4b, +0x6b, 0x52, 0x43, 0x57, 0x54, 0x4a, 0x41, 0x51, 0x32, 0x46, 0x6c, 0x67, 0x52, 0x59, 0x2b, 0x4d, +0x59, 0x45, 0x38, 0x64, 0x73, 0x4c, 0x4c, 0x63, 0x73, 0x62, 0x4f, 0x34, 0x6b, 0x6c, 0x68, 0x48, +0x4e, 0x56, 0x53, 0x30, 0x67, 0x59, 0x46, 0x74, 0x67, 0x47, 0x4a, 0x61, 0x37, 0x56, 0x71, 0x77, +0x6b, 0x30, 0x68, 0x70, 0x72, 0x4e, 0x4e, 0x64, 0x2b, 0x54, 0x7a, 0x4a, 0x76, 0x6b, 0x61, 0x61, +0x6c, 0x56, 0x6d, 0x4b, 0x30, 0x5a, 0x4d, 0x63, 0x78, 0x6b, 0x68, 0x30, 0x4f, 0x6c, 0x5a, 0x77, +0x38, 0x56, 0x5a, 0x43, 0x50, 0x6e, 0x46, 0x43, 0x35, 0x72, 0x72, 0x55, 0x56, 0x41, 0x54, 0x7a, +0x61, 0x2f, 0x54, 0x79, 0x35, 0x44, 0x2f, 0x4c, 0x38, 0x31, 0x39, 0x71, 0x31, 0x30, 0x4e, 0x57, +0x46, 0x46, 0x5a, 0x49, 0x54, 0x2f, 0x2f, 0x6b, 0x70, 0x73, 0x51, 0x6e, 0x35, 0x72, 0x2f, 0x67, +0x56, 0x70, 0x6f, 0x77, 0x36, 0x68, 0x45, 0x34, 0x4e, 0x67, 0x36, 0x76, 0x4b, 0x47, 0x46, 0x78, +0x56, 0x52, 0x6b, 0x34, 0x5a, 0x56, 0x6e, 0x56, 0x46, 0x6c, 0x49, 0x55, 0x42, 0x6b, 0x45, 0x39, +0x48, 0x51, 0x4b, 0x33, 0x35, 0x6b, 0x6f, 0x7a, 0x52, 0x50, 0x4e, 0x7a, 0x57, 0x79, 0x37, 0x63, +0x72, 0x51, 0x37, 0x62, 0x70, 0x69, 0x66, 0x68, 0x4a, 0x57, 0x77, 0x39, 0x4b, 0x43, 0x45, 0x36, +0x73, 0x44, 0x42, 0x44, 0x72, 0x44, 0x62, 0x65, 0x75, 0x36, 0x2b, 0x51, 0x48, 0x31, 0x53, 0x46, +0x4b, 0x43, 0x48, 0x4c, 0x4e, 0x4c, 0x55, 0x36, 0x4a, 0x43, 0x55, 0x4d, 0x33, 0x66, 0x6d, 0x76, +0x58, 0x4f, 0x63, 0x4c, 0x56, 0x42, 0x6b, 0x79, 0x42, 0x30, 0x56, 0x4f, 0x69, 0x54, 0x51, 0x53, +0x42, 0x6c, 0x45, 0x35, 0x41, 0x4e, 0x6a, 0x63, 0x58, 0x6a, 0x58, 0x38, 0x66, 0x35, 0x72, 0x63, +0x57, 0x6c, 0x69, 0x31, 0x31, 0x35, 0x5a, 0x4b, 0x7a, 0x69, 0x50, 0x47, 0x74, 0x74, 0x51, 0x52, +0x42, 0x67, 0x45, 0x70, 0x55, 0x4f, 0x32, 0x73, 0x78, 0x71, 0x31, 0x59, 0x35, 0x41, 0x65, 0x53, +0x46, 0x69, 0x7a, 0x55, 0x78, 0x51, 0x57, 0x73, 0x6e, 0x32, 0x66, 0x4d, 0x58, 0x6f, 0x33, 0x37, +0x62, 0x6a, 0x48, 0x34, 0x37, 0x42, 0x33, 0x35, 0x65, 0x6b, 0x4a, 0x4b, 0x77, 0x70, 0x51, 0x57, +0x4e, 0x57, 0x37, 0x79, 0x6b, 0x67, 0x59, 0x33, 0x53, 0x65, 0x67, 0x4c, 0x32, 0x41, 0x74, 0x49, +0x34, 0x59, 0x6c, 0x62, 0x47, 0x6e, 0x39, 0x61, 0x69, 0x54, 0x65, 0x46, 0x7a, 0x59, 0x33, 0x6b, +0x41, 0x77, 0x70, 0x44, 0x4e, 0x4f, 0x74, 0x6b, 0x7a, 0x64, 0x36, 0x35, 0x31, 0x69, 0x35, 0x77, +0x45, 0x49, 0x53, 0x33, 0x49, 0x6d, 0x42, 0x31, 0x35, 0x6a, 0x54, 0x33, 0x44, 0x74, 0x32, 0x68, +0x67, 0x44, 0x62, 0x6e, 0x42, 0x54, 0x56, 0x54, 0x74, 0x76, 0x52, 0x76, 0x78, 0x69, 0x45, 0x59, +0x2b, 0x6d, 0x76, 0x4d, 0x4f, 0x38, 0x66, 0x73, 0x66, 0x38, 0x63, 0x39, 0x35, 0x38, 0x77, 0x65, +0x6b, 0x50, 0x79, 0x74, 0x6c, 0x65, 0x6b, 0x31, 0x50, 0x49, 0x62, 0x46, 0x53, 0x4f, 0x4c, 0x71, +0x53, 0x6b, 0x71, 0x43, 0x31, 0x46, 0x51, 0x50, 0x38, 0x39, 0x4b, 0x55, 0x66, 0x6f, 0x66, 0x61, +0x66, 0x52, 0x6e, 0x62, 0x39, 0x57, 0x73, 0x6f, 0x37, 0x4f, 0x7a, 0x46, 0x78, 0x54, 0x46, 0x6c, +0x4e, 0x4e, 0x56, 0x30, 0x6d, 0x59, 0x4a, 0x75, 0x38, 0x34, 0x50, 0x6d, 0x4b, 0x76, 0x57, 0x6c, +0x58, 0x41, 0x53, 0x49, 0x53, 0x50, 0x50, 0x54, 0x6e, 0x4f, 0x52, 0x77, 0x38, 0x61, 0x51, 0x7a, +0x54, 0x66, 0x2f, 0x73, 0x57, 0x6f, 0x31, 0x73, 0x48, 0x41, 0x59, 0x71, 0x36, 0x69, 0x68, 0x79, +0x48, 0x76, 0x66, 0x6b, 0x6b, 0x63, 0x76, 0x56, 0x71, 0x44, 0x76, 0x76, 0x44, 0x4c, 0x37, 0x6a, +0x6e, 0x32, 0x4d, 0x75, 0x51, 0x55, 0x6a, 0x6f, 0x42, 0x5a, 0x67, 0x31, 0x4b, 0x65, 0x77, 0x62, +0x57, 0x46, 0x71, 0x6b, 0x4e, 0x30, 0x68, 0x69, 0x55, 0x4e, 0x67, 0x79, 0x72, 0x4b, 0x58, 0x64, +0x43, 0x74, 0x71, 0x6f, 0x4b, 0x4d, 0x6c, 0x6c, 0x57, 0x39, 0x45, 0x69, 0x30, 0x58, 0x31, 0x79, +0x6b, 0x4d, 0x57, 0x68, 0x74, 0x6b, 0x56, 0x6f, 0x6a, 0x4c, 0x59, 0x37, 0x68, 0x6a, 0x55, 0x56, +0x6f, 0x70, 0x30, 0x46, 0x4a, 0x62, 0x57, 0x69, 0x74, 0x7a, 0x6b, 0x47, 0x75, 0x35, 0x6a, 0x38, +0x58, 0x41, 0x4d, 0x59, 0x59, 0x74, 0x4c, 0x46, 0x6f, 0x5a, 0x58, 0x30, 0x6a, 0x4e, 0x64, 0x59, +0x4b, 0x35, 0x72, 0x77, 0x79, 0x6b, 0x76, 0x4a, 0x59, 0x6f, 0x48, 0x56, 0x45, 0x70, 0x32, 0x31, +0x6b, 0x70, 0x30, 0x4d, 0x2b, 0x78, 0x4d, 0x51, 0x78, 0x4a, 0x68, 0x39, 0x68, 0x52, 0x55, 0x77, +0x67, 0x34, 0x6c, 0x54, 0x64, 0x73, 0x73, 0x61, 0x57, 0x44, 0x50, 0x35, 0x6a, 0x42, 0x7a, 0x37, +0x57, 0x6a, 0x2b, 0x41, 0x47, 0x49, 0x73, 0x42, 0x6c, 0x45, 0x35, 0x5a, 0x78, 0x77, 0x41, 0x45, +0x48, 0x6f, 0x4c, 0x56, 0x4f, 0x56, 0x32, 0x62, 0x70, 0x4a, 0x38, 0x67, 0x43, 0x35, 0x6f, 0x7a, +0x54, 0x73, 0x56, 0x70, 0x68, 0x58, 0x33, 0x34, 0x4e, 0x2b, 0x38, 0x35, 0x73, 0x70, 0x4c, 0x54, +0x6b, 0x5a, 0x52, 0x34, 0x68, 0x59, 0x34, 0x53, 0x4b, 0x49, 0x58, 0x4b, 0x71, 0x39, 0x55, 0x68, +0x6a, 0x32, 0x56, 0x64, 0x72, 0x6e, 0x74, 0x4f, 0x47, 0x30, 0x45, 0x72, 0x2b, 0x38, 0x6f, 0x72, +0x6d, 0x31, 0x43, 0x4d, 0x45, 0x67, 0x35, 0x6f, 0x55, 0x31, 0x6b, 0x72, 0x32, 0x79, 0x67, 0x6a, +0x75, 0x66, 0x46, 0x52, 0x67, 0x6a, 0x55, 0x52, 0x49, 0x78, 0x64, 0x46, 0x43, 0x4d, 0x46, 0x46, +0x4b, 0x6c, 0x67, 0x4b, 0x33, 0x35, 0x76, 0x62, 0x67, 0x69, 0x74, 0x48, 0x62, 0x38, 0x6f, 0x30, +0x68, 0x58, 0x36, 0x41, 0x2f, 0x6e, 0x6f, 0x65, 0x74, 0x67, 0x75, 0x7a, 0x49, 0x45, 0x58, 0x52, +0x32, 0x43, 0x57, 0x61, 0x33, 0x51, 0x36, 0x2b, 0x32, 0x43, 0x41, 0x6e, 0x54, 0x6a, 0x74, 0x71, +0x63, 0x79, 0x72, 0x67, 0x4c, 0x67, 0x70, 0x44, 0x75, 0x62, 0x43, 0x58, 0x66, 0x66, 0x33, 0x77, +0x65, 0x45, 0x47, 0x45, 0x4d, 0x36, 0x65, 0x70, 0x73, 0x6c, 0x57, 0x4b, 0x6e, 0x6a, 0x4f, 0x57, +0x71, 0x31, 0x5a, 0x31, 0x45, 0x63, 0x59, 0x79, 0x56, 0x67, 0x69, 0x71, 0x6c, 0x75, 0x4c, 0x30, +0x72, 0x52, 0x6f, 0x71, 0x59, 0x43, 0x79, 0x6f, 0x7a, 0x47, 0x43, 0x47, 0x39, 0x69, 0x69, 0x38, +0x64, 0x41, 0x37, 0x65, 0x33, 0x70, 0x2b, 0x4e, 0x6e, 0x2f, 0x52, 0x69, 0x53, 0x4d, 0x48, 0x76, +0x78, 0x69, 0x71, 0x57, 0x53, 0x6c, 0x63, 0x74, 0x78, 0x69, 0x5a, 0x57, 0x79, 0x4d, 0x50, 0x35, +0x39, 0x6d, 0x52, 0x38, 0x63, 0x6f, 0x53, 0x74, 0x56, 0x49, 0x50, 0x77, 0x2b, 0x34, 0x35, 0x2f, +0x4d, 0x76, 0x62, 0x38, 0x70, 0x5a, 0x58, 0x34, 0x70, 0x6f, 0x46, 0x78, 0x51, 0x39, 0x6f, 0x50, +0x50, 0x4d, 0x50, 0x4f, 0x72, 0x4b, 0x50, 0x76, 0x2b, 0x53, 0x76, 0x54, 0x72, 0x49, 0x35, 0x33, +0x67, 0x4c, 0x78, 0x49, 0x43, 0x47, 0x72, 0x69, 0x6d, 0x64, 0x54, 0x31, 0x62, 0x44, 0x57, 0x31, +0x45, 0x47, 0x6d, 0x38, 0x79, 0x57, 0x43, 0x63, 0x49, 0x4c, 0x47, 0x36, 0x31, 0x74, 0x39, 0x5a, +0x69, 0x73, 0x56, 0x68, 0x6a, 0x4d, 0x62, 0x35, 0x75, 0x59, 0x79, 0x31, 0x6c, 0x41, 0x54, 0x52, +0x39, 0x59, 0x7a, 0x32, 0x58, 0x4d, 0x68, 0x52, 0x72, 0x48, 0x50, 0x4e, 0x4c, 0x43, 0x57, 0x50, +0x4d, 0x48, 0x48, 0x62, 0x50, 0x76, 0x55, 0x35, 0x4c, 0x78, 0x52, 0x49, 0x79, 0x46, 0x5a, 0x56, +0x55, 0x62, 0x62, 0x38, 0x74, 0x5a, 0x51, 0x64, 0x63, 0x43, 0x4f, 0x58, 0x31, 0x7a, 0x50, 0x76, +0x72, 0x2f, 0x58, 0x7a, 0x78, 0x68, 0x39, 0x2b, 0x79, 0x2b, 0x4f, 0x50, 0x6c, 0x62, 0x48, 0x66, +0x63, 0x38, 0x59, 0x7a, 0x62, 0x2f, 0x54, 0x44, 0x34, 0x5a, 0x42, 0x56, 0x32, 0x71, 0x34, 0x6e, +0x51, 0x4e, 0x41, 0x79, 0x73, 0x53, 0x62, 0x55, 0x6a, 0x57, 0x7a, 0x79, 0x47, 0x78, 0x66, 0x64, +0x4b, 0x49, 0x59, 0x51, 0x67, 0x4e, 0x32, 0x77, 0x59, 0x5a, 0x75, 0x5a, 0x4d, 0x2f, 0x72, 0x37, +0x31, 0x74, 0x2f, 0x6a, 0x76, 0x62, 0x32, 0x78, 0x48, 0x78, 0x62, 0x6f, 0x56, 0x52, 0x41, 0x75, +0x58, 0x45, 0x47, 0x53, 0x79, 0x56, 0x45, 0x30, 0x59, 0x51, 0x2f, 0x66, 0x4b, 0x39, 0x53, 0x7a, +0x75, 0x4c, 0x53, 0x64, 0x61, 0x62, 0x54, 0x6c, 0x71, 0x2f, 0x77, 0x6e, 0x38, 0x61, 0x65, 0x59, +0x38, 0x46, 0x6e, 0x79, 0x2b, 0x6a, 0x67, 0x2f, 0x6e, 0x72, 0x65, 0x4b, 0x71, 0x37, 0x2b, 0x33, +0x46, 0x71, 0x2b, 0x38, 0x73, 0x42, 0x58, 0x72, 0x70, 0x46, 0x49, 0x72, 0x6e, 0x4a, 0x68, 0x33, +0x50, 0x51, 0x59, 0x2f, 0x64, 0x78, 0x6e, 0x31, 0x48, 0x58, 0x59, 0x53, 0x55, 0x79, 0x6a, 0x47, +0x39, 0x5a, 0x33, 0x35, 0x64, 0x78, 0x50, 0x54, 0x53, 0x43, 0x77, 0x48, 0x6c, 0x54, 0x34, 0x54, +0x69, 0x39, 0x55, 0x74, 0x33, 0x5a, 0x75, 0x7a, 0x74, 0x74, 0x79, 0x4e, 0x57, 0x72, 0x38, 0x45, +0x61, 0x4e, 0x2f, 0x66, 0x47, 0x74, 0x39, 0x50, 0x34, 0x30, 0x30, 0x72, 0x70, 0x37, 0x72, 0x33, +0x6d, 0x61, 0x4a, 0x55, 0x69, 0x31, 0x39, 0x7a, 0x4d, 0x55, 0x55, 0x2f, 0x65, 0x38, 0x35, 0x38, +0x4c, 0x41, 0x4b, 0x57, 0x63, 0x32, 0x71, 0x79, 0x30, 0x51, 0x61, 0x6c, 0x6b, 0x30, 0x6d, 0x4b, +0x47, 0x74, 0x47, 0x2b, 0x6b, 0x38, 0x64, 0x4d, 0x75, 0x65, 0x6b, 0x2f, 0x6f, 0x4a, 0x70, 0x68, +0x54, 0x69, 0x54, 0x45, 0x78, 0x52, 0x6b, 0x54, 0x59, 0x76, 0x4c, 0x73, 0x47, 0x73, 0x55, 0x44, +0x67, 0x56, 0x4c, 0x32, 0x67, 0x57, 0x44, 0x57, 0x56, 0x36, 0x6d, 0x75, 0x5a, 0x76, 0x35, 0x67, +0x41, 0x68, 0x52, 0x41, 0x6f, 0x70, 0x52, 0x42, 0x53, 0x49, 0x6f, 0x56, 0x41, 0x4a, 0x71, 0x76, +0x2f, 0x6d, 0x57, 0x63, 0x69, 0x58, 0x76, 0x34, 0x62, 0x74, 0x72, 0x32, 0x44, 0x7a, 0x4f, 0x46, +0x48, 0x59, 0x6d, 0x65, 0x39, 0x69, 0x6f, 0x77, 0x74, 0x73, 0x59, 0x79, 0x4a, 0x56, 0x45, 0x53, +0x73, 0x42, 0x66, 0x52, 0x36, 0x4f, 0x37, 0x69, 0x68, 0x6d, 0x69, 0x50, 0x79, 0x64, 0x53, 0x7a, +0x64, 0x39, 0x7a, 0x4a, 0x69, 0x6d, 0x32, 0x47, 0x58, 0x51, 0x62, 0x39, 0x6a, 0x2b, 0x76, 0x4b, +0x54, 0x55, 0x4a, 0x38, 0x6e, 0x67, 0x32, 0x30, 0x35, 0x39, 0x4a, 0x74, 0x33, 0x73, 0x57, 0x53, +0x72, 0x37, 0x78, 0x48, 0x45, 0x4d, 0x57, 0x63, 0x39, 0x65, 0x53, 0x48, 0x5a, 0x70, 0x67, 0x59, +0x4d, 0x38, 0x47, 0x42, 0x48, 0x48, 0x62, 0x38, 0x62, 0x30, 0x63, 0x67, 0x44, 0x37, 0x2f, 0x65, +0x79, 0x66, 0x37, 0x61, 0x47, 0x6e, 0x46, 0x58, 0x4d, 0x47, 0x4c, 0x30, 0x76, 0x70, 0x33, 0x7a, +0x35, 0x41, 0x59, 0x2b, 0x76, 0x6b, 0x6f, 0x68, 0x4b, 0x45, 0x4d, 0x61, 0x51, 0x36, 0x33, 0x67, +0x53, 0x34, 0x76, 0x6d, 0x55, 0x6a, 0x62, 0x69, 0x61, 0x71, 0x74, 0x58, 0x33, 0x6f, 0x38, 0x7a, +0x75, 0x67, 0x43, 0x51, 0x55, 0x58, 0x67, 0x42, 0x49, 0x69, 0x64, 0x57, 0x4b, 0x39, 0x37, 0x76, +0x7a, 0x6a, 0x44, 0x43, 0x4b, 0x2b, 0x56, 0x49, 0x69, 0x59, 0x73, 0x46, 0x47, 0x49, 0x52, 0x43, +0x78, 0x59, 0x4b, 0x68, 0x56, 0x76, 0x4e, 0x34, 0x5a, 0x73, 0x55, 0x4e, 0x31, 0x36, 0x4d, 0x30, +0x6f, 0x53, 0x51, 0x67, 0x4d, 0x71, 0x66, 0x6f, 0x4e, 0x50, 0x31, 0x55, 0x37, 0x73, 0x31, 0x72, +0x31, 0x59, 0x76, 0x77, 0x63, 0x4b, 0x47, 0x56, 0x51, 0x53, 0x69, 0x4f, 0x6c, 0x36, 0x58, 0x63, +0x76, 0x70, 0x55, 0x46, 0x4b, 0x7a, 0x58, 0x42, 0x5a, 0x7a, 0x62, 0x33, 0x45, 0x55, 0x48, 0x38, +0x54, 0x56, 0x31, 0x35, 0x35, 0x46, 0x4d, 0x75, 0x58, 0x64, 0x37, 0x6e, 0x66, 0x53, 0x67, 0x4e, +0x42, 0x51, 0x4b, 0x38, 0x2b, 0x6a, 0x79, 0x75, 0x75, 0x32, 0x42, 0x5a, 0x6a, 0x4c, 0x44, 0x2f, +0x2b, 0x38, 0x58, 0x73, 0x45, 0x2b, 0x7a, 0x35, 0x44, 0x64, 0x33, 0x65, 0x4d, 0x45, 0x41, 0x6f, +0x70, 0x44, 0x61, 0x4e, 0x47, 0x31, 0x54, 0x4a, 0x72, 0x31, 0x6a, 0x54, 0x65, 0x32, 0x74, 0x4b, +0x36, 0x65, 0x59, 0x76, 0x6a, 0x31, 0x46, 0x78, 0x41, 0x53, 0x73, 0x71, 0x6d, 0x4c, 0x43, 0x41, +0x2b, 0x62, 0x51, 0x4c, 0x57, 0x35, 0x73, 0x6c, 0x64, 0x71, 0x72, 0x41, 0x39, 0x50, 0x57, 0x36, +0x4f, 0x34, 0x39, 0x6a, 0x4e, 0x54, 0x78, 0x52, 0x68, 0x67, 0x43, 0x31, 0x71, 0x44, 0x59, 0x32, +0x35, 0x49, 0x75, 0x48, 0x6a, 0x6d, 0x64, 0x2f, 0x6d, 0x58, 0x30, 0x5a, 0x33, 0x50, 0x34, 0x4f, +0x78, 0x69, 0x72, 0x44, 0x36, 0x4d, 0x47, 0x7a, 0x46, 0x77, 0x58, 0x30, 0x57, 0x41, 0x4e, 0x69, +0x31, 0x45, 0x5a, 0x51, 0x77, 0x56, 0x4a, 0x6b, 0x75, 0x6a, 0x73, 0x69, 0x2b, 0x79, 0x4a, 0x6a, +0x79, 0x65, 0x5a, 0x51, 0x46, 0x6b, 0x6f, 0x72, 0x52, 0x6f, 0x79, 0x67, 0x2f, 0x38, 0x45, 0x4b, +0x43, 0x6f, 0x5a, 0x75, 0x6c, 0x76, 0x2f, 0x2f, 0x73, 0x35, 0x55, 0x66, 0x34, 0x38, 0x70, 0x4d, +0x33, 0x79, 0x51, 0x34, 0x65, 0x52, 0x56, 0x58, 0x6d, 0x4d, 0x38, 0x72, 0x70, 0x59, 0x6d, 0x31, +0x37, 0x6a, 0x72, 0x58, 0x50, 0x50, 0x6b, 0x74, 0x54, 0x55, 0x31, 0x50, 0x2f, 0x2b, 0x67, 0x65, +0x67, 0x4f, 0x53, 0x46, 0x45, 0x65, 0x69, 0x32, 0x72, 0x72, 0x6b, 0x5a, 0x2b, 0x39, 0x37, 0x75, +0x30, 0x50, 0x7a, 0x6f, 0x58, 0x47, 0x68, 0x74, 0x35, 0x65, 0x6b, 0x32, 0x57, 0x4c, 0x57, 0x70, +0x36, 0x43, 0x4a, 0x58, 0x6d, 0x35, 0x63, 0x47, 0x37, 0x73, 0x75, 0x2b, 0x67, 0x4c, 0x2b, 0x68, +0x59, 0x30, 0x4d, 0x61, 0x42, 0x6d, 0x34, 0x2b, 0x69, 0x64, 0x56, 0x67, 0x74, 0x6c, 0x35, 0x79, +0x35, 0x4f, 0x31, 0x66, 0x2f, 0x38, 0x6d, 0x56, 0x4f, 0x50, 0x48, 0x77, 0x69, 0x5a, 0x64, 0x6d, +0x41, 0x67, 0x2f, 0x59, 0x63, 0x77, 0x78, 0x31, 0x45, 0x47, 0x4b, 0x58, 0x6f, 0x7a, 0x75, 0x61, +0x34, 0x39, 0x39, 0x68, 0x4c, 0x69, 0x61, 0x52, 0x47, 0x65, 0x7a, 0x56, 0x64, 0x47, 0x65, 0x74, +0x6f, 0x7a, 0x2f, 0x4f, 0x57, 0x30, 0x41, 0x55, 0x74, 0x77, 0x44, 0x32, 0x33, 0x7a, 0x6f, 0x34, +0x50, 0x51, 0x79, 0x39, 0x34, 0x6e, 0x5a, 0x61, 0x48, 0x56, 0x4f, 0x67, 0x6f, 0x7a, 0x39, 0x43, +0x54, 0x54, 0x71, 0x4a, 0x73, 0x2b, 0x41, 0x67, 0x36, 0x58, 0x6e, 0x32, 0x4e, 0x73, 0x6c, 0x47, +0x74, 0x64, 0x4c, 0x7a, 0x2b, 0x4f, 0x72, 0x31, 0x7a, 0x35, 0x32, 0x4b, 0x6c, 0x77, 0x69, 0x67, +0x6e, 0x31, 0x45, 0x50, 0x34, 0x7a, 0x77, 0x56, 0x41, 0x4a, 0x4c, 0x79, 0x61, 0x6f, 0x67, 0x78, +0x53, 0x57, 0x61, 0x53, 0x79, 0x57, 0x42, 0x73, 0x52, 0x6c, 0x51, 0x6c, 0x36, 0x54, 0x2b, 0x69, +0x6d, 0x2b, 0x75, 0x61, 0x31, 0x78, 0x41, 0x63, 0x50, 0x77, 0x35, 0x67, 0x49, 0x6b, 0x38, 0x38, +0x37, 0x64, 0x54, 0x79, 0x4b, 0x43, 0x65, 0x4b, 0x43, 0x42, 0x6f, 0x44, 0x53, 0x36, 0x55, 0x72, +0x31, 0x4c, 0x77, 0x73, 0x41, 0x72, 0x34, 0x4a, 0x47, 0x76, 0x62, 0x30, 0x6f, 0x76, 0x2f, 0x49, +0x4c, 0x49, 0x59, 0x6e, 0x6a, 0x43, 0x43, 0x73, 0x45, 0x70, 0x72, 0x49, 0x43, 0x74, 0x65, 0x75, +0x75, 0x6b, 0x49, 0x38, 0x49, 0x4b, 0x6e, 0x4c, 0x59, 0x4b, 0x45, 0x4a, 0x46, 0x68, 0x72, 0x7a, +0x4b, 0x45, 0x38, 0x6d, 0x59, 0x32, 0x47, 0x73, 0x41, 0x42, 0x6a, 0x44, 0x4b, 0x53, 0x66, 0x37, +0x44, 0x48, 0x37, 0x2b, 0x52, 0x65, 0x77, 0x2b, 0x38, 0x6a, 0x4e, 0x2b, 0x73, 0x50, 0x77, 0x4d, +0x5a, 0x4b, 0x61, 0x51, 0x4f, 0x33, 0x65, 0x41, 0x72, 0x79, 0x39, 0x77, 0x76, 0x76, 0x30, 0x39, +0x57, 0x64, 0x48, 0x48, 0x4a, 0x59, 0x7a, 0x38, 0x67, 0x71, 0x48, 0x45, 0x53, 0x56, 0x51, 0x46, +0x48, 0x74, 0x63, 0x44, 0x4e, 0x72, 0x33, 0x2f, 0x4f, 0x6a, 0x45, 0x58, 0x64, 0x31, 0x46, 0x74, +0x4e, 0x52, 0x6d, 0x76, 0x75, 0x66, 0x4f, 0x78, 0x74, 0x58, 0x68, 0x33, 0x56, 0x77, 0x4b, 0x53, +0x6d, 0x58, 0x6d, 0x59, 0x4a, 0x6a, 0x64, 0x42, 0x4f, 0x59, 0x47, 0x57, 0x48, 0x54, 0x55, 0x45, +0x73, 0x75, 0x52, 0x52, 0x54, 0x75, 0x78, 0x66, 0x61, 0x47, 0x69, 0x44, 0x76, 0x43, 0x45, 0x36, +0x37, 0x53, 0x51, 0x6d, 0x56, 0x5a, 0x6a, 0x79, 0x61, 0x74, 0x56, 0x4a, 0x79, 0x65, 0x58, 0x58, +0x41, 0x4e, 0x5a, 0x30, 0x78, 0x51, 0x67, 0x69, 0x6d, 0x31, 0x6d, 0x5a, 0x34, 0x73, 0x6c, 0x32, +0x77, 0x68, 0x64, 0x55, 0x59, 0x41, 0x56, 0x6f, 0x49, 0x73, 0x74, 0x37, 0x42, 0x4b, 0x59, 0x52, +0x7a, 0x48, 0x47, 0x6e, 0x6c, 0x47, 0x46, 0x77, 0x72, 0x67, 0x2b, 0x7a, 0x48, 0x39, 0x4e, 0x6f, +0x52, 0x6a, 0x57, 0x66, 0x2b, 0x35, 0x46, 0x6e, 0x69, 0x5a, 0x6c, 0x54, 0x4b, 0x49, 0x71, 0x56, +0x4e, 0x42, 0x63, 0x41, 0x76, 0x62, 0x74, 0x32, 0x44, 0x43, 0x79, 0x39, 0x36, 0x6b, 0x32, 0x75, +0x76, 0x65, 0x63, 0x38, 0x4a, 0x44, 0x41, 0x30, 0x2f, 0x75, 0x33, 0x35, 0x48, 0x4c, 0x72, 0x37, +0x34, 0x44, 0x59, 0x51, 0x77, 0x36, 0x58, 0x74, 0x42, 0x4f, 0x53, 0x4d, 0x6d, 0x73, 0x66, 0x6d, +0x54, 0x31, 0x56, 0x4d, 0x49, 0x7a, 0x49, 0x49, 0x4b, 0x63, 0x6a, 0x63, 0x75, 0x52, 0x56, 0x7a, +0x66, 0x41, 0x50, 0x55, 0x46, 0x48, 0x34, 0x41, 0x56, 0x49, 0x76, 0x33, 0x64, 0x79, 0x6a, 0x36, +0x61, 0x52, 0x36, 0x70, 0x39, 0x57, 0x49, 0x75, 0x4e, 0x58, 0x73, 0x4b, 0x59, 0x7a, 0x37, 0x46, +0x47, 0x59, 0x6e, 0x74, 0x6e, 0x59, 0x6e, 0x4d, 0x48, 0x39, 0x5a, 0x74, 0x2f, 0x59, 0x77, 0x77, +0x6e, 0x39, 0x72, 0x7a, 0x41, 0x33, 0x70, 0x31, 0x4c, 0x4d, 0x4f, 0x57, 0x72, 0x4b, 0x4e, 0x74, +0x69, 0x41, 0x70, 0x55, 0x48, 0x2f, 0x78, 0x64, 0x42, 0x56, 0x58, 0x58, 0x4a, 0x62, 0x33, 0x74, +0x57, 0x33, 0x4d, 0x6a, 0x59, 0x66, 0x53, 0x39, 0x68, 0x36, 0x4d, 0x34, 0x37, 0x6f, 0x50, 0x4b, +0x4e, 0x72, 0x4a, 0x73, 0x2f, 0x68, 0x79, 0x41, 0x73, 0x6f, 0x36, 0x6c, 0x78, 0x30, 0x4b, 0x62, +0x72, 0x2f, 0x37, 0x72, 0x54, 0x2f, 0x32, 0x37, 0x39, 0x53, 0x36, 0x2f, 0x77, 0x70, 0x35, 0x71, +0x44, 0x6d, 0x62, 0x31, 0x53, 0x73, 0x73, 0x36, 0x55, 0x59, 0x35, 0x54, 0x6d, 0x37, 0x38, 0x2f, +0x4d, 0x59, 0x63, 0x37, 0x77, 0x47, 0x69, 0x5a, 0x6d, 0x4e, 0x45, 0x38, 0x2b, 0x2f, 0x77, 0x6d, +0x6e, 0x48, 0x72, 0x38, 0x44, 0x7a, 0x37, 0x33, 0x32, 0x47, 0x56, 0x4a, 0x71, 0x58, 0x6e, 0x35, +0x37, 0x4b, 0x57, 0x45, 0x6d, 0x34, 0x49, 0x58, 0x58, 0x46, 0x2f, 0x76, 0x35, 0x41, 0x32, 0x30, +0x73, 0x65, 0x61, 0x47, 0x64, 0x32, 0x75, 0x39, 0x4e, 0x48, 0x4b, 0x6d, 0x64, 0x79, 0x65, 0x4e, +0x57, 0x66, 0x56, 0x73, 0x77, 0x41, 0x5a, 0x4a, 0x37, 0x37, 0x39, 0x41, 0x7a, 0x57, 0x6a, 0x76, +0x54, 0x53, 0x52, 0x75, 0x73, 0x63, 0x71, 0x74, 0x2f, 0x2b, 0x5a, 0x68, 0x78, 0x6c, 0x49, 0x30, +0x65, 0x77, 0x78, 0x66, 0x54, 0x70, 0x74, 0x46, 0x38, 0x39, 0x74, 0x6d, 0x45, 0x31, 0x54, 0x56, +0x55, 0x62, 0x74, 0x4e, 0x42, 0x31, 0x35, 0x79, 0x50, 0x76, 0x56, 0x61, 0x67, 0x4d, 0x63, 0x59, +0x35, 0x5a, 0x66, 0x38, 0x66, 0x42, 0x49, 0x42, 0x79, 0x39, 0x6f, 0x59, 0x79, 0x53, 0x4f, 0x6b, +0x45, 0x77, 0x4c, 0x4a, 0x35, 0x39, 0x61, 0x79, 0x49, 0x4b, 0x32, 0x6d, 0x5a, 0x76, 0x6f, 0x36, +0x4f, 0x79, 0x38, 0x76, 0x35, 0x38, 0x70, 0x31, 0x4b, 0x77, 0x67, 0x38, 0x48, 0x4d, 0x54, 0x62, +0x65, 0x69, 0x49, 0x37, 0x63, 0x43, 0x68, 0x44, 0x47, 0x63, 0x65, 0x4b, 0x49, 0x64, 0x32, 0x71, +0x36, 0x55, 0x6b, 0x35, 0x31, 0x2f, 0x42, 0x63, 0x46, 0x51, 0x4f, 0x41, 0x6e, 0x71, 0x79, 0x65, +0x4b, 0x6b, 0x46, 0x49, 0x69, 0x68, 0x43, 0x43, 0x4f, 0x59, 0x2b, 0x49, 0x34, 0x78, 0x67, 0x69, +0x42, 0x2f, 0x6e, 0x77, 0x78, 0x34, 0x62, 0x41, 0x57, 0x54, 0x48, 0x55, 0x4e, 0x61, 0x76, 0x34, +0x43, 0x67, 0x74, 0x35, 0x65, 0x70, 0x49, 0x52, 0x49, 0x52, 0x51, 0x67, 0x6c, 0x6e, 0x41, 0x44, +0x77, 0x44, 0x62, 0x44, 0x47, 0x4f, 0x66, 0x64, 0x47, 0x56, 0x57, 0x6b, 0x4f, 0x6d, 0x6e, 0x55, +0x76, 0x62, 0x78, 0x31, 0x35, 0x4d, 0x63, 0x6f, 0x45, 0x53, 0x47, 0x56, 0x52, 0x47, 0x70, 0x51, +0x47, 0x61, 0x54, 0x50, 0x73, 0x2b, 0x74, 0x41, 0x76, 0x32, 0x61, 0x71, 0x6d, 0x46, 0x79, 0x45, +0x31, 0x57, 0x61, 0x39, 0x43, 0x7a, 0x33, 0x69, 0x33, 0x6a, 0x5a, 0x32, 0x4f, 0x33, 0x6f, 0x49, +0x74, 0x52, 0x35, 0x58, 0x78, 0x74, 0x4e, 0x34, 0x4a, 0x5a, 0x51, 0x78, 0x62, 0x47, 0x54, 0x64, +0x5a, 0x66, 0x78, 0x4e, 0x31, 0x62, 0x72, 0x4c, 0x79, 0x6d, 0x67, 0x76, 0x6d, 0x37, 0x6b, 0x74, +0x35, 0x74, 0x68, 0x4e, 0x6c, 0x72, 0x71, 0x59, 0x6a, 0x30, 0x69, 0x69, 0x31, 0x47, 0x6e, 0x44, +0x76, 0x53, 0x41, 0x53, 0x66, 0x31, 0x70, 0x4b, 0x4a, 0x67, 0x57, 0x5a, 0x30, 0x75, 0x65, 0x58, +0x4a, 0x74, 0x6c, 0x36, 0x79, 0x55, 0x71, 0x42, 0x45, 0x7a, 0x49, 0x76, 0x74, 0x68, 0x72, 0x50, +0x4b, 0x41, 0x38, 0x71, 0x56, 0x78, 0x58, 0x69, 0x56, 0x48, 0x43, 0x6c, 0x64, 0x49, 0x45, 0x51, +0x6b, 0x44, 0x71, 0x2f, 0x53, 0x55, 0x38, 0x6f, 0x43, 0x55, 0x30, 0x76, 0x70, 0x56, 0x55, 0x6c, +0x70, 0x2f, 0x44, 0x50, 0x72, 0x76, 0x65, 0x51, 0x41, 0x79, 0x70, 0x6c, 0x51, 0x53, 0x69, 0x47, +0x6b, 0x52, 0x6b, 0x6e, 0x44, 0x65, 0x65, 0x65, 0x39, 0x77, 0x72, 0x65, 0x4f, 0x6d, 0x73, 0x43, +0x42, 0x42, 0x37, 0x52, 0x67, 0x74, 0x4f, 0x48, 0x35, 0x76, 0x36, 0x37, 0x67, 0x2b, 0x39, 0x39, +0x2f, 0x44, 0x53, 0x6b, 0x74, 0x51, 0x75, 0x68, 0x55, 0x69, 0x34, 0x43, 0x49, 0x63, 0x30, 0x31, +0x41, 0x36, 0x78, 0x74, 0x76, 0x45, 0x45, 0x55, 0x52, 0x78, 0x68, 0x69, 0x73, 0x74, 0x56, 0x78, +0x78, 0x52, 0x5a, 0x36, 0x50, 0x50, 0x77, 0x7a, 0x5a, 0x73, 0x39, 0x79, 0x77, 0x7a, 0x63, 0x33, +0x72, 0x2b, 0x63, 0x6b, 0x74, 0x47, 0x56, 0x36, 0x50, 0x49, 0x71, 0x65, 0x2b, 0x68, 0x79, 0x47, +0x32, 0x72, 0x49, 0x79, 0x4b, 0x6a, 0x52, 0x76, 0x5a, 0x49, 0x43, 0x56, 0x6e, 0x46, 0x44, 0x4d, +0x63, 0x66, 0x67, 0x57, 0x32, 0x46, 0x70, 0x76, 0x62, 0x42, 0x36, 0x4c, 0x31, 0x67, 0x4d, 0x42, +0x57, 0x48, 0x44, 0x6a, 0x67, 0x2f, 0x42, 0x74, 0x6a, 0x65, 0x49, 0x43, 0x39, 0x32, 0x4b, 0x56, +0x39, 0x4a, 0x30, 0x5a, 0x76, 0x66, 0x4a, 0x50, 0x4e, 0x50, 0x2f, 0x71, 0x45, 0x33, 0x72, 0x64, +0x2b, 0x53, 0x48, 0x5a, 0x34, 0x43, 0x78, 0x56, 0x37, 0x37, 0x30, 0x2f, 0x5a, 0x4e, 0x6a, 0x74, +0x6a, 0x67, 0x34, 0x44, 0x4b, 0x34, 0x56, 0x4d, 0x51, 0x62, 0x53, 0x2b, 0x51, 0x36, 0x35, 0x6c, +0x44, 0x55, 0x48, 0x38, 0x59, 0x6f, 0x77, 0x37, 0x59, 0x6b, 0x63, 0x31, 0x32, 0x2f, 0x6a, 0x5a, +0x4c, 0x33, 0x2f, 0x75, 0x34, 0x6c, 0x4f, 0x47, 0x4c, 0x36, 0x2f, 0x2b, 0x36, 0x42, 0x63, 0x6a, +0x58, 0x66, 0x2b, 0x66, 0x66, 0x32, 0x70, 0x68, 0x79, 0x57, 0x45, 0x68, 0x47, 0x35, 0x4a, 0x6d, +0x74, 0x47, 0x78, 0x78, 0x74, 0x71, 0x4a, 0x67, 0x46, 0x69, 0x33, 0x72, 0x35, 0x79, 0x4e, 0x73, +0x31, 0x64, 0x7a, 0x7a, 0x30, 0x4c, 0x6b, 0x49, 0x70, 0x77, 0x48, 0x4c, 0x34, 0x66, 0x75, 0x4f, +0x35, 0x2f, 0x34, 0x6b, 0x50, 0x47, 0x54, 0x4b, 0x6f, 0x43, 0x68, 0x44, 0x45, 0x79, 0x6e, 0x67, +0x61, 0x38, 0x38, 0x79, 0x76, 0x6e, 0x62, 0x33, 0x75, 0x56, 0x50, 0x2b, 0x2b, 0x41, 0x73, 0x42, +0x70, 0x42, 0x64, 0x49, 0x4c, 0x43, 0x59, 0x52, 0x62, 0x51, 0x6f, 0x50, 0x45, 0x71, 0x36, 0x38, +0x55, 0x67, 0x64, 0x4c, 0x45, 0x6e, 0x38, 0x34, 0x6a, 0x58, 0x76, 0x77, 0x35, 0x4c, 0x65, 0x65, +0x63, 0x51, 0x39, 0x73, 0x54, 0x66, 0x36, 0x4a, 0x36, 0x72, 0x37, 0x33, 0x6f, 0x65, 0x66, 0x74, +0x64, 0x67, 0x74, 0x67, 0x35, 0x4e, 0x51, 0x50, 0x70, 0x66, 0x6d, 0x2f, 0x2b, 0x76, 0x77, 0x52, +0x41, 0x6f, 0x6c, 0x6f, 0x4b, 0x61, 0x59, 0x68, 0x46, 0x77, 0x49, 0x6a, 0x4e, 0x6c, 0x37, 0x48, +0x6b, 0x6b, 0x38, 0x31, 0x35, 0x59, 0x39, 0x49, 0x45, 0x35, 0x44, 0x73, 0x43, 0x4a, 0x51, 0x56, +0x6a, 0x74, 0x31, 0x32, 0x43, 0x37, 0x6f, 0x6d, 0x77, 0x73, 0x63, 0x42, 0x34, 0x57, 0x7a, 0x41, +0x4a, 0x70, 0x51, 0x53, 0x4a, 0x58, 0x5a, 0x69, 0x73, 0x45, 0x76, 0x2b, 0x43, 0x2b, 0x6d, 0x2f, +0x39, 0x42, 0x47, 0x41, 0x74, 0x55, 0x6b, 0x71, 0x69, 0x4b, 0x45, 0x71, 0x46, 0x67, 0x49, 0x6b, +0x69, 0x37, 0x46, 0x39, 0x66, 0x4a, 0x42, 0x72, 0x61, 0x68, 0x4a, 0x57, 0x4b, 0x33, 0x4b, 0x66, +0x7a, 0x49, 0x59, 0x35, 0x52, 0x6f, 0x6d, 0x41, 0x43, 0x53, 0x43, 0x4e, 0x42, 0x2b, 0x4c, 0x43, +0x50, 0x55, 0x6c, 0x69, 0x70, 0x6b, 0x55, 0x71, 0x79, 0x70, 0x31, 0x37, 0x4f, 0x58, 0x72, 0x32, +0x76, 0x55, 0x48, 0x2f, 0x69, 0x66, 0x35, 0x66, 0x55, 0x32, 0x66, 0x62, 0x37, 0x33, 0x79, 0x50, +0x69, 0x2b, 0x51, 0x67, 0x6c, 0x4d, 0x64, 0x4a, 0x35, 0x69, 0x41, 0x31, 0x41, 0x4c, 0x46, 0x44, +0x57, 0x71, 0x57, 0x6a, 0x61, 0x46, 0x4b, 0x74, 0x70, 0x46, 0x71, 0x45, 0x4d, 0x56, 0x6a, 0x75, +0x62, 0x64, 0x63, 0x46, 0x48, 0x79, 0x78, 0x6e, 0x79, 0x6a, 0x56, 0x61, 0x30, 0x43, 0x66, 0x6a, +0x69, 0x2f, 0x57, 0x57, 0x4d, 0x47, 0x56, 0x49, 0x47, 0x4f, 0x44, 0x4d, 0x49, 0x36, 0x59, 0x53, +0x66, 0x6c, 0x6f, 0x4a, 0x4b, 0x4a, 0x66, 0x6a, 0x4a, 0x6d, 0x67, 0x35, 0x2b, 0x57, 0x4a, 0x4e, +0x68, 0x35, 0x72, 0x71, 0x59, 0x4b, 0x49, 0x34, 0x35, 0x74, 0x54, 0x48, 0x48, 0x39, 0x31, 0x65, +0x32, 0x63, 0x2b, 0x2f, 0x67, 0x4d, 0x75, 0x65, 0x67, 0x45, 0x67, 0x4b, 0x6a, 0x46, 0x62, 0x31, +0x41, 0x39, 0x2b, 0x31, 0x6e, 0x6b, 0x39, 0x33, 0x72, 0x46, 0x6d, 0x7a, 0x50, 0x53, 0x71, 0x78, +0x31, 0x55, 0x51, 0x75, 0x72, 0x5a, 0x65, 0x6e, 0x56, 0x4f, 0x47, 0x65, 0x6d, 0x4e, 0x52, 0x71, +0x4d, 0x65, 0x78, 0x5a, 0x57, 0x6a, 0x2b, 0x52, 0x48, 0x30, 0x52, 0x38, 0x59, 0x38, 0x75, 0x73, +0x4e, 0x31, 0x4e, 0x66, 0x58, 0x39, 0x31, 0x2f, 0x39, 0x4a, 0x6b, 0x33, 0x43, 0x50, 0x75, 0x68, +0x38, 0x42, 0x56, 0x73, 0x4b, 0x77, 0x53, 0x55, 0x66, 0x66, 0x56, 0x51, 0x79, 0x2f, 0x6b, 0x45, +0x51, 0x73, 0x47, 0x6a, 0x52, 0x56, 0x68, 0x78, 0x2f, 0x2f, 0x50, 0x47, 0x70, 0x41, 0x45, 0x6d, +0x2b, 0x58, 0x37, 0x41, 0x67, 0x34, 0x4d, 0x67, 0x6a, 0x4a, 0x55, 0x72, 0x42, 0x2f, 0x62, 0x38, +0x4e, 0x75, 0x4f, 0x42, 0x63, 0x78, 0x57, 0x75, 0x76, 0x68, 0x61, 0x6d, 0x41, 0x63, 0x4b, 0x45, +0x75, 0x68, 0x5a, 0x53, 0x53, 0x65, 0x52, 0x32, 0x47, 0x69, 0x62, 0x55, 0x57, 0x6f, 0x53, 0x33, +0x57, 0x65, 0x37, 0x47, 0x64, 0x6e, 0x58, 0x38, 0x51, 0x74, 0x75, 0x71, 0x62, 0x47, 0x4f, 0x76, +0x4d, 0x53, 0x74, 0x4e, 0x54, 0x6d, 0x41, 0x74, 0x6a, 0x49, 0x4a, 0x65, 0x31, 0x76, 0x4c, 0x6c, +0x65, 0x6f, 0x36, 0x68, 0x43, 0x44, 0x36, 0x72, 0x6d, 0x30, 0x59, 0x56, 0x48, 0x45, 0x63, 0x65, +0x48, 0x30, 0x43, 0x72, 0x6e, 0x38, 0x38, 0x32, 0x56, 0x4c, 0x7a, 0x4c, 0x75, 0x30, 0x2f, 0x73, +0x4a, 0x31, 0x58, 0x51, 0x71, 0x74, 0x74, 0x2b, 0x4f, 0x69, 0x73, 0x4f, 0x50, 0x49, 0x72, 0x76, +0x5a, 0x51, 0x66, 0x52, 0x73, 0x6e, 0x45, 0x6d, 0x77, 0x36, 0x69, 0x59, 0x6d, 0x54, 0x68, 0x43, +0x55, 0x5a, 0x31, 0x39, 0x44, 0x79, 0x6d, 0x6f, 0x47, 0x48, 0x33, 0x77, 0x77, 0x39, 0x70, 0x4a, +0x4c, 0x73, 0x4f, 0x76, 0x57, 0x6c, 0x66, 0x70, 0x4f, 0x6c, 0x4d, 0x49, 0x71, 0x58, 0x56, 0x69, +0x63, 0x74, 0x43, 0x62, 0x72, 0x6e, 0x32, 0x65, 0x31, 0x78, 0x67, 0x34, 0x62, 0x42, 0x74, 0x4f, +0x6d, 0x41, 0x61, 0x65, 0x42, 0x31, 0x37, 0x71, 0x4f, 0x33, 0x57, 0x38, 0x43, 0x45, 0x30, 0x59, +0x50, 0x35, 0x72, 0x6f, 0x37, 0x58, 0x6e, 0x4d, 0x32, 0x75, 0x74, 0x46, 0x49, 0x36, 0x53, 0x49, +0x37, 0x56, 0x6c, 0x76, 0x69, 0x57, 0x50, 0x47, 0x4c, 0x2b, 0x32, 0x59, 0x54, 0x42, 0x70, 0x62, +0x42, 0x64, 0x65, 0x57, 0x41, 0x51, 0x70, 0x36, 0x36, 0x50, 0x30, 0x48, 0x6a, 0x56, 0x4b, 0x78, +0x61, 0x44, 0x6c, 0x5a, 0x69, 0x72, 0x58, 0x52, 0x61, 0x54, 0x2f, 0x47, 0x31, 0x35, 0x4a, 0x6b, +0x47, 0x4b, 0x77, 0x6d, 0x79, 0x6f, 0x37, 0x6a, 0x68, 0x32, 0x68, 0x64, 0x5a, 0x64, 0x43, 0x52, +0x6f, 0x37, 0x52, 0x61, 0x50, 0x52, 0x4a, 0x4d, 0x30, 0x6f, 0x57, 0x58, 0x56, 0x66, 0x62, 0x2f, +0x42, 0x43, 0x6f, 0x6e, 0x52, 0x69, 0x76, 0x61, 0x35, 0x6e, 0x7a, 0x72, 0x37, 0x50, 0x2f, 0x6d, +0x4e, 0x55, 0x57, 0x53, 0x4d, 0x6f, 0x76, 0x76, 0x2f, 0x52, 0x51, 0x44, 0x30, 0x4a, 0x75, 0x71, +0x6d, 0x52, 0x6b, 0x70, 0x4c, 0x48, 0x49, 0x4f, 0x31, 0x45, 0x58, 0x73, 0x65, 0x38, 0x79, 0x37, +0x2f, 0x66, 0x48, 0x63, 0x59, 0x53, 0x6b, 0x5a, 0x73, 0x76, 0x75, 0x74, 0x43, 0x74, 0x49, 0x34, +0x78, 0x76, 0x63, 0x34, 0x42, 0x61, 0x4b, 0x51, 0x69, 0x6b, 0x44, 0x4b, 0x4e, 0x43, 0x32, 0x65, +0x4b, 0x76, 0x4e, 0x4e, 0x57, 0x53, 0x69, 0x5a, 0x4e, 0x6d, 0x6f, 0x54, 0x77, 0x39, 0x6e, 0x78, +0x36, 0x39, 0x54, 0x61, 0x2b, 0x55, 0x68, 0x4b, 0x6c, 0x4e, 0x4f, 0x50, 0x48, 0x6a, 0x32, 0x66, +0x4f, 0x6e, 0x44, 0x6d, 0x41, 0x69, 0x2f, 0x30, 0x4c, 0x49, 0x59, 0x69, 0x69, 0x69, 0x44, 0x69, +0x4f, 0x73, 0x56, 0x47, 0x45, 0x6e, 0x54, 0x65, 0x66, 0x79, 0x67, 0x38, 0x2f, 0x63, 0x6f, 0x37, +0x48, 0x4b, 0x45, 0x4c, 0x48, 0x4d, 0x54, 0x4b, 0x47, 0x53, 0x4f, 0x63, 0x52, 0x32, 0x6f, 0x55, +0x52, 0x45, 0x77, 0x48, 0x67, 0x4a, 0x6c, 0x74, 0x67, 0x70, 0x47, 0x75, 0x48, 0x66, 0x76, 0x59, +0x70, 0x6f, 0x71, 0x30, 0x6d, 0x6b, 0x74, 0x74, 0x6d, 0x47, 0x36, 0x79, 0x31, 0x52, 0x50, 0x50, +0x6d, 0x38, 0x75, 0x58, 0x50, 0x66, 0x30, 0x35, 0x44, 0x66, 0x55, 0x58, 0x71, 0x59, 0x4c, 0x46, +0x47, 0x4f, 0x79, 0x65, 0x63, 0x6c, 0x44, 0x37, 0x36, 0x35, 0x56, 0x51, 0x32, 0x62, 0x61, 0x78, +0x62, 0x6b, 0x62, 0x58, 0x46, 0x65, 0x4a, 0x4e, 0x49, 0x47, 0x6f, 0x76, 0x4d, 0x53, 0x31, 0x5a, +0x39, 0x75, 0x4d, 0x77, 0x35, 0x53, 0x33, 0x73, 0x45, 0x65, 0x6c, 0x41, 0x5a, 0x69, 0x51, 0x5a, +0x67, 0x74, 0x4d, 0x54, 0x34, 0x38, 0x43, 0x68, 0x43, 0x4d, 0x4b, 0x30, 0x75, 0x51, 0x30, 0x5a, +0x4a, 0x4a, 0x6d, 0x55, 0x73, 0x58, 0x61, 0x47, 0x68, 0x52, 0x6b, 0x6e, 0x75, 0x47, 0x31, 0x79, +0x47, 0x54, 0x68, 0x79, 0x63, 0x32, 0x6a, 0x6c, 0x33, 0x41, 0x45, 0x77, 0x49, 0x47, 0x4f, 0x57, +0x5a, 0x33, 0x33, 0x31, 0x58, 0x59, 0x48, 0x37, 0x70, 0x6d, 0x64, 0x38, 0x2f, 0x4d, 0x38, 0x72, +0x39, 0x31, 0x69, 0x69, 0x4d, 0x4e, 0x5a, 0x41, 0x74, 0x4f, 0x50, 0x4c, 0x36, 0x43, 0x59, 0x43, +0x6b, 0x72, 0x75, 0x54, 0x61, 0x52, 0x77, 0x41, 0x37, 0x75, 0x64, 0x6c, 0x66, 0x57, 0x7a, 0x50, +0x47, 0x38, 0x4f, 0x53, 0x54, 0x49, 0x55, 0x38, 0x38, 0x6b, 0x55, 0x32, 0x66, 0x50, 0x66, 0x5a, +0x45, 0x77, 0x50, 0x48, 0x48, 0x47, 0x52, 0x35, 0x2f, 0x77, 0x76, 0x61, 0x72, 0x37, 0x2f, 0x79, +0x46, 0x67, 0x37, 0x6b, 0x69, 0x41, 0x32, 0x76, 0x79, 0x53, 0x65, 0x69, 0x71, 0x6f, 0x41, 0x61, +0x37, 0x63, 0x46, 0x62, 0x52, 0x35, 0x2f, 0x51, 0x4b, 0x7a, 0x5a, 0x56, 0x77, 0x38, 0x78, 0x75, +0x44, 0x41, 0x49, 0x30, 0x51, 0x57, 0x65, 0x4c, 0x59, 0x45, 0x73, 0x64, 0x6c, 0x7a, 0x49, 0x32, +0x33, 0x34, 0x59, 0x4e, 0x34, 0x61, 0x32, 0x54, 0x55, 0x77, 0x30, 0x37, 0x71, 0x37, 0x78, 0x79, +0x38, 0x34, 0x6e, 0x6b, 0x32, 0x65, 0x2b, 0x48, 0x37, 0x5a, 0x43, 0x74, 0x7a, 0x56, 0x4f, 0x32, +0x39, 0x43, 0x32, 0x58, 0x66, 0x6e, 0x6f, 0x7a, 0x4d, 0x5a, 0x69, 0x6a, 0x50, 0x61, 0x73, 0x4a, +0x77, 0x4b, 0x57, 0x62, 0x4f, 0x48, 0x44, 0x4b, 0x7a, 0x5a, 0x32, 0x4f, 0x58, 0x4c, 0x45, 0x6e, +0x70, 0x4c, 0x7a, 0x46, 0x56, 0x53, 0x76, 0x71, 0x66, 0x33, 0x43, 0x76, 0x70, 0x56, 0x4d, 0x4c, +0x78, 0x34, 0x2f, 0x30, 0x6f, 0x43, 0x49, 0x54, 0x53, 0x57, 0x47, 0x76, 0x5a, 0x62, 0x66, 0x73, +0x52, 0x31, 0x46, 0x53, 0x57, 0x63, 0x63, 0x7a, 0x42, 0x57, 0x2f, 0x4c, 0x77, 0x30, 0x33, 0x4f, +0x38, 0x31, 0x71, 0x57, 0x52, 0x79, 0x68, 0x41, 0x4a, 0x79, 0x63, 0x6a, 0x6d, 0x4f, 0x6f, 0x34, +0x37, 0x65, 0x45, 0x74, 0x75, 0x75, 0x50, 0x76, 0x76, 0x61, 0x47, 0x30, 0x42, 0x52, 0x64, 0x6e, +0x74, 0x7a, 0x33, 0x48, 0x39, 0x73, 0x52, 0x4e, 0x5a, 0x30, 0x52, 0x6d, 0x6e, 0x39, 0x72, 0x33, +0x30, 0x47, 0x6d, 0x54, 0x69, 0x41, 0x45, 0x79, 0x66, 0x65, 0x39, 0x74, 0x66, 0x47, 0x63, 0x4f, +0x6f, 0x2b, 0x67, 0x71, 0x65, 0x2b, 0x4e, 0x47, 0x2b, 0x38, 0x4f, 0x4f, 0x72, 0x4f, 0x57, 0x63, +0x76, 0x7a, 0x5a, 0x49, 0x75, 0x6a, 0x64, 0x51, 0x4b, 0x61, 0x54, 0x52, 0x43, 0x4b, 0x34, 0x51, +0x57, 0x53, 0x43, 0x45, 0x52, 0x61, 0x4b, 0x52, 0x52, 0x44, 0x6c, 0x64, 0x67, 0x46, 0x45, 0x6f, +0x72, 0x6c, 0x4e, 0x47, 0x4d, 0x72, 0x7a, 0x66, 0x4d, 0x57, 0x66, 0x62, 0x2f, 0x49, 0x41, 0x41, +0x36, 0x65, 0x79, 0x4f, 0x6b, 0x73, 0x74, 0x54, 0x57, 0x5a, 0x4a, 0x48, 0x53, 0x6b, 0x43, 0x73, +0x44, 0x47, 0x41, 0x62, 0x45, 0x62, 0x4c, 0x47, 0x72, 0x77, 0x42, 0x69, 0x46, 0x4d, 0x53, 0x4d, +0x4a, 0x51, 0x30, 0x45, 0x77, 0x79, 0x67, 0x46, 0x55, 0x41, 0x6d, 0x2f, 0x76, 0x4a, 0x78, 0x70, +0x41, 0x4b, 0x42, 0x57, 0x30, 0x74, 0x44, 0x67, 0x68, 0x6f, 0x44, 0x51, 0x6a, 0x6c, 0x55, 0x52, +0x4b, 0x64, 0x79, 0x59, 0x72, 0x68, 0x56, 0x49, 0x4b, 0x70, 0x5a, 0x79, 0x36, 0x6d, 0x70, 0x7a, +0x4a, 0x45, 0x63, 0x63, 0x78, 0x67, 0x78, 0x73, 0x62, 0x45, 0x62, 0x47, 0x7a, 0x6d, 0x59, 0x6b, +0x46, 0x69, 0x4a, 0x68, 0x41, 0x43, 0x49, 0x49, 0x34, 0x4a, 0x70, 0x43, 0x53, 0x55, 0x41, 0x6a, +0x71, 0x68, 0x73, 0x47, 0x59, 0x32, 0x6b, 0x61, 0x6b, 0x6b, 0x69, 0x69, 0x6a, 0x6f, 0x4e, 0x63, +0x44, 0x61, 0x35, 0x51, 0x6d, 0x48, 0x44, 0x6f, 0x73, 0x62, 0x5a, 0x64, 0x56, 0x69, 0x6e, 0x58, +0x33, 0x33, 0x38, 0x2f, 0x77, 0x61, 0x64, 0x4f, 0x77, 0x59, 0x63, 0x69, 0x36, 0x4f, 0x2b, 0x2b, +0x69, 0x61, 0x66, 0x75, 0x74, 0x73, 0x4d, 0x70, 0x67, 0x74, 0x51, 0x4b, 0x6a, 0x4d, 0x63, 0x72, +0x58, 0x48, 0x77, 0x75, 0x45, 0x4d, 0x67, 0x79, 0x72, 0x7a, 0x61, 0x55, 0x61, 0x51, 0x4f, 0x4c, +0x41, 0x30, 0x64, 0x61, 0x72, 0x62, 0x63, 0x61, 0x34, 0x55, 0x4c, 0x69, 0x66, 0x56, 0x4e, 0x4e, +0x51, 0x6a, 0x55, 0x6f, 0x68, 0x4d, 0x57, 0x43, 0x6c, 0x49, 0x6a, 0x4e, 0x6b, 0x4b, 0x4b, 0x48, +0x33, 0x30, 0x69, 0x4b, 0x64, 0x4d, 0x50, 0x70, 0x42, 0x51, 0x36, 0x50, 0x7a, 0x34, 0x47, 0x72, +0x6e, 0x63, 0x77, 0x69, 0x56, 0x41, 0x71, 0x6b, 0x78, 0x6e, 0x74, 0x45, 0x4e, 0x59, 0x44, 0x72, +0x42, 0x43, 0x67, 0x32, 0x5a, 0x49, 0x53, 0x52, 0x67, 0x6b, 0x79, 0x42, 0x51, 0x45, 0x42, 0x53, +0x59, 0x50, 0x51, 0x67, 0x31, 0x67, 0x66, 0x58, 0x52, 0x41, 0x61, 0x4d, 0x78, 0x4b, 0x49, 0x67, +0x56, 0x70, 0x70, 0x31, 0x30, 0x56, 0x53, 0x35, 0x6d, 0x53, 0x67, 0x42, 0x61, 0x57, 0x77, 0x6d, +0x6b, 0x54, 0x4a, 0x31, 0x36, 0x65, 0x4c, 0x73, 0x62, 0x41, 0x67, 0x6f, 0x51, 0x48, 0x33, 0x63, +0x59, 0x59, 0x38, 0x6a, 0x6c, 0x63, 0x75, 0x6d, 0x37, 0x42, 0x68, 0x49, 0x4b, 0x4d, 0x35, 0x36, +0x78, 0x6c, 0x4a, 0x66, 0x33, 0x46, 0x79, 0x4b, 0x68, 0x4d, 0x51, 0x53, 0x45, 0x4e, 0x4a, 0x55, +0x58, 0x77, 0x6e, 0x2f, 0x61, 0x34, 0x71, 0x34, 0x6d, 0x51, 0x46, 0x75, 0x50, 0x61, 0x2f, 0x45, +0x77, 0x41, 0x34, 0x63, 0x4c, 0x73, 0x4c, 0x34, 0x46, 0x78, 0x73, 0x38, 0x2f, 0x62, 0x44, 0x55, +0x78, 0x49, 0x49, 0x34, 0x67, 0x38, 0x6d, 0x63, 0x63, 0x31, 0x37, 0x42, 0x65, 0x48, 0x4d, 0x5a, +0x76, 0x6f, 0x30, 0x4f, 0x78, 0x63, 0x51, 0x2b, 0x48, 0x5a, 0x39, 0x35, 0x67, 0x2b, 0x77, 0x39, +0x66, 0x70, 0x2f, 0x37, 0x6a, 0x36, 0x65, 0x52, 0x47, 0x6a, 0x45, 0x54, 0x74, 0x64, 0x79, 0x44, +0x47, 0x35, 0x41, 0x65, 0x6b, 0x50, 0x35, 0x51, 0x50, 0x6c, 0x52, 0x62, 0x33, 0x50, 0x33, 0x46, +0x77, 0x46, 0x6b, 0x56, 0x61, 0x6a, 0x42, 0x63, 0x41, 0x78, 0x68, 0x67, 0x47, 0x31, 0x31, 0x66, +0x79, 0x77, 0x68, 0x75, 0x4c, 0x32, 0x57, 0x37, 0x7a, 0x4a, 0x6d, 0x61, 0x39, 0x73, 0x35, 0x54, +0x57, 0x35, 0x6a, 0x72, 0x69, 0x57, 0x4b, 0x4f, 0x74, 0x38, 0x37, 0x48, 0x6b, 0x49, 0x38, 0x47, +0x6c, 0x5a, 0x2b, 0x7a, 0x47, 0x78, 0x48, 0x46, 0x44, 0x69, 0x59, 0x58, 0x6d, 0x54, 0x79, 0x2b, +0x34, 0x4b, 0x46, 0x44, 0x2b, 0x33, 0x43, 0x50, 0x49, 0x4e, 0x6c, 0x2f, 0x71, 0x42, 0x4c, 0x53, +0x56, 0x59, 0x41, 0x76, 0x43, 0x6e, 0x45, 0x53, 0x6a, 0x51, 0x33, 0x6c, 0x4e, 0x77, 0x44, 0x67, +0x4e, 0x41, 0x4f, 0x64, 0x7a, 0x75, 0x65, 0x6d, 0x32, 0x31, 0x78, 0x6a, 0x33, 0x47, 0x6b, 0x69, +0x70, 0x61, 0x4d, 0x6b, 0x4e, 0x38, 0x54, 0x67, 0x5a, 0x78, 0x2b, 0x54, 0x53, 0x4b, 0x47, 0x53, +0x5a, 0x2b, 0x79, 0x79, 0x4e, 0x52, 0x6d, 0x6d, 0x4e, 0x73, 0x70, 0x35, 0x2f, 0x72, 0x45, 0x62, +0x48, 0x47, 0x74, 0x6f, 0x67, 0x4b, 0x4a, 0x6e, 0x30, 0x2f, 0x38, 0x4f, 0x78, 0x2f, 0x65, 0x47, +0x76, 0x32, 0x62, 0x56, 0x72, 0x49, 0x37, 0x6f, 0x6a, 0x51, 0x57, 0x2b, 0x33, 0x51, 0x6e, 0x66, +0x43, 0x73, 0x6f, 0x2b, 0x4f, 0x53, 0x33, 0x31, 0x43, 0x78, 0x61, 0x66, 0x5a, 0x6f, 0x59, 0x41, +0x45, 0x54, 0x42, 0x79, 0x41, 0x32, 0x39, 0x4d, 0x66, 0x58, 0x64, 0x58, 0x34, 0x48, 0x37, 0x55, +0x49, 0x6c, 0x6c, 0x47, 0x4b, 0x4f, 0x45, 0x7a, 0x4f, 0x51, 0x34, 0x45, 0x31, 0x57, 0x2b, 0x42, +0x38, 0x58, 0x77, 0x71, 0x6f, 0x67, 0x72, 0x6b, 0x4c, 0x43, 0x79, 0x69, 0x37, 0x34, 0x72, 0x59, +0x6c, 0x7a, 0x2f, 0x69, 0x4b, 0x61, 0x78, 0x59, 0x34, 0x65, 0x76, 0x44, 0x4e, 0x66, 0x64, 0x42, +0x39, 0x65, 0x55, 0x41, 0x57, 0x58, 0x53, 0x4d, 0x63, 0x6f, 0x34, 0x75, 0x69, 0x65, 0x30, 0x6e, +0x43, 0x2f, 0x47, 0x2f, 0x78, 0x4c, 0x76, 0x52, 0x70, 0x62, 0x33, 0x4b, 0x66, 0x52, 0x45, 0x6d, +0x69, 0x6f, 0x72, 0x34, 0x6c, 0x7a, 0x2f, 0x48, 0x50, 0x4a, 0x39, 0x2b, 0x4b, 0x69, 0x32, 0x59, +0x49, 0x42, 0x2f, 0x35, 0x4b, 0x72, 0x77, 0x70, 0x55, 0x30, 0x54, 0x33, 0x4a, 0x4d, 0x31, 0x2b, +0x42, 0x38, 0x66, 0x31, 0x76, 0x75, 0x50, 0x33, 0x4c, 0x66, 0x75, 0x67, 0x2b, 0x59, 0x77, 0x78, +0x71, 0x33, 0x4c, 0x68, 0x30, 0x6a, 0x68, 0x52, 0x67, 0x2f, 0x76, 0x45, 0x50, 0x54, 0x42, 0x69, +0x43, 0x63, 0x5a, 0x37, 0x70, 0x35, 0x44, 0x6a, 0x68, 0x68, 0x42, 0x50, 0x53, 0x2b, 0x37, 0x36, +0x43, 0x70, 0x4a, 0x69, 0x32, 0x2b, 0x6a, 0x4a, 0x2b, 0x63, 0x67, 0x79, 0x37, 0x35, 0x35, 0x2b, +0x30, 0x69, 0x51, 0x4b, 0x36, 0x4c, 0x31, 0x4b, 0x47, 0x53, 0x44, 0x6b, 0x51, 0x53, 0x34, 0x70, +0x63, 0x38, 0x77, 0x41, 0x6a, 0x68, 0x34, 0x62, 0x78, 0x56, 0x4b, 0x4b, 0x41, 0x48, 0x44, 0x42, +0x6c, 0x4f, 0x41, 0x58, 0x4b, 0x4b, 0x63, 0x5a, 0x4a, 0x39, 0x6e, 0x32, 0x57, 0x6a, 0x50, 0x4c, +0x66, 0x79, 0x58, 0x41, 0x61, 0x50, 0x38, 0x47, 0x68, 0x55, 0x45, 0x38, 0x61, 0x6f, 0x41, 0x51, +0x44, 0x50, 0x42, 0x76, 0x6f, 0x4e, 0x77, 0x44, 0x6a, 0x4f, 0x4e, 0x4c, 0x58, 0x6b, 0x63, 0x42, +0x4c, 0x69, 0x30, 0x2f, 0x56, 0x37, 0x39, 0x6d, 0x45, 0x2f, 0x61, 0x39, 0x6b, 0x34, 0x61, 0x73, +0x2f, 0x4c, 0x62, 0x7a, 0x6c, 0x34, 0x70, 0x65, 0x67, 0x4d, 0x33, 0x4c, 0x39, 0x39, 0x48, 0x5a, +0x38, 0x65, 0x69, 0x2b, 0x4b, 0x55, 0x48, 0x7a, 0x70, 0x76, 0x54, 0x2b, 0x4e, 0x67, 0x61, 0x6f, +0x73, 0x48, 0x48, 0x6f, 0x42, 0x64, 0x41, 0x35, 0x51, 0x56, 0x56, 0x2f, 0x6b, 0x72, 0x4b, 0x49, +0x2f, 0x6f, 0x64, 0x64, 0x41, 0x41, 0x4f, 0x2f, 0x5a, 0x43, 0x59, 0x63, 0x30, 0x38, 0x4d, 0x64, +0x66, 0x6a, 0x75, 0x53, 0x6d, 0x6e, 0x30, 0x7a, 0x6d, 0x6f, 0x58, 0x4f, 0x65, 0x70, 0x4c, 0x73, +0x58, 0x42, 0x74, 0x66, 0x35, 0x67, 0x66, 0x41, 0x4f, 0x58, 0x71, 0x4d, 0x53, 0x6a, 0x7a, 0x6e, +0x55, 0x2f, 0x74, 0x63, 0x7a, 0x68, 0x54, 0x64, 0x6c, 0x50, 0x69, 0x32, 0x64, 0x55, 0x57, 0x33, +0x51, 0x48, 0x31, 0x37, 0x6e, 0x37, 0x74, 0x74, 0x38, 0x75, 0x53, 0x71, 0x6e, 0x71, 0x6c, 0x5a, +0x4f, 0x75, 0x74, 0x67, 0x39, 0x4c, 0x47, 0x37, 0x64, 0x67, 0x63, 0x2b, 0x55, 0x6c, 0x69, 0x2f, +0x6d, 0x76, 0x72, 0x36, 0x64, 0x69, 0x76, 0x72, 0x63, 0x53, 0x77, 0x59, 0x38, 0x4f, 0x6a, 0x5a, +0x43, 0x6a, 0x65, 0x63, 0x53, 0x59, 0x38, 0x41, 0x30, 0x75, 0x4a, 0x58, 0x53, 0x44, 0x4f, 0x73, +0x2f, 0x6b, 0x59, 0x50, 0x37, 0x6c, 0x44, 0x55, 0x44, 0x66, 0x50, 0x36, 0x71, 0x73, 0x36, 0x4b, +0x6e, 0x70, 0x31, 0x2f, 0x39, 0x69, 0x5a, 0x71, 0x62, 0x4d, 0x46, 0x50, 0x78, 0x66, 0x51, 0x6d, +0x54, 0x47, 0x63, 0x4f, 0x67, 0x2b, 0x76, 0x71, 0x53, 0x73, 0x72, 0x55, 0x7a, 0x5a, 0x32, 0x4a, +0x4f, 0x4f, 0x6f, 0x6b, 0x69, 0x4c, 0x39, 0x31, 0x58, 0x6b, 0x76, 0x66, 0x67, 0x75, 0x58, 0x4e, +0x42, 0x56, 0x4c, 0x46, 0x67, 0x39, 0x2f, 0x47, 0x59, 0x57, 0x4a, 0x4d, 0x64, 0x4e, 0x69, 0x79, +0x4e, 0x2f, 0x79, 0x4b, 0x63, 0x76, 0x30, 0x56, 0x5a, 0x57, 0x77, 0x49, 0x66, 0x42, 0x74, 0x6a, +0x36, 0x75, 0x62, 0x63, 0x77, 0x32, 0x55, 0x34, 0x61, 0x46, 0x78, 0x78, 0x53, 0x4b, 0x6d, 0x47, +0x53, 0x69, 0x67, 0x41, 0x39, 0x74, 0x63, 0x42, 0x37, 0x41, 0x35, 0x37, 0x41, 0x6f, 0x68, 0x39, +0x65, 0x77, 0x55, 0x76, 0x68, 0x61, 0x4b, 0x36, 0x2b, 0x65, 0x78, 0x37, 0x58, 0x4e, 0x48, 0x31, +0x4d, 0x4e, 0x6f, 0x51, 0x66, 0x72, 0x78, 0x6e, 0x4a, 0x42, 0x61, 0x33, 0x64, 0x6e, 0x4c, 0x54, +0x50, 0x63, 0x4e, 0x72, 0x2f, 0x63, 0x41, 0x39, 0x68, 0x6e, 0x37, 0x61, 0x72, 0x51, 0x68, 0x55, +0x63, 0x39, 0x55, 0x2f, 0x63, 0x66, 0x49, 0x5a, 0x46, 0x54, 0x53, 0x6a, 0x69, 0x73, 0x6f, 0x54, +0x32, 0x4b, 0x4b, 0x35, 0x58, 0x46, 0x58, 0x68, 0x67, 0x35, 0x49, 0x6d, 0x5a, 0x30, 0x72, 0x46, +0x58, 0x75, 0x6b, 0x52, 0x79, 0x70, 0x71, 0x6a, 0x43, 0x54, 0x5a, 0x79, 0x4e, 0x33, 0x2b, 0x30, +0x37, 0x65, 0x64, 0x42, 0x50, 0x43, 0x67, 0x2f, 0x4d, 0x79, 0x32, 0x37, 0x63, 0x78, 0x68, 0x38, +0x42, 0x55, 0x36, 0x64, 0x43, 0x4c, 0x75, 0x64, 0x55, 0x6a, 0x36, 0x54, 0x52, 0x4b, 0x66, 0x36, +0x39, 0x4b, 0x45, 0x4b, 0x53, 0x43, 0x6a, 0x4c, 0x50, 0x36, 0x47, 0x46, 0x49, 0x66, 0x76, 0x68, +0x33, 0x79, 0x4b, 0x6f, 0x2b, 0x64, 0x4f, 0x64, 0x2f, 0x68, 0x6f, 0x4a, 0x73, 0x7a, 0x76, 0x47, +0x4f, 0x69, 0x62, 0x78, 0x77, 0x42, 0x30, 0x77, 0x4f, 0x54, 0x42, 0x62, 0x4d, 0x72, 0x36, 0x48, +0x37, 0x79, 0x55, 0x4b, 0x78, 0x7a, 0x61, 0x79, 0x6c, 0x36, 0x71, 0x53, 0x50, 0x36, 0x66, 0x37, +0x39, 0x31, 0x69, 0x7a, 0x4e, 0x5a, 0x41, 0x59, 0x55, 0x61, 0x48, 0x30, 0x58, 0x75, 0x69, 0x7a, +0x41, 0x43, 0x59, 0x66, 0x56, 0x73, 0x61, 0x35, 0x4e, 0x38, 0x54, 0x2b, 0x2f, 0x65, 0x59, 0x78, +0x58, 0x5a, 0x73, 0x2f, 0x6b, 0x6f, 0x42, 0x33, 0x65, 0x77, 0x43, 0x49, 0x49, 0x41, 0x6b, 0x58, +0x67, 0x48, 0x51, 0x59, 0x68, 0x4d, 0x6c, 0x56, 0x4e, 0x6a, 0x72, 0x74, 0x6f, 0x49, 0x6c, 0x4a, +0x5a, 0x5a, 0x74, 0x7a, 0x39, 0x44, 0x77, 0x43, 0x75, 0x76, 0x76, 0x30, 0x77, 0x33, 0x32, 0x2b, +0x4c, 0x55, 0x53, 0x48, 0x42, 0x79, 0x42, 0x36, 0x73, 0x31, 0x44, 0x42, 0x49, 0x45, 0x56, 0x68, +0x46, 0x4a, 0x71, 0x4d, 0x49, 0x73, 0x35, 0x4c, 0x4a, 0x55, 0x34, 0x2f, 0x32, 0x6b, 0x46, 0x35, +0x6e, 0x47, 0x38, 0x32, 0x34, 0x37, 0x51, 0x35, 0x58, 0x2f, 0x71, 0x4b, 0x72, 0x66, 0x58, 0x6d, +0x44, 0x73, 0x51, 0x5a, 0x74, 0x69, 0x71, 0x44, 0x41, 0x4f, 0x6a, 0x6b, 0x39, 0x46, 0x46, 0x67, +0x58, 0x51, 0x59, 0x45, 0x76, 0x6d, 0x75, 0x48, 0x4b, 0x58, 0x31, 0x31, 0x55, 0x33, 0x68, 0x67, +0x71, 0x71, 0x6a, 0x54, 0x55, 0x4f, 0x56, 0x55, 0x70, 0x73, 0x49, 0x6f, 0x4d, 0x69, 0x72, 0x42, +0x57, 0x59, 0x69, 0x66, 0x33, 0x68, 0x33, 0x4c, 0x36, 0x46, 0x77, 0x44, 0x2f, 0x4e, 0x79, 0x67, +0x6f, 0x51, 0x46, 0x56, 0x56, 0x6c, 0x53, 0x74, 0x66, 0x73, 0x75, 0x49, 0x42, 0x66, 0x48, 0x56, +0x6f, 0x61, 0x66, 0x58, 0x71, 0x31, 0x51, 0x44, 0x55, 0x31, 0x74, 0x59, 0x57, 0x79, 0x68, 0x31, +0x2f, 0x48, 0x4d, 0x47, 0x2b, 0x4b, 0x2b, 0x43, 0x33, 0x44, 0x33, 0x68, 0x30, 0x58, 0x36, 0x45, +0x4e, 0x51, 0x54, 0x37, 0x66, 0x72, 0x2f, 0x36, 0x74, 0x50, 0x2f, 0x34, 0x57, 0x6e, 0x35, 0x36, +0x34, 0x68, 0x43, 0x30, 0x6a, 0x52, 0x65, 0x38, 0x37, 0x37, 0x39, 0x44, 0x39, 0x30, 0x6b, 0x74, +0x6b, 0x6d, 0x70, 0x70, 0x41, 0x61, 0x31, 0x52, 0x58, 0x6c, 0x79, 0x4f, 0x30, 0x69, 0x67, 0x71, +0x73, 0x31, 0x73, 0x6a, 0x6c, 0x79, 0x36, 0x6b, 0x2b, 0x35, 0x46, 0x43, 0x71, 0x44, 0x2f, 0x6f, +0x6d, 0x31, 0x6c, 0x6f, 0x71, 0x70, 0x31, 0x56, 0x43, 0x42, 0x56, 0x78, 0x39, 0x6b, 0x42, 0x38, +0x2f, 0x36, 0x38, 0x59, 0x2f, 0x45, 0x79, 0x52, 0x4d, 0x31, 0x55, 0x55, 0x51, 0x2b, 0x50, 0x6b, +0x4c, 0x2f, 0x66, 0x7a, 0x62, 0x77, 0x72, 0x57, 0x37, 0x65, 0x77, 0x62, 0x6e, 0x50, 0x39, 0x76, +0x4c, 0x73, 0x77, 0x39, 0x74, 0x79, 0x79, 0x6b, 0x58, 0x48, 0x6b, 0x36, 0x30, 0x59, 0x44, 0x36, +0x32, 0x75, 0x35, 0x76, 0x76, 0x44, 0x42, 0x31, 0x47, 0x58, 0x58, 0x4d, 0x54, 0x66, 0x35, 0x75, +0x7a, 0x67, 0x54, 0x33, 0x72, 0x4d, 0x6f, 0x54, 0x4b, 0x6d, 0x54, 0x59, 0x4a, 0x47, 0x43, 0x56, +0x70, 0x2f, 0x2b, 0x77, 0x5a, 0x4d, 0x36, 0x6a, 0x61, 0x33, 0x49, 0x32, 0x50, 0x37, 0x76, 0x6f, +0x39, 0x71, 0x48, 0x55, 0x59, 0x73, 0x78, 0x47, 0x4d, 0x78, 0x6c, 0x72, 0x6a, 0x7a, 0x4a, 0x67, +0x67, 0x38, 0x58, 0x64, 0x34, 0x6b, 0x38, 0x5a, 0x4b, 0x6a, 0x46, 0x65, 0x54, 0x32, 0x2b, 0x59, +0x2b, 0x35, 0x70, 0x70, 0x35, 0x30, 0x2b, 0x31, 0x2b, 0x2f, 0x69, 0x79, 0x42, 0x30, 0x57, 0x43, +0x4d, 0x51, 0x30, 0x52, 0x71, 0x54, 0x57, 0x42, 0x63, 0x61, 0x44, 0x5a, 0x55, 0x73, 0x73, 0x69, +0x70, 0x70, 0x37, 0x46, 0x61, 0x30, 0x6a, 0x33, 0x74, 0x4e, 0x67, 0x43, 0x75, 0x4f, 0x2f, 0x6b, +0x36, 0x48, 0x39, 0x5a, 0x7a, 0x39, 0x4b, 0x4f, 0x74, 0x52, 0x68, 0x76, 0x4e, 0x58, 0x68, 0x4e, +0x37, 0x79, 0x61, 0x4a, 0x34, 0x39, 0x73, 0x4d, 0x51, 0x5a, 0x5a, 0x53, 0x6a, 0x53, 0x31, 0x57, +0x67, 0x76, 0x38, 0x64, 0x2f, 0x2f, 0x44, 0x67, 0x38, 0x39, 0x78, 0x78, 0x58, 0x48, 0x33, 0x63, +0x63, 0x37, 0x4c, 0x38, 0x2f, 0x70, 0x72, 0x49, 0x53, 0x49, 0x36, 0x58, 0x7a, 0x58, 0x64, 0x41, +0x48, 0x69, 0x67, 0x73, 0x4f, 0x30, 0x47, 0x4d, 0x4d, 0x30, 0x6c, 0x71, 0x6b, 0x74, 0x63, 0x79, +0x59, 0x50, 0x5a, 0x75, 0x73, 0x67, 0x75, 0x7a, 0x6d, 0x6e, 0x76, 0x34, 0x77, 0x59, 0x49, 0x33, +0x72, 0x76, 0x39, 0x73, 0x78, 0x67, 0x63, 0x32, 0x4e, 0x78, 0x51, 0x70, 0x46, 0x56, 0x73, 0x7a, +0x46, 0x42, 0x67, 0x71, 0x4e, 0x4a, 0x42, 0x41, 0x4b, 0x4f, 0x31, 0x50, 0x53, 0x2f, 0x61, 0x53, +0x6a, 0x76, 0x30, 0x45, 0x2f, 0x76, 0x6a, 0x71, 0x6c, 0x73, 0x56, 0x2b, 0x63, 0x50, 0x70, 0x77, +0x67, 0x43, 0x47, 0x69, 0x38, 0x39, 0x42, 0x4a, 0x6e, 0x72, 0x71, 0x59, 0x4f, 0x54, 0x59, 0x6d, +0x56, 0x37, 0x70, 0x72, 0x34, 0x75, 0x68, 0x59, 0x2f, 0x50, 0x63, 0x50, 0x37, 0x41, 0x4b, 0x7a, +0x6c, 0x30, 0x65, 0x63, 0x37, 0x6d, 0x4c, 0x73, 0x6f, 0x35, 0x6f, 0x52, 0x44, 0x44, 0x2b, 0x61, +0x50, 0x4c, 0x37, 0x5a, 0x78, 0x77, 0x71, 0x37, 0x50, 0x6b, 0x41, 0x6c, 0x69, 0x43, 0x4a, 0x7a, +0x6a, 0x77, 0x30, 0x32, 0x38, 0x77, 0x42, 0x72, 0x42, 0x50, 0x7a, 0x2b, 0x50, 0x61, 0x47, 0x33, +0x4a, 0x55, 0x5a, 0x44, 0x6a, 0x6c, 0x68, 0x56, 0x72, 0x65, 0x39, 0x48, 0x61, 0x6f, 0x6b, 0x57, +0x41, 0x46, 0x55, 0x76, 0x42, 0x36, 0x6b, 0x4b, 0x35, 0x51, 0x47, 0x4a, 0x6a, 0x79, 0x63, 0x4c, +0x6c, 0x37, 0x51, 0x67, 0x74, 0x6b, 0x56, 0x4c, 0x54, 0x32, 0x6c, 0x78, 0x4e, 0x51, 0x5a, 0x6d, +0x31, 0x72, 0x4e, 0x69, 0x34, 0x45, 0x6d, 0x33, 0x63, 0x77, 0x45, 0x39, 0x61, 0x49, 0x54, 0x6c, +0x69, 0x73, 0x57, 0x5a, 0x45, 0x75, 0x38, 0x51, 0x71, 0x79, 0x66, 0x4a, 0x79, 0x79, 0x57, 0x4f, +0x74, 0x6b, 0x6d, 0x65, 0x61, 0x68, 0x58, 0x4e, 0x75, 0x53, 0x45, 0x6c, 0x72, 0x59, 0x32, 0x74, +0x42, 0x39, 0x47, 0x46, 0x5a, 0x73, 0x57, 0x4a, 0x6c, 0x36, 0x68, 0x74, 0x77, 0x6d, 0x35, 0x42, +0x30, 0x77, 0x59, 0x4e, 0x71, 0x70, 0x58, 0x4f, 0x4b, 0x4c, 0x65, 0x77, 0x50, 0x35, 0x55, 0x7a, +0x4b, 0x2f, 0x31, 0x2b, 0x68, 0x6f, 0x41, 0x57, 0x47, 0x48, 0x77, 0x42, 0x4e, 0x39, 0x31, 0x56, +0x68, 0x54, 0x42, 0x2f, 0x48, 0x37, 0x6c, 0x66, 0x2b, 0x6b, 0x30, 0x2f, 0x68, 0x4e, 0x2f, 0x64, +0x67, 0x4e, 0x37, 0x52, 0x42, 0x73, 0x51, 0x4e, 0x4b, 0x53, 0x6b, 0x78, 0x50, 0x54, 0x37, 0x2f, +0x36, 0x31, 0x36, 0x39, 0x65, 0x79, 0x71, 0x31, 0x7a, 0x66, 0x38, 0x34, 0x52, 0x59, 0x34, 0x35, +0x6c, 0x69, 0x31, 0x31, 0x33, 0x70, 0x58, 0x4c, 0x72, 0x48, 0x66, 0x6e, 0x79, 0x32, 0x71, 0x6c, +0x59, 0x72, 0x57, 0x6b, 0x36, 0x37, 0x30, 0x4a, 0x73, 0x45, 0x4c, 0x42, 0x32, 0x2b, 0x69, 0x39, +0x51, 0x48, 0x52, 0x30, 0x4d, 0x6e, 0x33, 0x34, 0x58, 0x74, 0x6a, 0x62, 0x48, 0x70, 0x2f, 0x6c, +0x2f, 0x38, 0x71, 0x75, 0x50, 0x66, 0x67, 0x48, 0x7a, 0x67, 0x46, 0x33, 0x39, 0x2b, 0x50, 0x57, +0x73, 0x54, 0x41, 0x6d, 0x2f, 0x4c, 0x43, 0x6a, 0x44, 0x6f, 0x4c, 0x47, 0x32, 0x6f, 0x33, 0x51, +0x4d, 0x72, 0x66, 0x43, 0x6e, 0x4a, 0x41, 0x68, 0x61, 0x4d, 0x51, 0x62, 0x75, 0x4d, 0x30, 0x2f, +0x42, 0x2f, 0x49, 0x6c, 0x55, 0x76, 0x76, 0x55, 0x4b, 0x6d, 0x66, 0x59, 0x4f, 0x62, 0x44, 0x35, +0x50, 0x64, 0x6c, 0x41, 0x44, 0x65, 0x52, 0x55, 0x77, 0x71, 0x62, 0x65, 0x62, 0x65, 0x4d, 0x6c, +0x69, 0x78, 0x2f, 0x52, 0x43, 0x6f, 0x68, 0x4e, 0x48, 0x70, 0x35, 0x54, 0x6b, 0x2b, 0x6f, 0x78, +0x66, 0x57, 0x48, 0x4f, 0x79, 0x75, 0x77, 0x4a, 0x47, 0x72, 0x38, 0x56, 0x30, 0x2f, 0x49, 0x71, +0x34, 0x65, 0x79, 0x32, 0x69, 0x73, 0x35, 0x50, 0x4b, 0x51, 0x57, 0x37, 0x2f, 0x41, 0x34, 0x48, +0x45, 0x57, 0x49, 0x6b, 0x31, 0x67, 0x71, 0x42, 0x73, 0x70, 0x4e, 0x4d, 0x4d, 0x58, 0x50, 0x4f, +0x78, 0x36, 0x39, 0x65, 0x36, 0x2b, 0x55, 0x76, 0x32, 0x49, 0x71, 0x53, 0x4d, 0x72, 0x67, 0x73, +0x6f, 0x53, 0x49, 0x2b, 0x41, 0x74, 0x45, 0x6f, 0x53, 0x44, 0x47, 0x30, 0x75, 0x49, 0x43, 0x47, +0x78, 0x72, 0x4f, 0x72, 0x38, 0x45, 0x70, 0x30, 0x77, 0x75, 0x56, 0x45, 0x38, 0x65, 0x46, 0x77, +0x50, 0x31, 0x6c, 0x5a, 0x69, 0x72, 0x65, 0x54, 0x41, 0x35, 0x67, 0x30, 0x63, 0x38, 0x58, 0x41, +0x47, 0x6f, 0x53, 0x54, 0x4b, 0x51, 0x39, 0x4a, 0x48, 0x31, 0x6f, 0x38, 0x73, 0x61, 0x45, 0x36, +0x4c, 0x46, 0x37, 0x46, 0x69, 0x38, 0x57, 0x4c, 0x30, 0x38, 0x63, 0x65, 0x6a, 0x6d, 0x35, 0x71, +0x52, 0x6b, 0x66, 0x53, 0x51, 0x58, 0x42, 0x79, 0x7a, 0x47, 0x35, 0x44, 0x57, 0x49, 0x49, 0x78, +0x4e, 0x39, 0x34, 0x57, 0x30, 0x6c, 0x70, 0x65, 0x42, 0x71, 0x63, 0x46, 0x6b, 0x66, 0x51, 0x76, +0x45, 0x53, 0x72, 0x44, 0x61, 0x43, 0x7a, 0x39, 0x50, 0x76, 0x35, 0x56, 0x62, 0x59, 0x67, 0x61, +0x66, 0x53, 0x78, 0x52, 0x5a, 0x52, 0x4e, 0x52, 0x44, 0x75, 0x4f, 0x46, 0x79, 0x75, 0x6c, 0x59, +0x49, 0x6d, 0x76, 0x37, 0x34, 0x54, 0x7a, 0x4c, 0x6a, 0x57, 0x6a, 0x48, 0x4f, 0x6a, 0x2b, 0x78, +0x45, 0x78, 0x34, 0x71, 0x56, 0x41, 0x4b, 0x7a, 0x5a, 0x36, 0x42, 0x79, 0x7a, 0x61, 0x75, 0x6c, +0x53, 0x35, 0x37, 0x42, 0x4d, 0x30, 0x48, 0x39, 0x53, 0x46, 0x76, 0x62, 0x68, 0x43, 0x45, 0x6e, +0x47, 0x6a, 0x33, 0x38, 0x57, 0x6a, 0x4d, 0x4e, 0x66, 0x4b, 0x33, 0x6a, 0x76, 0x6b, 0x31, 0x36, +0x45, 0x4e, 0x4a, 0x78, 0x30, 0x78, 0x48, 0x66, 0x34, 0x77, 0x2f, 0x4f, 0x43, 0x6b, 0x2f, 0x62, +0x34, 0x4d, 0x35, 0x6c, 0x41, 0x59, 0x67, 0x4f, 0x42, 0x31, 0x63, 0x4b, 0x48, 0x49, 0x51, 0x52, +0x43, 0x75, 0x72, 0x42, 0x66, 0x6f, 0x6b, 0x67, 0x34, 0x4a, 0x4b, 0x70, 0x48, 0x4c, 0x75, 0x6b, +0x41, 0x72, 0x47, 0x62, 0x36, 0x66, 0x59, 0x4b, 0x6a, 0x39, 0x33, 0x45, 0x61, 0x77, 0x36, 0x4e, +0x2f, 0x46, 0x55, 0x77, 0x35, 0x58, 0x79, 0x43, 0x6b, 0x38, 0x31, 0x42, 0x4b, 0x35, 0x54, 0x79, +0x6a, 0x69, 0x52, 0x76, 0x65, 0x65, 0x64, 0x44, 0x64, 0x71, 0x72, 0x2f, 0x58, 0x43, 0x73, 0x6b, +0x35, 0x48, 0x32, 0x74, 0x43, 0x44, 0x30, 0x56, 0x46, 0x53, 0x44, 0x62, 0x72, 0x46, 0x6c, 0x79, +0x79, 0x52, 0x68, 0x42, 0x39, 0x51, 0x2f, 0x4c, 0x6e, 0x46, 0x70, 0x48, 0x75, 0x44, 0x55, 0x67, +0x4f, 0x59, 0x36, 0x77, 0x4c, 0x52, 0x58, 0x6c, 0x49, 0x73, 0x4c, 0x58, 0x61, 0x45, 0x36, 0x6f, +0x71, 0x4a, 0x56, 0x78, 0x52, 0x38, 0x4f, 0x6f, 0x6d, 0x59, 0x55, 0x6a, 0x6f, 0x44, 0x30, 0x56, +0x4f, 0x77, 0x43, 0x7a, 0x70, 0x69, 0x69, 0x2b, 0x45, 0x5a, 0x2f, 0x37, 0x2b, 0x35, 0x52, 0x64, +0x31, 0x4c, 0x6d, 0x4a, 0x6b, 0x4f, 0x42, 0x4a, 0x74, 0x64, 0x53, 0x6d, 0x54, 0x59, 0x7a, 0x47, +0x32, 0x34, 0x42, 0x51, 0x7a, 0x31, 0x6e, 0x67, 0x34, 0x71, 0x31, 0x74, 0x6c, 0x79, 0x38, 0x49, +0x73, 0x6e, 0x2f, 0x56, 0x2b, 0x52, 0x68, 0x4e, 0x4e, 0x70, 0x62, 0x62, 0x78, 0x4e, 0x74, 0x74, +0x67, 0x72, 0x2f, 0x73, 0x70, 0x58, 0x48, 0x38, 0x39, 0x64, 0x76, 0x48, 0x69, 0x55, 0x6a, 0x68, +0x75, 0x6b, 0x58, 0x63, 0x36, 0x71, 0x58, 0x39, 0x77, 0x58, 0x51, 0x4e, 0x31, 0x75, 0x51, 0x62, +0x75, 0x6e, 0x44, 0x4f, 0x64, 0x48, 0x59, 0x62, 0x75, 0x78, 0x4f, 0x6c, 0x6a, 0x54, 0x71, 0x50, +0x35, 0x35, 0x70, 0x75, 0x78, 0x31, 0x72, 0x4b, 0x2b, 0x62, 0x54, 0x6c, 0x43, 0x4b, 0x6f, 0x5a, +0x4e, 0x6e, 0x35, 0x36, 0x32, 0x34, 0x37, 0x59, 0x46, 0x30, 0x35, 0x6e, 0x78, 0x2b, 0x51, 0x78, +0x32, 0x48, 0x37, 0x59, 0x48, 0x4e, 0x46, 0x41, 0x36, 0x2f, 0x6c, 0x61, 0x6a, 0x6a, 0x49, 0x51, +0x41, 0x50, 0x34, 0x62, 0x39, 0x47, 0x54, 0x2b, 0x35, 0x67, 0x6f, 0x74, 0x2b, 0x50, 0x46, 0x32, +0x7a, 0x4d, 0x2b, 0x64, 0x4d, 0x6d, 0x45, 0x68, 0x75, 0x2f, 0x52, 0x66, 0x6b, 0x46, 0x79, 0x38, +0x6e, 0x61, 0x43, 0x71, 0x6e, 0x63, 0x73, 0x78, 0x49, 0x4e, 0x69, 0x78, 0x5a, 0x77, 0x32, 0x64, +0x36, 0x4d, 0x4a, 0x75, 0x4c, 0x54, 0x37, 0x46, 0x53, 0x4d, 0x50, 0x71, 0x78, 0x78, 0x79, 0x43, +0x54, 0x63, 0x65, 0x32, 0x49, 0x59, 0x35, 0x61, 0x64, 0x64, 0x52, 0x59, 0x4b, 0x75, 0x4f, 0x57, +0x6d, 0x6d, 0x37, 0x68, 0x69, 0x79, 0x70, 0x51, 0x53, 0x51, 0x52, 0x69, 0x45, 0x54, 0x59, 0x51, +0x4e, 0x31, 0x37, 0x4e, 0x38, 0x34, 0x78, 0x65, 0x55, 0x76, 0x7a, 0x32, 0x44, 0x69, 0x6b, 0x4e, +0x65, 0x67, 0x74, 0x42, 0x67, 0x64, 0x49, 0x38, 0x4c, 0x63, 0x31, 0x6c, 0x42, 0x4e, 0x6c, 0x51, +0x59, 0x42, 0x62, 0x30, 0x6e, 0x61, 0x6e, 0x49, 0x54, 0x42, 0x47, 0x5a, 0x59, 0x35, 0x44, 0x51, +0x45, 0x34, 0x35, 0x6e, 0x65, 0x68, 0x7a, 0x76, 0x52, 0x50, 0x69, 0x4b, 0x53, 0x68, 0x4d, 0x44, +0x38, 0x66, 0x56, 0x6a, 0x58, 0x53, 0x2b, 0x65, 0x6f, 0x51, 0x70, 0x33, 0x61, 0x4f, 0x49, 0x66, +0x5a, 0x59, 0x64, 0x76, 0x30, 0x38, 0x4f, 0x33, 0x68, 0x6d, 0x71, 0x6c, 0x54, 0x62, 0x2b, 0x63, +0x6a, 0x30, 0x34, 0x78, 0x55, 0x6c, 0x6e, 0x48, 0x52, 0x61, 0x70, 0x36, 0x5a, 0x64, 0x6a, 0x79, +0x50, 0x66, 0x43, 0x47, 0x35, 0x61, 0x31, 0x62, 0x47, 0x61, 0x61, 0x46, 0x4b, 0x70, 0x75, 0x75, +0x58, 0x4d, 0x52, 0x62, 0x39, 0x78, 0x58, 0x4c, 0x55, 0x2f, 0x66, 0x64, 0x7a, 0x77, 0x54, 0x36, +0x72, 0x32, 0x58, 0x4e, 0x37, 0x6a, 0x54, 0x57, 0x69, 0x45, 0x4a, 0x6b, 0x78, 0x66, 0x76, 0x7a, +0x53, 0x65, 0x30, 0x6c, 0x67, 0x4e, 0x71, 0x4d, 0x6a, 0x65, 0x69, 0x6b, 0x56, 0x51, 0x43, 0x58, +0x4d, 0x62, 0x7a, 0x51, 0x32, 0x4a, 0x37, 0x43, 0x64, 0x48, 0x39, 0x43, 0x65, 0x36, 0x34, 0x4a, +0x4d, 0x4a, 0x57, 0x56, 0x47, 0x59, 0x49, 0x5a, 0x4d, 0x5a, 0x2b, 0x4e, 0x64, 0x78, 0x7a, 0x43, +0x30, 0x51, 0x57, 0x44, 0x4c, 0x4a, 0x53, 0x5a, 0x68, 0x41, 0x57, 0x32, 0x64, 0x78, 0x6f, 0x72, +0x33, 0x6e, 0x51, 0x42, 0x57, 0x43, 0x62, 0x66, 0x69, 0x4a, 0x37, 0x51, 0x6a, 0x68, 0x52, 0x66, +0x45, 0x37, 0x68, 0x72, 0x36, 0x4b, 0x46, 0x77, 0x57, 0x53, 0x44, 0x33, 0x55, 0x53, 0x6c, 0x76, +0x65, 0x6d, 0x64, 0x4f, 0x4c, 0x45, 0x49, 0x5a, 0x54, 0x6a, 0x6a, 0x71, 0x5a, 0x42, 0x32, 0x62, +0x45, 0x6e, 0x4c, 0x37, 0x33, 0x34, 0x34, 0x53, 0x42, 0x53, 0x42, 0x74, 0x75, 0x74, 0x55, 0x42, +0x49, 0x6a, 0x30, 0x52, 0x43, 0x4f, 0x5a, 0x73, 0x2f, 0x59, 0x58, 0x35, 0x6c, 0x55, 0x43, 0x72, +0x41, 0x57, 0x6f, 0x47, 0x53, 0x6b, 0x71, 0x64, 0x65, 0x6c, 0x6d, 0x67, 0x74, 0x55, 0x56, 0x4c, +0x34, 0x63, 0x68, 0x71, 0x68, 0x64, 0x61, 0x6b, 0x41, 0x55, 0x4b, 0x43, 0x74, 0x54, 0x6c, 0x58, +0x39, 0x33, 0x56, 0x63, 0x6f, 0x51, 0x74, 0x46, 0x2f, 0x35, 0x51, 0x32, 0x46, 0x34, 0x49, 0x41, +0x6c, 0x6b, 0x73, 0x65, 0x61, 0x33, 0x47, 0x61, 0x67, 0x59, 0x67, 0x47, 0x51, 0x78, 0x4b, 0x47, +0x56, 0x55, 0x69, 0x69, 0x70, 0x4b, 0x46, 0x32, 0x31, 0x4e, 0x69, 0x30, 0x41, 0x63, 0x50, 0x54, +0x66, 0x48, 0x34, 0x71, 0x73, 0x58, 0x50, 0x67, 0x73, 0x66, 0x37, 0x47, 0x37, 0x6c, 0x74, 0x2f, +0x6f, 0x4e, 0x78, 0x62, 0x4a, 0x2f, 0x75, 0x57, 0x33, 0x75, 0x32, 0x38, 0x37, 0x72, 0x76, 0x7a, +0x6d, 0x6c, 0x53, 0x7a, 0x76, 0x57, 0x75, 0x35, 0x33, 0x4c, 0x53, 0x6f, 0x6e, 0x6f, 0x4e, 0x49, +0x4e, 0x54, 0x42, 0x4b, 0x70, 0x76, 0x65, 0x5a, 0x69, 0x4a, 0x45, 0x4b, 0x35, 0x36, 0x36, 0x6a, +0x61, 0x55, 0x63, 0x79, 0x36, 0x66, 0x52, 0x62, 0x74, 0x7a, 0x78, 0x54, 0x74, 0x5a, 0x51, 0x58, +0x73, 0x4a, 0x35, 0x2f, 0x41, 0x7a, 0x33, 0x2b, 0x42, 0x62, 0x64, 0x38, 0x34, 0x73, 0x50, 0x62, +0x52, 0x70, 0x2f, 0x37, 0x45, 0x49, 0x54, 0x65, 0x73, 0x70, 0x6f, 0x56, 0x35, 0x36, 0x2b, 0x64, +0x79, 0x33, 0x75, 0x70, 0x7a, 0x75, 0x58, 0x48, 0x33, 0x36, 0x64, 0x54, 0x5a, 0x63, 0x73, 0x79, +0x36, 0x6a, 0x51, 0x52, 0x4b, 0x59, 0x42, 0x73, 0x33, 0x6f, 0x39, 0x73, 0x4b, 0x54, 0x6e, 0x6e, +0x31, 0x32, 0x77, 0x51, 0x6d, 0x77, 0x2b, 0x69, 0x47, 0x4d, 0x64, 0x6a, 0x41, 0x70, 0x69, 0x75, +0x59, 0x78, 0x6e, 0x6d, 0x49, 0x6c, 0x66, 0x63, 0x69, 0x45, 0x2b, 0x49, 0x59, 0x71, 0x59, 0x54, +0x70, 0x2b, 0x77, 0x73, 0x41, 0x67, 0x46, 0x55, 0x48, 0x6e, 0x49, 0x43, 0x6f, 0x71, 0x4f, 0x46, +0x33, 0x79, 0x2b, 0x72, 0x5a, 0x49, 0x68, 0x68, 0x4b, 0x4b, 0x43, 0x78, 0x7a, 0x65, 0x7a, 0x66, +0x6e, 0x67, 0x43, 0x32, 0x47, 0x73, 0x4f, 0x47, 0x64, 0x70, 0x57, 0x67, 0x68, 0x43, 0x61, 0x54, +0x62, 0x6c, 0x50, 0x57, 0x6a, 0x56, 0x65, 0x55, 0x6f, 0x59, 0x35, 0x6b, 0x32, 0x4c, 0x4d, 0x5a, +0x36, 0x41, 0x70, 0x78, 0x79, 0x31, 0x56, 0x56, 0x73, 0x32, 0x4c, 0x69, 0x52, 0x64, 0x65, 0x76, +0x57, 0x63, 0x65, 0x61, 0x35, 0x35, 0x7a, 0x4a, 0x73, 0x36, 0x46, 0x44, 0x47, 0x74, 0x72, 0x61, +0x69, 0x38, 0x33, 0x6c, 0x71, 0x6e, 0x72, 0x77, 0x48, 0x4a, 0x51, 0x51, 0x62, 0x39, 0x52, 0x50, +0x55, 0x74, 0x56, 0x69, 0x79, 0x31, 0x6d, 0x4c, 0x56, 0x4d, 0x75, 0x53, 0x36, 0x71, 0x37, 0x41, +0x59, 0x52, 0x41, 0x54, 0x64, 0x5a, 0x30, 0x4c, 0x74, 0x69, 0x41, 0x67, 0x74, 0x65, 0x37, 0x42, +0x57, 0x4f, 0x63, 0x33, 0x54, 0x6d, 0x77, 0x72, 0x57, 0x4a, 0x4f, 0x5a, 0x43, 0x63, 0x69, 0x39, +0x54, 0x4a, 0x67, 0x7a, 0x4c, 0x61, 0x6d, 0x6d, 0x2f, 0x41, 0x58, 0x67, 0x46, 0x70, 0x39, 0x36, +0x48, 0x50, 0x64, 0x78, 0x37, 0x74, 0x43, 0x4a, 0x6a, 0x46, 0x52, 0x39, 0x39, 0x63, 0x41, 0x4c, +0x2f, 0x66, 0x58, 0x34, 0x7a, 0x35, 0x31, 0x62, 0x45, 0x2f, 0x47, 0x4e, 0x78, 0x6e, 0x6c, 0x73, +0x65, 0x48, 0x38, 0x6f, 0x56, 0x4e, 0x31, 0x7a, 0x4f, 0x7a, 0x64, 0x64, 0x66, 0x78, 0x33, 0x66, +0x47, 0x43, 0x58, 0x61, 0x35, 0x75, 0x38, 0x7a, 0x68, 0x53, 0x4a, 0x4c, 0x78, 0x53, 0x2b, 0x68, +0x76, 0x39, 0x57, 0x6f, 0x65, 0x2b, 0x4c, 0x4d, 0x69, 0x51, 0x4c, 0x4c, 0x62, 0x74, 0x6b, 0x58, +0x78, 0x65, 0x31, 0x50, 0x45, 0x50, 0x30, 0x5a, 0x34, 0x44, 0x37, 0x2b, 0x6e, 0x58, 0x77, 0x4d, +0x59, 0x54, 0x52, 0x4c, 0x4b, 0x78, 0x53, 0x70, 0x73, 0x4b, 0x4f, 0x6e, 0x74, 0x43, 0x75, 0x6d, +0x53, 0x77, 0x38, 0x6c, 0x30, 0x76, 0x45, 0x78, 0x58, 0x2b, 0x63, 0x46, 0x38, 0x2f, 0x74, 0x7a, +0x64, 0x4e, 0x4f, 0x31, 0x33, 0x42, 0x6b, 0x31, 0x6e, 0x58, 0x6f, 0x2f, 0x39, 0x39, 0x57, 0x6e, +0x67, 0x36, 0x58, 0x2b, 0x6b, 0x31, 0x67, 0x52, 0x42, 0x6b, 0x41, 0x6f, 0x79, 0x70, 0x5a, 0x32, +0x67, 0x62, 0x33, 0x6a, 0x79, 0x36, 0x61, 0x2f, 0x56, 0x51, 0x4c, 0x66, 0x73, 0x37, 0x48, 0x51, +0x61, 0x51, 0x49, 0x6f, 0x79, 0x55, 0x68, 0x59, 0x6c, 0x44, 0x57, 0x39, 0x2b, 0x30, 0x45, 0x4d, +0x55, 0x61, 0x38, 0x34, 0x38, 0x39, 0x6e, 0x54, 0x75, 0x65, 0x53, 0x72, 0x6d, 0x7a, 0x48, 0x30, +0x65, 0x6f, 0x61, 0x79, 0x73, 0x49, 0x4d, 0x6d, 0x45, 0x30, 0x43, 0x69, 0x56, 0x54, 0x54, 0x55, +0x41, 0x46, 0x36, 0x50, 0x55, 0x76, 0x6a, 0x78, 0x59, 0x49, 0x39, 0x6c, 0x68, 0x76, 0x4f, 0x43, +0x64, 0x75, 0x55, 0x34, 0x41, 0x37, 0x44, 0x44, 0x42, 0x62, 0x36, 0x51, 0x52, 0x47, 0x6d, 0x46, +0x30, 0x43, 0x6c, 0x56, 0x4e, 0x4e, 0x41, 0x43, 0x6c, 0x4e, 0x56, 0x4b, 0x37, 0x30, 0x4e, 0x79, +0x57, 0x61, 0x31, 0x55, 0x4a, 0x6f, 0x78, 0x58, 0x66, 0x62, 0x2f, 0x65, 0x6c, 0x63, 0x41, 0x79, +0x6b, 0x5a, 0x47, 0x45, 0x6e, 0x47, 0x6e, 0x67, 0x63, 0x67, 0x75, 0x77, 0x6a, 0x41, 0x45, 0x53, +0x70, 0x41, 0x44, 0x43, 0x6c, 0x38, 0x56, 0x31, 0x38, 0x47, 0x50, 0x49, 0x44, 0x6f, 0x4c, 0x56, +0x53, 0x49, 0x32, 0x6f, 0x53, 0x32, 0x39, 0x54, 0x62, 0x71, 0x54, 0x63, 0x4b, 0x61, 0x68, 0x73, +0x64, 0x6f, 0x58, 0x2f, 0x35, 0x4f, 0x30, 0x48, 0x5a, 0x61, 0x58, 0x34, 0x54, 0x54, 0x70, 0x6b, +0x54, 0x4a, 0x47, 0x56, 0x56, 0x69, 0x6f, 0x2b, 0x54, 0x2b, 0x71, 0x33, 0x62, 0x75, 0x61, 0x69, +0x73, 0x32, 0x37, 0x34, 0x73, 0x6a, 0x58, 0x53, 0x37, 0x46, 0x6f, 0x31, 0x45, 0x57, 0x6f, 0x6d, +0x77, 0x41, 0x6d, 0x45, 0x6c, 0x30, 0x67, 0x69, 0x45, 0x64, 0x63, 0x2b, 0x56, 0x4c, 0x66, 0x58, +0x38, 0x70, 0x47, 0x62, 0x44, 0x31, 0x6c, 0x76, 0x44, 0x72, 0x32, 0x37, 0x44, 0x54, 0x72, 0x30, +0x4b, 0x2b, 0x39, 0x6e, 0x43, 0x30, 0x6a, 0x45, 0x59, 0x6f, 0x50, 0x32, 0x39, 0x4a, 0x6b, 0x4a, +0x62, 0x6a, 0x62, 0x47, 0x61, 0x71, 0x6f, 0x70, 0x71, 0x4e, 0x72, 0x53, 0x76, 0x5a, 0x32, 0x48, +0x48, 0x66, 0x48, 0x59, 0x4d, 0x4a, 0x74, 0x49, 0x34, 0x66, 0x6d, 0x73, 0x33, 0x34, 0x5a, 0x31, +0x35, 0x46, 0x72, 0x4f, 0x59, 0x6a, 0x6e, 0x77, 0x58, 0x6f, 0x77, 0x61, 0x50, 0x51, 0x69, 0x72, +0x50, 0x36, 0x46, 0x36, 0x47, 0x4b, 0x31, 0x4d, 0x59, 0x66, 0x32, 0x56, 0x38, 0x62, 0x46, 0x38, +0x70, 0x37, 0x4c, 0x64, 0x45, 0x30, 0x51, 0x70, 0x53, 0x70, 0x41, 0x6c, 0x4a, 0x43, 0x61, 0x4d, +0x56, 0x35, 0x6b, 0x57, 0x34, 0x66, 0x4d, 0x53, 0x6c, 0x72, 0x47, 0x69, 0x36, 0x69, 0x6d, 0x44, +0x2b, 0x4f, 0x75, 0x72, 0x72, 0x65, 0x37, 0x42, 0x4b, 0x45, 0x72, 0x30, 0x2b, 0x68, 0x79, 0x56, +0x6a, 0x6d, 0x6a, 0x69, 0x30, 0x75, 0x70, 0x30, 0x4e, 0x4d, 0x6e, 0x62, 0x34, 0x42, 0x61, 0x31, +0x35, 0x38, 0x34, 0x4c, 0x44, 0x4f, 0x66, 0x76, 0x6b, 0x79, 0x5a, 0x67, 0x6a, 0x6a, 0x30, 0x52, +0x37, 0x4b, 0x48, 0x55, 0x79, 0x66, 0x35, 0x32, 0x64, 0x6e, 0x66, 0x78, 0x69, 0x32, 0x6a, 0x53, +0x55, 0x56, 0x4e, 0x79, 0x38, 0x35, 0x35, 0x5a, 0x6b, 0x4d, 0x6c, 0x6b, 0x36, 0x44, 0x7a, 0x2b, +0x4a, 0x38, 0x59, 0x32, 0x44, 0x36, 0x50, 0x7a, 0x44, 0x4e, 0x61, 0x77, 0x54, 0x4d, 0x63, 0x32, +0x58, 0x2f, 0x67, 0x77, 0x62, 0x74, 0x70, 0x49, 0x5a, 0x2b, 0x6a, 0x42, 0x42, 0x47, 0x46, 0x4b, +0x33, 0x54, 0x7a, 0x75, 0x73, 0x48, 0x75, 0x47, 0x46, 0x6c, 0x57, 0x63, 0x67, 0x76, 0x34, 0x71, +0x61, 0x59, 0x6a, 0x43, 0x4e, 0x55, 0x52, 0x69, 0x53, 0x46, 0x56, 0x68, 0x69, 0x6a, 0x43, 0x49, +0x30, 0x4b, 0x6e, 0x57, 0x30, 0x44, 0x61, 0x2b, 0x50, 0x2b, 0x4f, 0x6b, 0x42, 0x33, 0x72, 0x65, +0x42, 0x59, 0x76, 0x6f, 0x4c, 0x42, 0x37, 0x4b, 0x69, 0x78, 0x37, 0x4c, 0x54, 0x32, 0x44, 0x4a, +0x32, 0x32, 0x64, 0x78, 0x79, 0x2f, 0x64, 0x6d, 0x57, 0x4e, 0x39, 0x2f, 0x64, 0x4c, 0x68, 0x57, +0x45, 0x37, 0x33, 0x79, 0x76, 0x68, 0x2b, 0x76, 0x66, 0x47, 0x4d, 0x51, 0x4c, 0x50, 0x66, 0x33, +0x70, 0x62, 0x30, 0x32, 0x76, 0x34, 0x73, 0x62, 0x66, 0x53, 0x6e, 0x35, 0x31, 0x75, 0x61, 0x42, +0x31, 0x70, 0x4a, 0x38, 0x37, 0x49, 0x2f, 0x70, 0x70, 0x41, 0x6d, 0x69, 0x56, 0x4f, 0x6a, 0x64, +0x4a, 0x74, 0x53, 0x33, 0x6e, 0x38, 0x37, 0x43, 0x52, 0x5a, 0x45, 0x58, 0x31, 0x48, 0x30, 0x48, +0x6b, 0x79, 0x5a, 0x52, 0x5a, 0x73, 0x68, 0x6e, 0x4c, 0x4e, 0x6b, 0x65, 0x65, 0x41, 0x34, 0x54, +0x55, 0x33, 0x6e, 0x38, 0x71, 0x74, 0x6c, 0x4b, 0x43, 0x64, 0x50, 0x4f, 0x66, 0x4f, 0x2b, 0x46, +0x6a, 0x70, 0x6e, 0x39, 0x33, 0x42, 0x4b, 0x73, 0x33, 0x53, 0x6f, 0x65, 0x54, 0x55, 0x4a, 0x62, +0x4c, 0x48, 0x67, 0x62, 0x68, 0x54, 0x64, 0x41, 0x41, 0x41, 0x43, 0x41, 0x41, 0x53, 0x55, 0x52, +0x42, 0x56, 0x46, 0x78, 0x5a, 0x41, 0x6b, 0x69, 0x54, 0x71, 0x72, 0x43, 0x5a, 0x53, 0x43, 0x6e, +0x33, 0x66, 0x50, 0x69, 0x67, 0x4d, 0x75, 0x36, 0x39, 0x38, 0x44, 0x30, 0x6e, 0x41, 0x4c, 0x53, +0x32, 0x4b, 0x4f, 0x6d, 0x51, 0x61, 0x77, 0x6d, 0x4d, 0x39, 0x4f, 0x2f, 0x76, 0x39, 0x5a, 0x43, +0x50, 0x4e, 0x65, 0x65, 0x65, 0x63, 0x42, 0x5a, 0x33, 0x50, 0x78, 0x35, 0x7a, 0x77, 0x54, 0x63, +0x66, 0x49, 0x41, 0x69, 0x64, 0x4a, 0x42, 0x4d, 0x71, 0x30, 0x51, 0x44, 0x63, 0x43, 0x47, 0x71, +0x50, 0x4d, 0x78, 0x64, 0x46, 0x47, 0x73, 0x42, 0x2b, 0x65, 0x77, 0x68, 0x65, 0x2f, 0x31, 0x44, +0x53, 0x6d, 0x78, 0x63, 0x63, 0x75, 0x72, 0x64, 0x6a, 0x51, 0x69, 0x45, 0x4c, 0x41, 0x69, 0x44, +0x56, 0x49, 0x41, 0x53, 0x70, 0x2b, 0x69, 0x57, 0x55, 0x34, 0x4e, 0x4d, 0x61, 0x78, 0x59, 0x35, +0x64, 0x79, 0x59, 0x70, 0x58, 0x4a, 0x41, 0x69, 0x45, 0x34, 0x50, 0x33, 0x42, 0x68, 0x52, 0x57, +0x30, 0x56, 0x41, 0x4e, 0x51, 0x48, 0x73, 0x6f, 0x71, 0x42, 0x68, 0x41, 0x41, 0x52, 0x64, 0x65, +0x69, 0x39, 0x77, 0x56, 0x65, 0x68, 0x64, 0x37, 0x6c, 0x78, 0x33, 0x44, 0x78, 0x49, 0x59, 0x71, +0x6c, 0x58, 0x51, 0x70, 0x68, 0x68, 0x49, 0x2b, 0x68, 0x53, 0x75, 0x52, 0x38, 0x77, 0x66, 0x32, +0x37, 0x75, 0x48, 0x4c, 0x48, 0x76, 0x53, 0x38, 0x52, 0x35, 0x2f, 0x73, 0x56, 0x58, 0x4c, 0x72, +0x72, 0x32, 0x44, 0x72, 0x4a, 0x75, 0x79, 0x75, 0x41, 0x45, 0x48, 0x53, 0x6f, 0x55, 0x4b, 0x46, +0x43, 0x57, 0x49, 0x45, 0x4b, 0x46, 0x44, 0x4b, 0x51, 0x53, 0x41, 0x51, 0x69, 0x6b, 0x41, 0x67, +0x45, 0x2f, 0x68, 0x4d, 0x79, 0x64, 0x4d, 0x4a, 0x41, 0x57, 0x6f, 0x6b, 0x4d, 0x5a, 0x59, 0x72, +0x43, 0x4b, 0x45, 0x45, 0x34, 0x76, 0x76, 0x38, 0x65, 0x33, 0x50, 0x4a, 0x7a, 0x62, 0x46, 0x76, +0x62, 0x67, 0x47, 0x50, 0x51, 0x74, 0x2f, 0x32, 0x72, 0x4b, 0x78, 0x54, 0x47, 0x75, 0x68, 0x57, +0x38, 0x76, 0x61, 0x65, 0x64, 0x76, 0x4d, 0x6b, 0x7a, 0x72, 0x6e, 0x59, 0x37, 0x6c, 0x76, 0x37, +0x75, 0x62, 0x6d, 0x72, 0x33, 0x32, 0x51, 0x64, 0x79, 0x46, 0x57, 0x78, 0x34, 0x36, 0x67, 0x6e, +0x47, 0x6e, 0x48, 0x63, 0x5a, 0x4f, 0x69, 0x74, 0x59, 0x31, 0x37, 0x36, 0x4f, 0x6d, 0x71, 0x6f, +0x61, 0x74, 0x4e, 0x46, 0x51, 0x6b, 0x79, 0x68, 0x78, 0x66, 0x76, 0x78, 0x39, 0x2f, 0x30, 0x33, +0x6f, 0x34, 0x73, 0x31, 0x32, 0x34, 0x77, 0x43, 0x41, 0x6d, 0x4b, 0x54, 0x2b, 0x42, 0x6c, 0x66, +0x2f, 0x30, 0x70, 0x58, 0x72, 0x32, 0x4c, 0x4a, 0x72, 0x47, 0x63, 0x31, 0x71, 0x4b, 0x58, 0x71, +0x31, 0x77, 0x79, 0x38, 0x63, 0x4c, 0x53, 0x58, 0x6d, 0x55, 0x38, 0x45, 0x47, 0x76, 0x33, 0x50, +0x52, 0x53, 0x73, 0x6c, 0x64, 0x58, 0x39, 0x37, 0x4e, 0x51, 0x54, 0x66, 0x74, 0x78, 0x47, 0x4c, +0x39, 0x43, 0x64, 0x4e, 0x58, 0x4c, 0x75, 0x51, 0x59, 0x72, 0x77, 0x46, 0x30, 0x7a, 0x59, 0x65, +0x67, 0x6f, 0x59, 0x78, 0x46, 0x43, 0x37, 0x4e, 0x63, 0x64, 0x56, 0x4d, 0x76, 0x53, 0x69, 0x6f, +0x75, 0x66, 0x47, 0x6b, 0x65, 0x64, 0x2b, 0x34, 0x37, 0x6a, 0x69, 0x6c, 0x6e, 0x6e, 0x55, 0x57, +0x56, 0x6b, 0x4e, 0x78, 0x38, 0x79, 0x48, 0x5a, 0x73, 0x50, 0x50, 0x59, 0x38, 0x31, 0x69, 0x35, +0x5a, 0x77, 0x74, 0x61, 0x6a, 0x52, 0x31, 0x4d, 0x4d, 0x42, 0x54, 0x59, 0x4b, 0x72, 0x48, 0x64, +0x51, 0x59, 0x39, 0x7a, 0x56, 0x46, 0x47, 0x6b, 0x41, 0x36, 0x63, 0x71, 0x66, 0x61, 0x41, 0x46, +0x65, 0x49, 0x46, 0x69, 0x30, 0x63, 0x39, 0x51, 0x4c, 0x57, 0x4e, 0x6f, 0x57, 0x63, 0x73, 0x35, +0x7a, 0x69, 0x6c, 0x38, 0x66, 0x4c, 0x73, 0x41, 0x71, 0x64, 0x68, 0x72, 0x30, 0x4c, 0x70, 0x39, +0x33, 0x48, 0x4d, 0x79, 0x63, 0x4a, 0x5a, 0x61, 0x58, 0x35, 0x6d, 0x53, 0x5a, 0x2b, 0x6d, 0x33, +0x4c, 0x64, 0x72, 0x56, 0x76, 0x70, 0x77, 0x4c, 0x67, 0x6d, 0x37, 0x2b, 0x58, 0x32, 0x43, 0x34, +0x4a, 0x39, 0x55, 0x42, 0x48, 0x4b, 0x66, 0x33, 0x56, 0x68, 0x49, 0x71, 0x7a, 0x6a, 0x35, 0x65, +0x30, 0x74, 0x76, 0x69, 0x35, 0x4b, 0x32, 0x48, 0x2b, 0x77, 0x75, 0x66, 0x41, 0x79, 0x44, 0x52, +0x45, 0x6d, 0x79, 0x49, 0x34, 0x41, 0x77, 0x45, 0x5a, 0x78, 0x59, 0x5a, 0x42, 0x56, 0x32, 0x4c, +0x79, 0x45, 0x63, 0x4e, 0x79, 0x37, 0x65, 0x68, 0x49, 0x30, 0x70, 0x61, 0x76, 0x70, 0x46, 0x61, +0x75, 0x52, 0x54, 0x31, 0x2f, 0x48, 0x62, 0x5a, 0x64, 0x59, 0x4b, 0x73, 0x6c, 0x67, 0x58, 0x62, +0x6a, 0x4c, 0x78, 0x37, 0x66, 0x74, 0x6b, 0x42, 0x44, 0x57, 0x43, 0x37, 0x2f, 0x33, 0x53, 0x70, +0x2b, 0x66, 0x6d, 0x72, 0x4c, 0x56, 0x36, 0x37, 0x2b, 0x31, 0x6c, 0x72, 0x43, 0x4d, 0x4f, 0x51, +0x6e, 0x52, 0x2b, 0x2f, 0x6a, 0x42, 0x49, 0x44, 0x30, 0x73, 0x46, 0x58, 0x6c, 0x56, 0x58, 0x73, +0x68, 0x44, 0x55, 0x4a, 0x61, 0x58, 0x6e, 0x32, 0x37, 0x68, 0x79, 0x6a, 0x53, 0x58, 0x48, 0x6a, +0x53, 0x65, 0x64, 0x7a, 0x36, 0x53, 0x4d, 0x52, 0x6c, 0x68, 0x39, 0x2b, 0x4c, 0x74, 0x52, 0x49, +0x6c, 0x44, 0x56, 0x70, 0x5a, 0x6b, 0x6f, 0x43, 0x4f, 0x4b, 0x36, 0x2f, 0x39, 0x5a, 0x70, 0x50, +0x41, 0x64, 0x54, 0x49, 0x6a, 0x61, 0x4b, 0x69, 0x52, 0x52, 0x4a, 0x48, 0x45, 0x6c, 0x69, 0x56, +0x62, 0x61, 0x54, 0x58, 0x53, 0x75, 0x73, 0x30, 0x6f, 0x57, 0x6e, 0x73, 0x54, 0x51, 0x4f, 0x42, +0x55, 0x5a, 0x65, 0x57, 0x49, 0x37, 0x2b, 0x55, 0x6d, 0x77, 0x62, 0x5a, 0x66, 0x53, 0x4d, 0x4a, +0x45, 0x35, 0x66, 0x5a, 0x45, 0x70, 0x35, 0x52, 0x6b, 0x78, 0x6e, 0x43, 0x2f, 0x65, 0x69, 0x71, +0x46, 0x31, 0x67, 0x55, 0x4e, 0x49, 0x45, 0x45, 0x4d, 0x4a, 0x70, 0x75, 0x43, 0x42, 0x74, 0x51, +0x41, 0x72, 0x43, 0x78, 0x5a, 0x50, 0x61, 0x31, 0x53, 0x72, 0x41, 0x43, 0x49, 0x66, 0x50, 0x31, +0x53, 0x4f, 0x50, 0x56, 0x64, 0x43, 0x36, 0x65, 0x32, 0x47, 0x38, 0x46, 0x33, 0x58, 0x6e, 0x61, +0x43, 0x52, 0x75, 0x47, 0x30, 0x44, 0x71, 0x46, 0x46, 0x75, 0x6c, 0x4a, 0x71, 0x37, 0x56, 0x66, +0x51, 0x4e, 0x32, 0x44, 0x55, 0x56, 0x70, 0x4b, 0x79, 0x44, 0x61, 0x37, 0x39, 0x53, 0x67, 0x6b, +0x66, 0x73, 0x66, 0x43, 0x6f, 0x52, 0x53, 0x32, 0x52, 0x79, 0x74, 0x31, 0x4c, 0x4c, 0x56, 0x43, +0x2b, 0x2f, 0x53, 0x4f, 0x48, 0x4b, 0x4e, 0x36, 0x64, 0x52, 0x51, 0x6c, 0x34, 0x42, 0x6f, 0x41, +0x64, 0x64, 0x38, 0x4c, 0x65, 0x64, 0x68, 0x76, 0x32, 0x69, 0x73, 0x75, 0x78, 0x69, 0x35, 0x66, +0x30, 0x31, 0x77, 0x43, 0x4b, 0x32, 0x75, 0x38, 0x38, 0x7a, 0x51, 0x34, 0x42, 0x74, 0x6d, 0x7a, +0x6a, 0x4d, 0x69, 0x59, 0x32, 0x54, 0x75, 0x54, 0x57, 0x58, 0x57, 0x37, 0x46, 0x57, 0x6b, 0x76, +0x74, 0x71, 0x64, 0x39, 0x4c, 0x33, 0x31, 0x74, 0x33, 0x33, 0x6d, 0x56, 0x59, 0x61, 0x33, 0x6e, +0x70, 0x67, 0x46, 0x66, 0x35, 0x34, 0x51, 0x64, 0x54, 0x65, 0x48, 0x6e, 0x46, 0x79, 0x77, 0x78, +0x70, 0x61, 0x55, 0x77, 0x31, 0x41, 0x47, 0x6c, 0x64, 0x33, 0x35, 0x4c, 0x2b, 0x57, 0x32, 0x75, +0x64, 0x74, 0x33, 0x77, 0x54, 0x7a, 0x46, 0x39, 0x63, 0x66, 0x77, 0x67, 0x4f, 0x50, 0x65, 0x6d, +0x7a, 0x45, 0x43, 0x55, 0x32, 0x70, 0x68, 0x47, 0x46, 0x78, 0x43, 0x56, 0x47, 0x43, 0x41, 0x36, +0x63, 0x2f, 0x43, 0x54, 0x50, 0x2f, 0x65, 0x34, 0x49, 0x6c, 0x46, 0x45, 0x63, 0x63, 0x74, 0x7a, +0x6a, 0x32, 0x4c, 0x46, 0x6a, 0x50, 0x51, 0x67, 0x4c, 0x4b, 0x6e, 0x4b, 0x61, 0x4c, 0x54, 0x59, +0x33, 0x2f, 0x50, 0x6e, 0x68, 0x4c, 0x48, 0x47, 0x58, 0x35, 0x63, 0x76, 0x6c, 0x68, 0x6f, 0x37, +0x31, 0x43, 0x37, 0x6e, 0x66, 0x37, 0x67, 0x4a, 0x52, 0x4e, 0x31, 0x63, 0x38, 0x4d, 0x35, 0x39, +0x2f, 0x50, 0x50, 0x61, 0x64, 0x46, 0x42, 0x57, 0x36, 0x30, 0x77, 0x34, 0x37, 0x38, 0x4e, 0x32, +0x7a, 0x7a, 0x32, 0x61, 0x58, 0x58, 0x58, 0x62, 0x68, 0x61, 0x51, 0x56, 0x37, 0x61, 0x30, 0x6d, +0x50, 0x69, 0x6a, 0x47, 0x65, 0x32, 0x59, 0x32, 0x52, 0x36, 0x4f, 0x54, 0x65, 0x2b, 0x6e, 0x76, +0x2f, 0x7a, 0x42, 0x71, 0x46, 0x74, 0x6f, 0x71, 0x61, 0x54, 0x4d, 0x51, 0x39, 0x48, 0x67, 0x2b, +0x69, 0x6c, 0x4b, 0x4b, 0x74, 0x4d, 0x2b, 0x54, 0x59, 0x50, 0x32, 0x51, 0x35, 0x63, 0x31, 0x49, +0x76, 0x35, 0x30, 0x2b, 0x2b, 0x6b, 0x54, 0x6c, 0x54, 0x4a, 0x76, 0x47, 0x68, 0x71, 0x45, 0x52, +0x71, 0x79, 0x36, 0x77, 0x2f, 0x64, 0x33, 0x50, 0x4c, 0x31, 0x4a, 0x2f, 0x77, 0x39, 0x46, 0x4c, +0x42, 0x31, 0x4c, 0x2b, 0x55, 0x49, 0x54, 0x57, 0x4d, 0x48, 0x56, 0x77, 0x47, 0x48, 0x58, 0x33, +0x6f, 0x72, 0x37, 0x61, 0x57, 0x73, 0x77, 0x39, 0x64, 0x77, 0x37, 0x36, 0x37, 0x53, 0x47, 0x65, +0x44, 0x6d, 0x32, 0x49, 0x54, 0x6f, 0x4b, 0x43, 0x4a, 0x4a, 0x75, 0x71, 0x2b, 0x69, 0x6c, 0x79, +0x34, 0x7a, 0x78, 0x71, 0x4a, 0x7a, 0x51, 0x6a, 0x79, 0x56, 0x63, 0x65, 0x79, 0x53, 0x75, 0x32, +0x45, 0x57, 0x52, 0x39, 0x51, 0x57, 0x64, 0x47, 0x4a, 0x33, 0x4c, 0x69, 0x43, 0x68, 0x6f, 0x63, +0x76, 0x6f, 0x58, 0x61, 0x33, 0x55, 0x31, 0x67, 0x37, 0x36, 0x55, 0x52, 0x36, 0x44, 0x72, 0x36, +0x4a, 0x6d, 0x67, 0x38, 0x50, 0x68, 0x58, 0x4b, 0x46, 0x31, 0x57, 0x37, 0x38, 0x6c, 0x32, 0x51, +0x79, 0x44, 0x4c, 0x6e, 0x6f, 0x66, 0x4e, 0x53, 0x53, 0x7a, 0x32, 0x6c, 0x34, 0x65, 0x67, 0x62, +0x53, 0x6d, 0x77, 0x41, 0x62, 0x39, 0x70, 0x6e, 0x6b, 0x74, 0x6f, 0x34, 0x6e, 0x77, 0x44, 0x4b, +0x76, 0x79, 0x54, 0x6d, 0x48, 0x6f, 0x43, 0x49, 0x37, 0x62, 0x69, 0x78, 0x7a, 0x33, 0x2f, 0x75, +0x41, 0x4c, 0x42, 0x53, 0x77, 0x2f, 0x47, 0x34, 0x44, 0x69, 0x56, 0x76, 0x4a, 0x68, 0x64, 0x39, +0x4d, 0x38, 0x72, 0x66, 0x5a, 0x33, 0x65, 0x51, 0x6a, 0x7a, 0x53, 0x57, 0x6e, 0x2f, 0x59, 0x42, +0x70, 0x44, 0x77, 0x74, 0x2b, 0x65, 0x4f, 0x52, 0x64, 0x66, 0x70, 0x4e, 0x4d, 0x6b, 0x76, 0x68, +0x4a, 0x4f, 0x52, 0x56, 0x49, 0x61, 0x56, 0x38, 0x65, 0x31, 0x32, 0x45, 0x70, 0x4f, 0x50, 0x39, +0x34, 0x33, 0x33, 0x6b, 0x68, 0x73, 0x56, 0x6b, 0x6e, 0x41, 0x4e, 0x77, 0x2b, 0x5a, 0x37, 0x2b, +0x66, 0x47, 0x51, 0x55, 0x52, 0x6e, 0x76, 0x43, 0x63, 0x59, 0x2b, 0x57, 0x35, 0x5a, 0x6b, 0x6d, +0x38, 0x6c, 0x65, 0x41, 0x37, 0x38, 0x77, 0x57, 0x6a, 0x65, 0x68, 0x33, 0x52, 0x4c, 0x61, 0x71, +0x55, 0x33, 0x44, 0x64, 0x4f, 0x38, 0x73, 0x65, 0x52, 0x43, 0x56, 0x4d, 0x35, 0x68, 0x32, 0x48, +0x42, 0x42, 0x46, 0x41, 0x70, 0x63, 0x6c, 0x44, 0x4b, 0x67, 0x57, 0x31, 0x57, 0x57, 0x79, 0x5a, +0x4c, 0x6f, 0x5a, 0x7a, 0x61, 0x51, 0x33, 0x6b, 0x56, 0x62, 0x74, 0x58, 0x76, 0x6d, 0x33, 0x67, +0x6b, 0x73, 0x64, 0x6d, 0x39, 0x4b, 0x70, 0x2f, 0x59, 0x38, 0x73, 0x70, 0x49, 0x6c, 0x48, 0x64, +0x59, 0x49, 0x69, 0x43, 0x65, 0x43, 0x5a, 0x6c, 0x57, 0x68, 0x56, 0x6c, 0x53, 0x67, 0x44, 0x4c, +0x2f, 0x4b, 0x31, 0x44, 0x53, 0x59, 0x4c, 0x7a, 0x6d, 0x4a, 0x78, 0x51, 0x77, 0x41, 0x36, 0x6b, +0x41, 0x65, 0x50, 0x64, 0x64, 0x37, 0x4b, 0x32, 0x33, 0x59, 0x6c, 0x65, 0x74, 0x47, 0x70, 0x67, +0x42, 0x69, 0x39, 0x6f, 0x50, 0x51, 0x42, 0x75, 0x73, 0x36, 0x6c, 0x37, 0x4a, 0x32, 0x56, 0x75, +0x66, 0x78, 0x32, 0x37, 0x31, 0x4f, 0x32, 0x47, 0x4e, 0x5a, 0x63, 0x55, 0x35, 0x5a, 0x30, 0x4d, +0x51, 0x4d, 0x50, 0x69, 0x53, 0x48, 0x32, 0x42, 0x74, 0x77, 0x4c, 0x70, 0x70, 0x50, 0x30, 0x4e, +0x73, 0x62, 0x47, 0x50, 0x55, 0x48, 0x2f, 0x2f, 0x4d, 0x74, 0x4f, 0x31, 0x76, 0x5a, 0x4e, 0x61, +0x6f, 0x32, 0x55, 0x7a, 0x2f, 0x38, 0x42, 0x5a, 0x59, 0x43, 0x77, 0x7a, 0x70, 0x33, 0x33, 0x39, +0x6a, 0x72, 0x59, 0x4d, 0x50, 0x46, 0x2f, 0x64, 0x6a, 0x45, 0x2f, 0x55, 0x37, 0x4a, 0x69, 0x37, +0x61, 0x61, 0x35, 0x34, 0x77, 0x2f, 0x77, 0x43, 0x43, 0x34, 0x49, 0x6a, 0x6a, 0x48, 0x33, 0x4d, +0x6d, 0x67, 0x74, 0x4b, 0x59, 0x70, 0x50, 0x32, 0x47, 0x67, 0x70, 0x4e, 0x4f, 0x53, 0x73, 0x70, +0x79, 0x6b, 0x74, 0x62, 0x78, 0x67, 0x71, 0x59, 0x6d, 0x67, 0x78, 0x7a, 0x39, 0x44, 0x36, 0x78, +0x56, 0x58, 0x4c, 0x30, 0x72, 0x48, 0x48, 0x47, 0x52, 0x53, 0x4b, 0x48, 0x67, 0x62, 0x38, 0x79, +0x65, 0x7a, 0x65, 0x71, 0x31, 0x61, 0x78, 0x30, 0x55, 0x66, 0x43, 0x5a, 0x63, 0x4c, 0x48, 0x74, +0x59, 0x4b, 0x6a, 0x72, 0x64, 0x34, 0x6d, 0x43, 0x4b, 0x54, 0x44, 0x41, 0x72, 0x53, 0x2b, 0x5a, +0x51, 0x47, 0x65, 0x56, 0x4d, 0x4e, 0x61, 0x4d, 0x5a, 0x53, 0x77, 0x39, 0x76, 0x64, 0x72, 0x6f, +0x31, 0x53, 0x46, 0x6d, 0x56, 0x2b, 0x70, 0x58, 0x75, 0x65, 0x44, 0x58, 0x44, 0x4c, 0x5a, 0x55, +0x39, 0x76, 0x48, 0x4c, 0x62, 0x66, 0x6c, 0x67, 0x35, 0x77, 0x76, 0x57, 0x37, 0x2f, 0x44, 0x4f, +0x32, 0x76, 0x53, 0x4f, 0x4c, 0x4e, 0x46, 0x6d, 0x55, 0x6c, 0x67, 0x56, 0x66, 0x53, 0x54, 0x48, +0x39, 0x44, 0x52, 0x32, 0x4b, 0x50, 0x50, 0x31, 0x30, 0x72, 0x6d, 0x30, 0x64, 0x6a, 0x65, 0x67, +0x52, 0x4c, 0x76, 0x47, 0x47, 0x73, 0x61, 0x56, 0x58, 0x57, 0x39, 0x6a, 0x71, 0x4f, 0x39, 0x36, +0x57, 0x4d, 0x79, 0x63, 0x37, 0x6d, 0x79, 0x37, 0x78, 0x50, 0x63, 0x67, 0x6f, 0x62, 0x4e, 0x6c, +0x57, 0x74, 0x48, 0x56, 0x73, 0x53, 0x38, 0x57, 0x61, 0x54, 0x70, 0x6f, 0x66, 0x75, 0x35, 0x78, +0x56, 0x55, 0x35, 0x36, 0x6b, 0x34, 0x35, 0x6e, 0x66, 0x55, 0x6b, 0x2b, 0x4d, 0x2f, 0x65, 0x68, +0x75, 0x68, 0x72, 0x78, 0x36, 0x4f, 0x34, 0x32, 0x42, 0x77, 0x41, 0x37, 0x78, 0x34, 0x2b, 0x2f, +0x70, 0x33, 0x2b, 0x43, 0x51, 0x70, 0x41, 0x6c, 0x63, 0x57, 0x32, 0x71, 0x2f, 0x33, 0x79, 0x4a, +0x4f, 0x6d, 0x44, 0x32, 0x68, 0x48, 0x51, 0x63, 0x33, 0x64, 0x38, 0x68, 0x53, 0x74, 0x38, 0x50, +0x4e, 0x4f, 0x77, 0x48, 0x64, 0x4e, 0x74, 0x36, 0x57, 0x70, 0x6a, 0x4a, 0x76, 0x6d, 0x78, 0x75, +0x48, 0x66, 0x76, 0x54, 0x62, 0x65, 0x35, 0x55, 0x79, 0x4c, 0x46, 0x6b, 0x68, 0x65, 0x65, 0x67, +0x76, 0x48, 0x56, 0x78, 0x77, 0x2f, 0x67, 0x2b, 0x35, 0x35, 0x39, 0x46, 0x42, 0x6a, 0x4e, 0x2b, +0x73, 0x48, 0x47, 0x30, 0x53, 0x41, 0x53, 0x43, 0x51, 0x79, 0x74, 0x41, 0x79, 0x70, 0x4e, 0x70, +0x74, 0x45, 0x34, 0x32, 0x42, 0x73, 0x70, 0x46, 0x75, 0x77, 0x34, 0x4a, 0x32, 0x63, 0x45, 0x61, +0x79, 0x45, 0x72, 0x4b, 0x4b, 0x73, 0x53, 0x4e, 0x72, 0x58, 0x61, 0x68, 0x4a, 0x4a, 0x78, 0x71, +0x41, 0x63, 0x52, 0x71, 0x41, 0x55, 0x72, 0x54, 0x55, 0x74, 0x7a, 0x6a, 0x62, 0x58, 0x6d, 0x73, +0x2b, 0x33, 0x6c, 0x62, 0x79, 0x6a, 0x32, 0x2f, 0x34, 0x31, 0x56, 0x65, 0x72, 0x46, 0x4c, 0x6f, +0x37, 0x31, 0x68, 0x52, 0x42, 0x67, 0x59, 0x73, 0x45, 0x67, 0x4a, 0x53, 0x4b, 0x6c, 0x70, 0x59, +0x57, 0x62, 0x34, 0x64, 0x70, 0x67, 0x73, 0x44, 0x5a, 0x37, 0x75, 0x36, 0x71, 0x41, 0x47, 0x63, +0x7a, 0x4d, 0x56, 0x62, 0x31, 0x68, 0x33, 0x49, 0x4b, 0x6b, 0x45, 0x62, 0x52, 0x55, 0x74, 0x33, +0x69, 0x56, 0x33, 0x66, 0x74, 0x73, 0x51, 0x61, 0x79, 0x68, 0x4b, 0x43, 0x55, 0x56, 0x71, 0x56, +0x51, 0x53, 0x71, 0x4e, 0x64, 0x61, 0x4a, 0x72, 0x2f, 0x44, 0x45, 0x70, 0x61, 0x44, 0x4d, 0x55, +0x46, 0x73, 0x44, 0x76, 0x74, 0x42, 0x44, 0x66, 0x65, 0x43, 0x4e, 0x64, 0x65, 0x43, 0x31, 0x31, +0x64, 0x4a, 0x65, 0x38, 0x49, 0x6b, 0x6d, 0x52, 0x33, 0x78, 0x65, 0x32, 0x76, 0x67, 0x70, 0x2f, +0x74, 0x4f, 0x41, 0x31, 0x72, 0x4c, 0x62, 0x31, 0x76, 0x76, 0x63, 0x33, 0x47, 0x52, 0x33, 0x35, +0x50, 0x32, 0x63, 0x69, 0x52, 0x6f, 0x44, 0x56, 0x74, 0x76, 0x37, 0x34, 0x48, 0x49, 0x79, 0x58, +0x5a, 0x35, 0x6d, 0x59, 0x79, 0x51, 0x34, 0x62, 0x77, 0x78, 0x57, 0x6b, 0x6e, 0x4d, 0x76, 0x69, +0x30, 0x4d, 0x39, 0x6e, 0x76, 0x30, 0x49, 0x50, 0x5a, 0x37, 0x38, 0x43, 0x2f, 0x55, 0x50, 0x64, +0x55, 0x6e, 0x64, 0x4f, 0x41, 0x2b, 0x76, 0x51, 0x2f, 0x47, 0x32, 0x59, 0x77, 0x53, 0x68, 0x4f, +0x30, 0x31, 0x6e, 0x78, 0x74, 0x2b, 0x35, 0x55, 0x6e, 0x77, 0x44, 0x4c, 0x66, 0x66, 0x36, 0x4f, +0x30, 0x6a, 0x7a, 0x55, 0x58, 0x6b, 0x6b, 0x2b, 0x6b, 0x56, 0x37, 0x2b, 0x70, 0x70, 0x73, 0x49, +0x6e, 0x33, 0x42, 0x41, 0x55, 0x56, 0x4f, 0x41, 0x67, 0x30, 0x34, 0x79, 0x78, 0x6b, 0x66, 0x4d, +0x39, 0x6f, 0x4b, 0x69, 0x6f, 0x6c, 0x34, 0x51, 0x35, 0x74, 0x33, 0x6c, 0x70, 0x77, 0x70, 0x36, +0x53, 0x66, 0x37, 0x35, 0x66, 0x52, 0x39, 0x78, 0x70, 0x57, 0x4c, 0x46, 0x4b, 0x73, 0x65, 0x4a, +0x4c, 0x78, 0x64, 0x53, 0x62, 0x45, 0x67, 0x50, 0x63, 0x4c, 0x53, 0x44, 0x4e, 0x32, 0x57, 0x62, +0x76, 0x66, 0x31, 0x46, 0x6f, 0x6f, 0x78, 0x43, 0x49, 0x31, 0x4b, 0x65, 0x68, 0x2f, 0x4b, 0x6f, +0x76, 0x72, 0x51, 0x76, 0x7a, 0x61, 0x61, 0x76, 0x52, 0x36, 0x42, 0x54, 0x63, 0x49, 0x35, 0x57, +0x69, 0x75, 0x61, 0x59, 0x6c, 0x6e, 0x58, 0x65, 0x6c, 0x6d, 0x6a, 0x6a, 0x35, 0x43, 0x63, 0x6e, +0x4a, 0x6b, 0x37, 0x72, 0x4a, 0x5a, 0x41, 0x31, 0x33, 0x2f, 0x6d, 0x6b, 0x4c, 0x52, 0x67, 0x33, +0x79, 0x49, 0x55, 0x4c, 0x74, 0x49, 0x69, 0x56, 0x47, 0x46, 0x78, 0x77, 0x34, 0x63, 0x72, 0x4e, +0x52, 0x74, 0x42, 0x78, 0x31, 0x4a, 0x4c, 0x4b, 0x32, 0x46, 0x68, 0x58, 0x48, 0x71, 0x4a, 0x77, +0x4c, 0x39, 0x55, 0x6d, 0x50, 0x41, 0x35, 0x42, 0x46, 0x65, 0x49, 0x41, 0x6b, 0x78, 0x5a, 0x65, +0x32, 0x65, 0x52, 0x43, 0x72, 0x43, 0x57, 0x76, 0x41, 0x68, 0x67, 0x72, 0x37, 0x31, 0x67, 0x5a, +0x61, 0x46, 0x6b, 0x2b, 0x48, 0x63, 0x6f, 0x30, 0x64, 0x4d, 0x35, 0x4b, 0x36, 0x7a, 0x35, 0x36, +0x6c, 0x4c, 0x43, 0x63, 0x49, 0x6d, 0x6b, 0x64, 0x42, 0x4b, 0x4b, 0x45, 0x75, 0x73, 0x52, 0x66, +0x38, 0x2b, 0x4a, 0x74, 0x43, 0x72, 0x6b, 0x65, 0x72, 0x46, 0x47, 0x47, 0x4c, 0x55, 0x2f, 0x75, +0x62, 0x36, 0x70, 0x78, 0x64, 0x6d, 0x52, 0x6e, 0x5a, 0x53, 0x71, 0x68, 0x64, 0x7a, 0x42, 0x38, +0x66, 0x2b, 0x38, 0x38, 0x6f, 0x35, 0x5a, 0x68, 0x66, 0x46, 0x77, 0x52, 0x77, 0x41, 0x43, 0x2f, +0x59, 0x55, 0x6e, 0x7a, 0x57, 0x70, 0x75, 0x34, 0x56, 0x4d, 0x4a, 0x53, 0x72, 0x62, 0x68, 0x37, +0x4c, 0x6a, 0x56, 0x4d, 0x2b, 0x41, 0x31, 0x62, 0x35, 0x37, 0x6e, 0x2f, 0x71, 0x35, 0x45, 0x67, +0x52, 0x76, 0x6d, 0x76, 0x44, 0x4d, 0x77, 0x39, 0x69, 0x65, 0x6e, 0x46, 0x59, 0x63, 0x77, 0x47, +0x6d, 0x78, 0x69, 0x47, 0x58, 0x57, 0x6b, 0x2f, 0x5a, 0x41, 0x2b, 0x63, 0x36, 0x62, 0x53, 0x66, +0x31, 0x67, 0x4c, 0x55, 0x73, 0x2b, 0x35, 0x66, 0x51, 0x66, 0x66, 0x2f, 0x4f, 0x73, 0x58, 0x41, +0x78, 0x69, 0x43, 0x78, 0x70, 0x62, 0x73, 0x54, 0x42, 0x46, 0x57, 0x44, 0x61, 0x59, 0x50, 0x56, +0x32, 0x4b, 0x63, 0x32, 0x51, 0x41, 0x78, 0x59, 0x42, 0x4a, 0x33, 0x2b, 0x50, 0x72, 0x30, 0x5a, +0x76, 0x46, 0x69, 0x4d, 0x53, 0x69, 0x34, 0x66, 0x43, 0x41, 0x43, 0x48, 0x30, 0x4c, 0x4f, 0x79, +0x50, 0x4c, 0x6f, 0x50, 0x2b, 0x7a, 0x77, 0x62, 0x36, 0x44, 0x55, 0x44, 0x4e, 0x6d, 0x6a, 0x56, +0x55, 0x56, 0x56, 0x55, 0x56, 0x45, 0x49, 0x4e, 0x33, 0x33, 0x59, 0x57, 0x35, 0x36, 0x71, 0x6f, +0x42, 0x33, 0x36, 0x45, 0x47, 0x4b, 0x4c, 0x2f, 0x69, 0x38, 0x31, 0x6d, 0x4d, 0x62, 0x42, 0x2f, +0x4b, 0x42, 0x7a, 0x74, 0x73, 0x52, 0x61, 0x66, 0x76, 0x56, 0x31, 0x38, 0x67, 0x57, 0x33, 0x48, +0x35, 0x35, 0x44, 0x66, 0x37, 0x50, 0x50, 0x6f, 0x6b, 0x38, 0x34, 0x61, 0x76, 0x35, 0x62, 0x78, +0x6e, 0x7a, 0x2b, 0x73, 0x50, 0x4a, 0x56, 0x56, 0x41, 0x4c, 0x36, 0x79, 0x5a, 0x2b, 0x66, 0x58, +0x74, 0x58, 0x7a, 0x44, 0x41, 0x30, 0x48, 0x78, 0x56, 0x2f, 0x61, 0x6e, 0x6a, 0x7a, 0x37, 0x66, +0x6a, 0x72, 0x50, 0x64, 0x49, 0x30, 0x61, 0x59, 0x70, 0x64, 0x4e, 0x6e, 0x50, 0x57, 0x35, 0x68, +0x31, 0x43, 0x46, 0x6a, 0x54, 0x36, 0x31, 0x34, 0x51, 0x56, 0x6f, 0x47, 0x71, 0x63, 0x50, 0x64, +0x47, 0x77, 0x5a, 0x4b, 0x50, 0x34, 0x63, 0x69, 0x4a, 0x66, 0x56, 0x37, 0x2b, 0x37, 0x7a, 0x51, +0x41, 0x34, 0x42, 0x56, 0x4b, 0x36, 0x57, 0x39, 0x54, 0x79, 0x46, 0x4e, 0x46, 0x67, 0x74, 0x34, +0x75, 0x50, 0x55, 0x61, 0x4d, 0x67, 0x4e, 0x74, 0x75, 0x63, 0x36, 0x6d, 0x35, 0x4f, 0x6a, 0x73, +0x4c, 0x67, 0x6a, 0x4a, 0x42, 0x2f, 0x41, 0x6c, 0x42, 0x50, 0x77, 0x51, 0x67, 0x75, 0x47, 0x73, +0x75, 0x52, 0x39, 0x66, 0x51, 0x4b, 0x58, 0x41, 0x75, 0x6d, 0x42, 0x68, 0x4d, 0x6b, 0x2b, 0x4d, +0x58, 0x46, 0x4a, 0x69, 0x65, 0x66, 0x34, 0x31, 0x2b, 0x45, 0x6c, 0x53, 0x37, 0x41, 0x55, 0x5a, +0x76, 0x33, 0x4d, 0x69, 0x67, 0x62, 0x64, 0x39, 0x6d, 0x77, 0x30, 0x65, 0x37, 0x4d, 0x71, 0x2b, +0x78, 0x73, 0x52, 0x39, 0x79, 0x74, 0x47, 0x2f, 0x58, 0x41, 0x59, 0x49, 0x4a, 0x37, 0x31, 0x6a, +0x62, 0x58, 0x76, 0x52, 0x45, 0x47, 0x5a, 0x65, 0x34, 0x4d, 0x6f, 0x46, 0x68, 0x32, 0x37, 0x34, +0x34, 0x37, 0x4f, 0x4c, 0x50, 0x67, 0x50, 0x31, 0x57, 0x44, 0x73, 0x34, 0x2f, 0x33, 0x36, 0x31, +0x59, 0x59, 0x38, 0x61, 0x55, 0x51, 0x68, 0x71, 0x2f, 0x6f, 0x67, 0x50, 0x4a, 0x57, 0x54, 0x50, +0x41, 0x6d, 0x43, 0x62, 0x7a, 0x6c, 0x4f, 0x41, 0x73, 0x63, 0x70, 0x74, 0x34, 0x48, 0x30, 0x44, +0x46, 0x45, 0x63, 0x64, 0x68, 0x32, 0x74, 0x73, 0x4a, 0x73, 0x79, 0x48, 0x52, 0x32, 0x68, 0x56, +0x55, 0x76, 0x2f, 0x64, 0x65, 0x76, 0x2f, 0x63, 0x6c, 0x4b, 0x36, 0x77, 0x51, 0x67, 0x6c, 0x57, +0x4e, 0x6a, 0x65, 0x51, 0x6f, 0x7a, 0x4f, 0x6b, 0x32, 0x48, 0x2b, 0x33, 0x53, 0x37, 0x37, 0x66, +0x46, 0x32, 0x31, 0x61, 0x54, 0x71, 0x39, 0x59, 0x75, 0x7a, 0x6c, 0x39, 0x38, 0x31, 0x56, 0x6f, +0x7a, 0x65, 0x75, 0x67, 0x79, 0x41, 0x48, 0x62, 0x66, 0x2f, 0x6b, 0x48, 0x65, 0x2f, 0x75, 0x69, +0x30, 0x51, 0x67, 0x65, 0x73, 0x41, 0x33, 0x57, 0x70, 0x32, 0x44, 0x69, 0x4e, 0x51, 0x43, 0x6d, +0x51, 0x4d, 0x52, 0x6a, 0x4a, 0x72, 0x43, 0x31, 0x48, 0x55, 0x62, 0x35, 0x35, 0x54, 0x41, 0x77, +0x63, 0x75, 0x74, 0x30, 0x43, 0x4d, 0x76, 0x57, 0x44, 0x2b, 0x50, 0x4f, 0x50, 0x57, 0x7a, 0x6a, +0x36, 0x75, 0x69, 0x38, 0x68, 0x64, 0x49, 0x67, 0x78, 0x33, 0x51, 0x30, 0x64, 0x48, 0x37, 0x6d, +0x38, 0x65, 0x51, 0x33, 0x6a, 0x76, 0x34, 0x41, 0x79, 0x34, 0x37, 0x51, 0x4c, 0x59, 0x64, 0x77, +0x4b, 0x6b, 0x4f, 0x44, 0x46, 0x5a, 0x32, 0x35, 0x54, 0x4f, 0x71, 0x50, 0x4a, 0x49, 0x42, 0x58, +0x50, 0x74, 0x6f, 0x48, 0x38, 0x38, 0x47, 0x45, 0x59, 0x4a, 0x56, 0x78, 0x69, 0x46, 0x68, 0x4e, +0x68, 0x6c, 0x4d, 0x58, 0x63, 0x41, 0x49, 0x4e, 0x6e, 0x39, 0x69, 0x2f, 0x61, 0x39, 0x33, 0x4e, +0x79, 0x56, 0x6c, 0x67, 0x62, 0x39, 0x42, 0x76, 0x63, 0x32, 0x77, 0x4f, 0x62, 0x54, 0x70, 0x52, +0x6e, 0x7a, 0x4d, 0x34, 0x4c, 0x4f, 0x34, 0x44, 0x2b, 0x4d, 0x4f, 0x68, 0x68, 0x62, 0x77, 0x38, +0x72, 0x5a, 0x63, 0x51, 0x51, 0x2f, 0x76, 0x62, 0x4b, 0x31, 0x54, 0x7a, 0x62, 0x50, 0x6f, 0x52, +0x66, 0x66, 0x62, 0x79, 0x61, 0x6d, 0x37, 0x76, 0x66, 0x4a, 0x34, 0x76, 0x68, 0x4d, 0x6a, 0x57, +0x52, 0x37, 0x32, 0x54, 0x62, 0x4f, 0x47, 0x72, 0x58, 0x49, 0x5a, 0x7a, 0x38, 0x35, 0x50, 0x50, +0x41, 0x53, 0x41, 0x62, 0x47, 0x32, 0x67, 0x76, 0x34, 0x33, 0x6c, 0x50, 0x51, 0x71, 0x39, 0x4c, +0x33, 0x45, 0x52, 0x6d, 0x6f, 0x43, 0x74, 0x47, 0x2f, 0x32, 0x37, 0x4f, 0x6b, 0x37, 0x67, 0x46, +0x50, 0x6f, 0x50, 0x47, 0x68, 0x51, 0x61, 0x56, 0x51, 0x36, 0x43, 0x77, 0x73, 0x75, 0x38, 0x7a, +0x56, 0x32, 0x4c, 0x66, 0x2f, 0x70, 0x71, 0x64, 0x41, 0x2f, 0x67, 0x6b, 0x55, 0x65, 0x75, 0x32, +0x67, 0x77, 0x76, 0x63, 0x4a, 0x6d, 0x72, 0x6e, 0x68, 0x49, 0x46, 0x6a, 0x37, 0x74, 0x39, 0x4c, +0x79, 0x66, 0x61, 0x59, 0x6a, 0x2f, 0x62, 0x7a, 0x6a, 0x54, 0x50, 0x65, 0x75, 0x34, 0x67, 0x46, +0x50, 0x33, 0x70, 0x2f, 0x65, 0x71, 0x30, 0x32, 0x63, 0x77, 0x42, 0x59, 0x2f, 0x2b, 0x6c, 0x6b, +0x42, 0x54, 0x2b, 0x63, 0x36, 0x37, 0x4f, 0x6a, 0x43, 0x44, 0x69, 0x51, 0x56, 0x2b, 0x36, 0x35, +0x77, 0x68, 0x75, 0x78, 0x36, 0x41, 0x64, 0x50, 0x47, 0x34, 0x6c, 0x4d, 0x35, 0x57, 0x36, 0x77, +0x4e, 0x58, 0x45, 0x4a, 0x47, 0x63, 0x42, 0x68, 0x79, 0x45, 0x36, 0x42, 0x73, 0x42, 0x6d, 0x33, +0x44, 0x64, 0x48, 0x75, 0x6d, 0x39, 0x46, 0x73, 0x31, 0x66, 0x2f, 0x6c, 0x32, 0x4e, 0x31, 0x51, +0x50, 0x63, 0x74, 0x75, 0x78, 0x66, 0x76, 0x59, 0x7a, 0x37, 0x46, 0x56, 0x58, 0x2f, 0x64, 0x74, +0x51, 0x32, 0x76, 0x4a, 0x52, 0x69, 0x37, 0x6e, 0x70, 0x6d, 0x73, 0x47, 0x2b, 0x37, 0x78, 0x61, +0x6a, 0x49, 0x53, 0x36, 0x76, 0x6f, 0x4c, 0x79, 0x6e, 0x6c, 0x2b, 0x6f, 0x4b, 0x67, 0x54, 0x53, +0x4b, 0x6a, 0x5a, 0x31, 0x6c, 0x64, 0x47, 0x63, 0x71, 0x43, 0x64, 0x6f, 0x36, 0x58, 0x48, 0x49, +0x4f, 0x62, 0x35, 0x6f, 0x38, 0x38, 0x50, 0x4e, 0x50, 0x32, 0x4c, 0x68, 0x38, 0x47, 0x70, 0x56, +0x54, 0x4c, 0x67, 0x45, 0x67, 0x30, 0x39, 0x56, 0x47, 0x56, 0x56, 0x56, 0x56, 0x36, 0x76, 0x77, +0x53, 0x48, 0x52, 0x30, 0x45, 0x42, 0x6a, 0x49, 0x4e, 0x64, 0x56, 0x68, 0x6a, 0x4b, 0x4d, 0x75, +0x57, 0x30, 0x58, 0x54, 0x2b, 0x2b, 0x57, 0x54, 0x4c, 0x61, 0x7a, 0x42, 0x61, 0x38, 0x2f, 0x6e, +0x74, 0x74, 0x7a, 0x70, 0x4d, 0x2f, 0x6a, 0x5a, 0x37, 0x46, 0x55, 0x62, 0x66, 0x65, 0x68, 0x69, +0x6d, 0x56, 0x56, 0x69, 0x72, 0x76, 0x59, 0x64, 0x5a, 0x45, 0x6c, 0x68, 0x6e, 0x53, 0x6d, 0x52, +0x73, 0x38, 0x6c, 0x6b, 0x69, 0x33, 0x31, 0x67, 0x43, 0x77, 0x4d, 0x78, 0x74, 0x2f, 0x73, 0x71, +0x42, 0x58, 0x4d, 0x2b, 0x4c, 0x57, 0x77, 0x39, 0x6c, 0x35, 0x73, 0x72, 0x44, 0x33, 0x48, 0x34, +0x35, 0x41, 0x31, 0x5a, 0x37, 0x62, 0x37, 0x6f, 0x42, 0x71, 0x79, 0x32, 0x6e, 0x74, 0x7a, 0x37, +0x46, 0x54, 0x6c, 0x58, 0x54, 0x34, 0x63, 0x52, 0x52, 0x39, 0x45, 0x34, 0x49, 0x65, 0x58, 0x6e, +0x68, 0x41, 0x6a, 0x4c, 0x31, 0x44, 0x53, 0x78, 0x34, 0x35, 0x47, 0x6c, 0x47, 0x6a, 0x50, 0x67, +0x78, 0x58, 0x2b, 0x7a, 0x34, 0x43, 0x49, 0x2b, 0x2f, 0x66, 0x51, 0x48, 0x61, 0x67, 0x49, 0x32, +0x68, 0x61, 0x74, 0x5a, 0x46, 0x57, 0x4b, 0x57, 0x34, 0x5a, 0x61, 0x38, 0x6d, 0x5a, 0x4d, 0x5a, +0x74, 0x4d, 0x39, 0x62, 0x47, 0x62, 0x54, 0x48, 0x57, 0x31, 0x6e, 0x44, 0x7a, 0x39, 0x78, 0x65, +0x42, 0x67, 0x71, 0x76, 0x48, 0x65, 0x43, 0x67, 0x76, 0x48, 0x6b, 0x70, 0x74, 0x4e, 0x51, 0x71, +0x4e, 0x31, 0x6f, 0x6f, 0x41, 0x78, 0x65, 0x52, 0x47, 0x52, 0x62, 0x62, 0x53, 0x68, 0x37, 0x6b, +0x53, 0x4b, 0x4f, 0x2f, 0x7a, 0x6b, 0x75, 0x36, 0x5a, 0x41, 0x30, 0x43, 0x68, 0x6b, 0x35, 0x69, +0x79, 0x6c, 0x42, 0x42, 0x46, 0x36, 0x66, 0x79, 0x70, 0x65, 0x2b, 0x39, 0x6c, 0x77, 0x4b, 0x4d, +0x62, 0x4f, 0x4b, 0x69, 0x6f, 0x76, 0x44, 0x58, 0x55, 0x31, 0x39, 0x63, 0x79, 0x45, 0x42, 0x52, +0x36, 0x38, 0x6c, 0x61, 0x54, 0x55, 0x56, 0x59, 0x69, 0x72, 0x62, 0x50, 0x46, 0x5a, 0x38, 0x79, +0x65, 0x77, 0x59, 0x38, 0x2b, 0x79, 0x76, 0x48, 0x6e, 0x58, 0x30, 0x7a, 0x69, 0x2b, 0x77, 0x31, +0x44, 0x30, 0x41, 0x76, 0x32, 0x78, 0x73, 0x53, 0x43, 0x51, 0x34, 0x59, 0x4f, 0x5a, 0x38, 0x69, +0x51, 0x47, 0x6c, 0x35, 0x61, 0x30, 0x73, 0x73, 0x50, 0x74, 0x74, 0x36, 0x5a, 0x54, 0x46, 0x6d, +0x56, 0x4d, 0x30, 0x32, 0x31, 0x39, 0x69, 0x61, 0x71, 0x38, 0x31, 0x73, 0x39, 0x4f, 0x50, 0x30, +0x79, 0x6c, 0x78, 0x58, 0x33, 0x70, 0x44, 0x47, 0x63, 0x74, 0x6d, 0x73, 0x6a, 0x76, 0x33, 0x75, +0x76, 0x44, 0x53, 0x30, 0x31, 0x64, 0x5a, 0x55, 0x5a, 0x6b, 0x6c, 0x32, 0x4c, 0x51, 0x52, 0x43, +0x51, 0x79, 0x57, 0x51, 0x49, 0x77, 0x37, 0x43, 0x66, 0x4a, 0x37, 0x79, 0x37, 0x75, 0x78, 0x75, +0x36, 0x2b, 0x30, 0x43, 0x68, 0x51, 0x30, 0x50, 0x44, 0x31, 0x52, 0x70, 0x36, 0x2b, 0x74, 0x42, +0x76, 0x70, 0x63, 0x53, 0x57, 0x39, 0x59, 0x64, 0x43, 0x47, 0x36, 0x44, 0x35, 0x6d, 0x71, 0x75, +0x70, 0x50, 0x51, 0x57, 0x36, 0x2f, 0x6d, 0x67, 0x6f, 0x47, 0x32, 0x4d, 0x6f, 0x33, 0x30, 0x58, +0x54, 0x73, 0x46, 0x4c, 0x54, 0x39, 0x62, 0x51, 0x43, 0x55, 0x63, 0x6a, 0x4e, 0x61, 0x50, 0x72, +0x51, 0x2f, 0x37, 0x77, 0x5a, 0x4d, 0x7a, 0x41, 0x47, 0x42, 0x6d, 0x2f, 0x58, 0x42, 0x77, 0x71, +0x63, 0x30, 0x47, 0x43, 0x43, 0x44, 0x54, 0x44, 0x4b, 0x30, 0x61, 0x48, 0x50, 0x37, 0x5a, 0x44, +0x55, 0x76, 0x2b, 0x54, 0x5a, 0x47, 0x56, 0x42, 0x56, 0x77, 0x5a, 0x32, 0x2f, 0x4f, 0x63, 0x52, +0x44, 0x6d, 0x66, 0x48, 0x2b, 0x47, 0x32, 0x64, 0x75, 0x47, 0x4a, 0x50, 0x6b, 0x46, 0x66, 0x51, +0x4a, 0x52, 0x72, 0x54, 0x50, 0x48, 0x47, 0x56, 0x63, 0x79, 0x50, 0x35, 0x58, 0x56, 0x39, 0x35, +0x4a, 0x4e, 0x67, 0x53, 0x4d, 0x68, 0x62, 0x58, 0x53, 0x6f, 0x76, 0x32, 0x57, 0x53, 0x32, 0x57, +0x74, 0x33, 0x34, 0x5a, 0x70, 0x76, 0x65, 0x31, 0x69, 0x76, 0x53, 0x31, 0x6a, 0x30, 0x32, 0x77, +0x6b, 0x77, 0x38, 0x6f, 0x44, 0x70, 0x77, 0x56, 0x30, 0x64, 0x4d, 0x43, 0x4c, 0x4c, 0x32, 0x49, +0x76, 0x76, 0x68, 0x67, 0x75, 0x76, 0x76, 0x6a, 0x66, 0x68, 0x39, 0x49, 0x4f, 0x61, 0x53, 0x61, +0x71, 0x79, 0x72, 0x47, 0x71, 0x7a, 0x65, 0x2b, 0x6a, 0x4e, 0x78, 0x41, 0x71, 0x32, 0x47, 0x2b, +0x66, 0x64, 0x51, 0x77, 0x64, 0x47, 0x52, 0x46, 0x70, 0x7a, 0x52, 0x65, 0x72, 0x42, 0x58, 0x39, +0x37, 0x2b, 0x68, 0x74, 0x30, 0x64, 0x4e, 0x53, 0x6e, 0x61, 0x63, 0x64, 0x47, 0x4e, 0x6f, 0x58, +0x41, 0x35, 0x6c, 0x42, 0x54, 0x34, 0x59, 0x5a, 0x75, 0x2f, 0x51, 0x5a, 0x30, 0x32, 0x39, 0x70, +0x30, 0x63, 0x70, 0x57, 0x78, 0x64, 0x4e, 0x39, 0x31, 0x4e, 0x79, 0x62, 0x53, 0x56, 0x45, 0x2b, +0x39, 0x6e, 0x49, 0x7a, 0x50, 0x54, 0x53, 0x38, 0x57, 0x4c, 0x73, 0x52, 0x55, 0x4e, 0x68, 0x41, +0x4f, 0x62, 0x30, 0x59, 0x41, 0x62, 0x62, 0x39, 0x63, 0x7a, 0x64, 0x42, 0x52, 0x47, 0x77, 0x6f, +0x45, 0x72, 0x52, 0x31, 0x4f, 0x48, 0x49, 0x38, 0x58, 0x64, 0x7a, 0x44, 0x53, 0x70, 0x42, 0x2f, +0x43, 0x49, 0x36, 0x77, 0x6b, 0x56, 0x46, 0x61, 0x54, 0x65, 0x61, 0x65, 0x48, 0x38, 0x4c, 0x4d, +0x38, 0x42, 0x33, 0x49, 0x35, 0x73, 0x4a, 0x47, 0x44, 0x73, 0x35, 0x4d, 0x52, 0x7a, 0x64, 0x50, +0x35, 0x77, 0x2b, 0x65, 0x6e, 0x65, 0x74, 0x53, 0x5a, 0x77, 0x35, 0x35, 0x66, 0x4d, 0x75, 0x34, +0x2b, 0x39, 0x71, 0x79, 0x35, 0x46, 0x76, 0x62, 0x55, 0x39, 0x4c, 0x34, 0x54, 0x6f, 0x72, 0x48, +0x55, 0x54, 0x68, 0x68, 0x4a, 0x44, 0x6a, 0x41, 0x61, 0x2f, 0x76, 0x72, 0x68, 0x6d, 0x66, 0x78, +0x58, 0x35, 0x66, 0x58, 0x38, 0x7a, 0x7a, 0x50, 0x6e, 0x59, 0x77, 0x4b, 0x4c, 0x6b, 0x57, 0x43, +0x30, 0x78, 0x58, 0x37, 0x2b, 0x4f, 0x56, 0x5a, 0x4b, 0x56, 0x6d, 0x36, 0x52, 0x78, 0x48, 0x4e, +0x39, 0x52, 0x68, 0x68, 0x6c, 0x47, 0x54, 0x59, 0x6f, 0x63, 0x4d, 0x7a, 0x6e, 0x53, 0x57, 0x65, +0x46, 0x4c, 0x45, 0x42, 0x35, 0x70, 0x5a, 0x56, 0x6f, 0x48, 0x77, 0x2b, 0x2f, 0x75, 0x46, 0x6d, +0x79, 0x66, 0x55, 0x55, 0x53, 0x46, 0x2f, 0x66, 0x4f, 0x30, 0x63, 0x63, 0x6b, 0x77, 0x57, 0x4f, +0x62, 0x67, 0x45, 0x49, 0x2f, 0x39, 0x46, 0x43, 0x42, 0x61, 0x59, 0x38, 0x2b, 0x32, 0x76, 0x57, +0x31, 0x70, 0x61, 0x57, 0x66, 0x5a, 0x70, 0x41, 0x65, 0x43, 0x5a, 0x53, 0x31, 0x5a, 0x36, 0x58, +0x72, 0x6a, 0x4e, 0x65, 0x51, 0x45, 0x71, 0x59, 0x76, 0x50, 0x68, 0x66, 0x6d, 0x46, 0x36, 0x59, +0x34, 0x69, 0x4e, 0x62, 0x79, 0x56, 0x6a, 0x42, 0x77, 0x33, 0x34, 0x70, 0x66, 0x45, 0x33, 0x37, +0x63, 0x52, 0x48, 0x33, 0x37, 0x42, 0x75, 0x4b, 0x32, 0x6a, 0x5a, 0x67, 0x34, 0x70, 0x6e, 0x78, +0x51, 0x50, 0x5a, 0x47, 0x30, 0x37, 0x4a, 0x77, 0x58, 0x50, 0x4e, 0x48, 0x5a, 0x54, 0x4c, 0x61, +0x38, 0x46, 0x69, 0x57, 0x64, 0x6f, 0x2f, 0x6e, 0x4a, 0x58, 0x35, 0x2f, 0x4e, 0x6f, 0x61, 0x66, +0x65, 0x77, 0x59, 0x6a, 0x6d, 0x42, 0x70, 0x4b, 0x63, 0x62, 0x6d, 0x66, 0x74, 0x50, 0x67, 0x53, +0x70, 0x4c, 0x61, 0x66, 0x75, 0x50, 0x4a, 0x6a, 0x72, 0x6e, 0x6c, 0x33, 0x42, 0x6f, 0x4a, 0x70, +0x4d, 0x4b, 0x6e, 0x79, 0x2b, 0x46, 0x6f, 0x72, 0x74, 0x32, 0x35, 0x39, 0x43, 0x6f, 0x51, 0x4f, +0x4e, 0x2b, 0x6b, 0x4a, 0x43, 0x56, 0x78, 0x2f, 0x36, 0x72, 0x53, 0x71, 0x4b, 0x34, 0x78, 0x64, +0x42, 0x6f, 0x51, 0x31, 0x51, 0x65, 0x36, 0x6f, 0x6c, 0x4d, 0x33, 0x51, 0x6c, 0x74, 0x61, 0x64, +0x71, 0x4e, 0x6b, 0x7a, 0x56, 0x6d, 0x46, 0x35, 0x4a, 0x62, 0x6d, 0x64, 0x4e, 0x32, 0x52, 0x61, +0x53, 0x37, 0x72, 0x2b, 0x55, 0x30, 0x6e, 0x38, 0x53, 0x46, 0x73, 0x32, 0x32, 0x74, 0x68, 0x59, +0x70, 0x62, 0x68, 0x59, 0x72, 0x2b, 0x30, 0x43, 0x42, 0x72, 0x65, 0x36, 0x66, 0x47, 0x43, 0x51, +0x42, 0x46, 0x42, 0x6c, 0x4a, 0x55, 0x4e, 0x36, 0x4b, 0x55, 0x52, 0x43, 0x76, 0x75, 0x70, 0x51, +0x4d, 0x4a, 0x4a, 0x74, 0x50, 0x30, 0x73, 0x53, 0x71, 0x66, 0x56, 0x4f, 0x34, 0x70, 0x35, 0x47, +0x6d, 0x6f, 0x76, 0x35, 0x66, 0x65, 0x64, 0x72, 0x74, 0x5a, 0x4a, 0x64, 0x73, 0x32, 0x31, 0x6d, +0x36, 0x47, 0x65, 0x56, 0x66, 0x77, 0x4c, 0x47, 0x37, 0x46, 0x38, 0x42, 0x35, 0x72, 0x49, 0x66, +0x36, 0x62, 0x32, 0x43, 0x37, 0x75, 0x2b, 0x47, 0x69, 0x69, 0x77, 0x61, 0x47, 0x30, 0x68, 0x5a, +0x42, 0x45, 0x54, 0x63, 0x4e, 0x78, 0x63, 0x58, 0x76, 0x6f, 0x34, 0x64, 0x4d, 0x6f, 0x44, 0x6e, +0x78, 0x31, 0x4c, 0x66, 0x59, 0x74, 0x6e, 0x77, 0x4c, 0x4d, 0x76, 0x6b, 0x6d, 0x70, 0x49, 0x7a, +0x59, 0x72, 0x72, 0x57, 0x58, 0x55, 0x64, 0x2b, 0x66, 0x78, 0x52, 0x30, 0x2f, 0x33, 0x59, 0x32, +0x65, 0x4b, 0x4a, 0x4d, 0x4b, 0x41, 0x65, 0x66, 0x43, 0x64, 0x52, 0x73, 0x2f, 0x58, 0x4c, 0x5a, +0x62, 0x42, 0x32, 0x4b, 0x4a, 0x50, 0x35, 0x31, 0x50, 0x62, 0x41, 0x53, 0x5a, 0x70, 0x63, 0x74, +0x42, 0x52, 0x50, 0x53, 0x38, 0x39, 0x7a, 0x35, 0x5a, 0x72, 0x53, 0x6e, 0x66, 0x64, 0x52, 0x66, +0x49, 0x35, 0x39, 0x46, 0x42, 0x42, 0x54, 0x59, 0x57, 0x4b, 0x4b, 0x44, 0x2b, 0x34, 0x69, 0x5a, +0x36, 0x74, 0x6f, 0x31, 0x4c, 0x69, 0x54, 0x6f, 0x42, 0x5a, 0x70, 0x43, 0x45, 0x45, 0x51, 0x76, +0x52, 0x42, 0x4f, 0x50, 0x76, 0x41, 0x38, 0x72, 0x70, 0x66, 0x4b, 0x30, 0x4d, 0x38, 0x31, 0x45, +0x6c, 0x2b, 0x65, 0x31, 0x50, 0x6f, 0x4a, 0x4a, 0x66, 0x30, 0x63, 0x34, 0x70, 0x2f, 0x48, 0x37, +0x78, 0x5a, 0x4a, 0x2b, 0x59, 0x51, 0x33, 0x50, 0x4a, 0x75, 0x4e, 0x2b, 0x77, 0x52, 0x38, 0x30, +0x31, 0x73, 0x4c, 0x73, 0x6d, 0x65, 0x69, 0x64, 0x45, 0x45, 0x31, 0x43, 0x4e, 0x33, 0x31, 0x4e, +0x2f, 0x58, 0x44, 0x6e, 0x73, 0x41, 0x35, 0x39, 0x74, 0x47, 0x7a, 0x42, 0x38, 0x65, 0x41, 0x61, +0x74, 0x72, 0x32, 0x58, 0x71, 0x79, 0x52, 0x41, 0x45, 0x69, 0x55, 0x50, 0x51, 0x59, 0x70, 0x39, +0x79, 0x68, 0x48, 0x50, 0x4c, 0x65, 0x5a, 0x6d, 0x69, 0x73, 0x51, 0x38, 0x78, 0x78, 0x6b, 0x33, +0x67, 0x4d, 0x54, 0x76, 0x30, 0x73, 0x70, 0x64, 0x31, 0x6d, 0x70, 0x4f, 0x32, 0x4c, 0x6a, 0x4b, +0x68, 0x50, 0x50, 0x4d, 0x72, 0x4b, 0x2f, 0x68, 0x65, 0x6b, 0x32, 0x4a, 0x53, 0x56, 0x5a, 0x2b, +0x6f, 0x79, 0x46, 0x4d, 0x43, 0x65, 0x35, 0x4f, 0x45, 0x6b, 0x5a, 0x75, 0x41, 0x51, 0x68, 0x66, +0x50, 0x76, 0x79, 0x66, 0x63, 0x34, 0x72, 0x6e, 0x71, 0x64, 0x78, 0x68, 0x66, 0x33, 0x6e, 0x6a, +0x69, 0x39, 0x66, 0x69, 0x4d, 0x67, 0x57, 0x68, 0x47, 0x4a, 0x45, 0x41, 0x6f, 0x37, 0x35, 0x31, +0x48, 0x77, 0x56, 0x2b, 0x48, 0x37, 0x73, 0x58, 0x4a, 0x34, 0x37, 0x63, 0x69, 0x32, 0x37, 0x47, +0x47, 0x37, 0x6f, 0x57, 0x66, 0x45, 0x77, 0x51, 0x68, 0x75, 0x63, 0x33, 0x48, 0x73, 0x6e, 0x48, +0x46, 0x65, 0x75, 0x61, 0x76, 0x4d, 0x38, 0x67, 0x4e, 0x58, 0x64, 0x68, 0x51, 0x38, 0x66, 0x69, +0x64, 0x5a, 0x2f, 0x47, 0x74, 0x4d, 0x2b, 0x2f, 0x6b, 0x30, 0x46, 0x50, 0x76, 0x51, 0x43, 0x72, +0x4e, 0x66, 0x54, 0x64, 0x50, 0x35, 0x70, 0x45, 0x37, 0x7a, 0x67, 0x50, 0x67, 0x6b, 0x59, 0x2f, +0x61, 0x4f, 0x48, 0x62, 0x72, 0x42, 0x6c, 0x37, 0x38, 0x72, 0x43, 0x4e, 0x4e, 0x34, 0x2f, 0x5a, +0x31, 0x39, 0x41, 0x76, 0x4f, 0x50, 0x48, 0x42, 0x71, 0x64, 0x68, 0x45, 0x55, 0x4f, 0x70, 0x42, +0x75, 0x44, 0x30, 0x46, 0x66, 0x2b, 0x69, 0x33, 0x72, 0x6a, 0x34, 0x52, 0x4d, 0x56, 0x50, 0x66, +0x75, 0x50, 0x31, 0x6c, 0x71, 0x54, 0x39, 0x48, 0x30, 0x50, 0x4b, 0x2f, 0x52, 0x6b, 0x53, 0x53, +0x6f, 0x31, 0x56, 0x67, 0x6c, 0x30, 0x47, 0x74, 0x55, 0x36, 0x6e, 0x31, 0x50, 0x51, 0x6e, 0x47, +0x4a, 0x41, 0x44, 0x41, 0x65, 0x42, 0x2b, 0x46, 0x6e, 0x65, 0x67, 0x44, 0x6d, 0x46, 0x33, 0x77, +0x56, 0x6c, 0x42, 0x67, 0x6a, 0x55, 0x51, 0x4a, 0x34, 0x36, 0x43, 0x48, 0x59, 0x61, 0x53, 0x64, +0x73, 0x76, 0x74, 0x66, 0x4e, 0x67, 0x33, 0x55, 0x5a, 0x6d, 0x74, 0x4e, 0x54, 0x2b, 0x36, 0x73, +0x31, 0x68, 0x57, 0x7a, 0x48, 0x78, 0x68, 0x42, 0x55, 0x56, 0x53, 0x4f, 0x65, 0x65, 0x49, 0x78, +0x73, 0x66, 0x58, 0x30, 0x39, 0x56, 0x31, 0x35, 0x35, 0x4a, 0x63, 0x75, 0x58, 0x4c, 0x30, 0x2b, +0x52, 0x64, 0x4c, 0x49, 0x6f, 0x49, 0x59, 0x63, 0x51, 0x45, 0x69, 0x6c, 0x46, 0x76, 0x77, 0x77, +0x39, 0x6f, 0x30, 0x61, 0x4e, 0x59, 0x74, 0x61, 0x73, 0x57, 0x65, 0x68, 0x31, 0x36, 0x77, 0x6a, +0x2b, 0x38, 0x68, 0x66, 0x34, 0x2b, 0x63, 0x2b, 0x78, 0x35, 0x35, 0x35, 0x62, 0x67, 0x4e, 0x4a, +0x75, 0x59, 0x75, 0x58, 0x76, 0x43, 0x32, 0x56, 0x31, 0x58, 0x6c, 0x7a, 0x72, 0x49, 0x30, 0x75, +0x57, 0x43, 0x5a, 0x75, 0x74, 0x5a, 0x6d, 0x52, 0x35, 0x41, 0x7a, 0x55, 0x64, 0x41, 0x65, 0x38, +0x73, 0x65, 0x70, 0x31, 0x38, 0x64, 0x35, 0x36, 0x4a, 0x7a, 0x64, 0x76, 0x51, 0x50, 0x4c, 0x71, +0x47, 0x72, 0x62, 0x64, 0x64, 0x77, 0x73, 0x75, 0x76, 0x62, 0x65, 0x36, 0x68, 0x78, 0x41, 0x48, +0x67, 0x2f, 0x67, 0x55, 0x6e, 0x31, 0x54, 0x62, 0x69, 0x32, 0x4b, 0x6c, 0x32, 0x76, 0x37, 0x36, +0x48, 0x62, 0x45, 0x30, 0x56, 0x51, 0x58, 0x55, 0x39, 0x74, 0x71, 0x77, 0x43, 0x2f, 0x65, 0x44, +0x44, 0x64, 0x48, 0x32, 0x78, 0x6c, 0x4b, 0x46, 0x50, 0x50, 0x6f, 0x6e, 0x4a, 0x78, 0x78, 0x44, +0x6b, 0x43, 0x55, 0x53, 0x4d, 0x41, 0x74, 0x70, 0x76, 0x57, 0x30, 0x74, 0x6a, 0x52, 0x66, 0x48, +0x47, 0x49, 0x6e, 0x63, 0x45, 0x53, 0x68, 0x52, 0x74, 0x48, 0x69, 0x6b, 0x67, 0x34, 0x46, 0x49, +0x6b, 0x58, 0x48, 0x57, 0x4d, 0x2f, 0x4c, 0x67, 0x48, 0x2f, 0x67, 0x79, 0x66, 0x6d, 0x46, 0x32, +0x5a, 0x2f, 0x74, 0x6b, 0x47, 0x76, 0x6a, 0x76, 0x71, 0x43, 0x59, 0x79, 0x53, 0x6e, 0x4e, 0x4c, +0x36, 0x4c, 0x45, 0x63, 0x4f, 0x4f, 0x67, 0x74, 0x32, 0x31, 0x34, 0x68, 0x33, 0x51, 0x6a, 0x51, +0x68, 0x6c, 0x53, 0x35, 0x69, 0x44, 0x74, 0x2b, 0x74, 0x68, 0x50, 0x76, 0x79, 0x7a, 0x47, 0x34, +0x2f, 0x6e, 0x55, 0x4e, 0x2f, 0x2b, 0x30, 0x74, 0x57, 0x62, 0x4f, 0x76, 0x47, 0x49, 0x5a, 0x50, +0x78, 0x77, 0x72, 0x63, 0x34, 0x4b, 0x36, 0x33, 0x66, 0x75, 0x4e, 0x47, 0x66, 0x65, 0x42, 0x30, +0x42, 0x64, 0x33, 0x56, 0x31, 0x51, 0x5a, 0x57, 0x48, 0x55, 0x68, 0x66, 0x39, 0x69, 0x59, 0x6f, +0x32, 0x6b, 0x6e, 0x4f, 0x47, 0x53, 0x67, 0x36, 0x75, 0x4c, 0x52, 0x5a, 0x65, 0x41, 0x76, 0x75, +0x4d, 0x78, 0x50, 0x35, 0x55, 0x59, 0x4f, 0x4d, 0x2b, 0x55, 0x47, 0x67, 0x6f, 0x72, 0x50, 0x7a, +0x46, 0x39, 0x54, 0x2f, 0x7a, 0x6a, 0x48, 0x74, 0x32, 0x35, 0x70, 0x6d, 0x62, 0x46, 0x41, 0x43, +0x75, 0x76, 0x44, 0x65, 0x5a, 0x6b, 0x6f, 0x78, 0x44, 0x6d, 0x32, 0x41, 0x36, 0x55, 0x59, 0x53, +0x45, 0x6c, 0x4e, 0x59, 0x4a, 0x67, 0x4b, 0x58, 0x62, 0x48, 0x30, 0x43, 0x63, 0x71, 0x2b, 0x54, +0x78, 0x46, 0x66, 0x58, 0x73, 0x6b, 0x68, 0x31, 0x4d, 0x71, 0x44, 0x55, 0x7a, 0x75, 0x6b, 0x65, +0x79, 0x2f, 0x34, 0x67, 0x61, 0x56, 0x6d, 0x35, 0x59, 0x6a, 0x78, 0x42, 0x74, 0x6d, 0x46, 0x42, +0x7a, 0x78, 0x42, 0x6c, 0x33, 0x2b, 0x6c, 0x43, 0x7a, 0x51, 0x6b, 0x72, 0x4e, 0x53, 0x52, 0x66, +0x2f, 0x46, 0x74, 0x42, 0x51, 0x30, 0x55, 0x43, 0x48, 0x4b, 0x75, 0x4f, 0x36, 0x56, 0x7a, 0x61, +0x69, 0x4c, 0x4b, 0x6a, 0x79, 0x43, 0x6c, 0x53, 0x43, 0x5a, 0x66, 0x67, 0x61, 0x41, 0x5a, 0x41, +0x63, 0x4b, 0x52, 0x54, 0x61, 0x4b, 0x46, 0x54, 0x67, 0x31, 0x66, 0x52, 0x41, 0x59, 0x71, 0x2f, +0x31, 0x71, 0x2b, 0x38, 0x55, 0x34, 0x61, 0x44, 0x67, 0x41, 0x30, 0x43, 0x68, 0x41, 0x55, 0x79, +0x37, 0x5a, 0x74, 0x32, 0x6c, 0x43, 0x71, 0x79, 0x69, 0x63, 0x68, 0x64, 0x46, 0x64, 0x72, 0x77, +0x6b, 0x2f, 0x34, 0x59, 0x6b, 0x2f, 0x37, 0x6f, 0x73, 0x78, 0x4e, 0x2b, 0x4c, 0x36, 0x44, 0x38, +0x4a, 0x6c, 0x79, 0x70, 0x50, 0x2f, 0x79, 0x51, 0x37, 0x2f, 0x77, 0x4a, 0x6e, 0x71, 0x31, 0x74, +0x38, 0x2f, 0x63, 0x6b, 0x69, 0x46, 0x50, 0x6a, 0x35, 0x51, 0x32, 0x49, 0x70, 0x71, 0x74, 0x2f, +0x41, 0x36, 0x74, 0x4e, 0x4f, 0x6f, 0x2b, 0x48, 0x4b, 0x4b, 0x39, 0x48, 0x4c, 0x6c, 0x2f, 0x75, +0x49, 0x53, 0x34, 0x48, 0x2f, 0x6b, 0x50, 0x33, 0x72, 0x54, 0x36, 0x36, 0x5a, 0x55, 0x61, 0x4e, +0x59, 0x4e, 0x47, 0x75, 0x57, 0x55, 0x34, 0x44, 0x36, 0x51, 0x6d, 0x6d, 0x6c, 0x4b, 0x6a, 0x42, +0x36, 0x77, 0x76, 0x52, 0x4a, 0x53, 0x71, 0x37, 0x6b, 0x65, 0x51, 0x72, 0x46, 0x62, 0x57, 0x71, +0x43, 0x6e, 0x68, 0x37, 0x73, 0x6d, 0x57, 0x66, 0x36, 0x53, 0x6e, 0x30, 0x44, 0x42, 0x6f, 0x44, +0x79, 0x44, 0x67, 0x52, 0x6c, 0x52, 0x5a, 0x6d, 0x69, 0x4e, 0x46, 0x6f, 0x77, 0x63, 0x73, 0x78, +0x71, 0x47, 0x6d, 0x77, 0x7a, 0x75, 0x5a, 0x6f, 0x68, 0x52, 0x43, 0x73, 0x55, 0x74, 0x6d, 0x73, +0x31, 0x7a, 0x62, 0x73, 0x64, 0x6a, 0x51, 0x4b, 0x61, 0x78, 0x79, 0x31, 0x45, 0x76, 0x6a, 0x7a, +0x65, 0x49, 0x52, 0x45, 0x54, 0x48, 0x45, 0x49, 0x55, 0x59, 0x54, 0x78, 0x38, 0x31, 0x33, 0x68, +0x6d, 0x59, 0x64, 0x77, 0x6f, 0x37, 0x41, 0x63, 0x66, 0x59, 0x4d, 0x74, 0x71, 0x43, 0x4c, 0x6f, +0x6a, 0x77, 0x6f, 0x35, 0x56, 0x5a, 0x4c, 0x62, 0x59, 0x30, 0x74, 0x6c, 0x45, 0x63, 0x5a, 0x34, +0x77, 0x57, 0x34, 0x6b, 0x52, 0x4c, 0x71, 0x6c, 0x6d, 0x37, 0x55, 0x57, 0x4e, 0x73, 0x48, 0x6c, +0x58, 0x50, 0x38, 0x4b, 0x32, 0x55, 0x4a, 0x53, 0x54, 0x72, 0x51, 0x6a, 0x46, 0x6c, 0x59, 0x41, +0x35, 0x51, 0x6b, 0x58, 0x48, 0x6d, 0x32, 0x56, 0x6f, 0x41, 0x59, 0x39, 0x38, 0x66, 0x67, 0x68, +0x47, 0x53, 0x65, 0x49, 0x34, 0x34, 0x50, 0x46, 0x74, 0x57, 0x32, 0x41, 0x50, 0x68, 0x58, 0x34, +0x37, 0x52, 0x42, 0x46, 0x53, 0x6e, 0x6a, 0x44, 0x2b, 0x57, 0x52, 0x56, 0x77, 0x62, 0x35, 0x36, +0x58, 0x4e, 0x31, 0x37, 0x41, 0x4c, 0x32, 0x63, 0x65, 0x52, 0x30, 0x74, 0x6c, 0x42, 0x74, 0x54, +0x6e, 0x6e, 0x50, 0x50, 0x36, 0x4f, 0x56, 0x77, 0x38, 0x36, 0x57, 0x4c, 0x61, 0x34, 0x2f, 0x5a, +0x55, 0x68, 0x64, 0x65, 0x68, 0x51, 0x52, 0x76, 0x46, 0x5a, 0x44, 0x39, 0x57, 0x39, 0x79, 0x32, +0x38, 0x44, 0x32, 0x55, 0x30, 0x52, 0x75, 0x69, 0x55, 0x32, 0x51, 0x65, 0x56, 0x44, 0x2b, 0x4c, +0x79, 0x35, 0x79, 0x2b, 0x48, 0x59, 0x79, 0x6c, 0x41, 0x6b, 0x58, 0x33, 0x49, 0x36, 0x35, 0x77, +0x6d, 0x79, 0x53, 0x47, 0x31, 0x66, 0x59, 0x42, 0x51, 0x66, 0x35, 0x58, 0x59, 0x61, 0x77, 0x55, +0x32, 0x36, 0x6a, 0x50, 0x2b, 0x41, 0x4e, 0x34, 0x38, 0x32, 0x70, 0x54, 0x32, 0x6c, 0x7a, 0x44, +0x36, 0x67, 0x49, 0x63, 0x69, 0x58, 0x66, 0x6c, 0x64, 0x74, 0x71, 0x52, 0x2f, 0x54, 0x51, 0x41, +0x6f, 0x37, 0x52, 0x78, 0x33, 0x62, 0x61, 0x2f, 0x4d, 0x35, 0x74, 0x47, 0x4a, 0x49, 0x31, 0x6d, +0x38, 0x76, 0x70, 0x50, 0x75, 0x58, 0x6a, 0x44, 0x4b, 0x38, 0x73, 0x6d, 0x4b, 0x54, 0x31, 0x6e, +0x51, 0x57, 0x4d, 0x50, 0x34, 0x4f, 0x45, 0x4a, 0x49, 0x78, 0x54, 0x4d, 0x50, 0x6e, 0x73, 0x50, +0x42, 0x70, 0x39, 0x37, 0x68, 0x61, 0x46, 0x4e, 0x71, 0x42, 0x32, 0x57, 0x57, 0x68, 0x74, 0x64, +0x66, 0x66, 0x35, 0x32, 0x39, 0x66, 0x37, 0x53, 0x49, 0x73, 0x4c, 0x4f, 0x53, 0x54, 0x45, 0x65, +0x45, 0x30, 0x5a, 0x62, 0x51, 0x47, 0x45, 0x52, 0x64, 0x4a, 0x54, 0x61, 0x66, 0x37, 0x36, 0x38, +0x47, 0x46, 0x34, 0x4f, 0x75, 0x77, 0x68, 0x43, 0x7a, 0x66, 0x6a, 0x30, 0x6c, 0x55, 0x47, 0x69, +0x72, 0x55, 0x50, 0x68, 0x56, 0x2f, 0x77, 0x63, 0x43, 0x4f, 0x39, 0x51, 0x7a, 0x34, 0x6c, 0x53, +0x42, 0x76, 0x61, 0x46, 0x55, 0x6b, 0x79, 0x4a, 0x51, 0x71, 0x51, 0x6c, 0x67, 0x59, 0x70, 0x33, +0x61, 0x2b, 0x50, 0x6c, 0x33, 0x46, 0x46, 0x52, 0x4b, 0x75, 0x70, 0x34, 0x75, 0x30, 0x48, 0x2b, +0x43, 0x68, 0x61, 0x41, 0x59, 0x48, 0x2b, 0x47, 0x42, 0x56, 0x49, 0x32, 0x6e, 0x76, 0x38, 0x55, +0x56, 0x4e, 0x34, 0x31, 0x6d, 0x32, 0x52, 0x71, 0x52, 0x77, 0x6e, 0x59, 0x54, 0x44, 0x54, 0x65, +0x35, 0x46, 0x39, 0x49, 0x68, 0x5a, 0x30, 0x58, 0x79, 0x57, 0x57, 0x6e, 0x47, 0x4e, 0x4a, 0x66, +0x7a, 0x39, 0x39, 0x76, 0x66, 0x34, 0x58, 0x50, 0x4f, 0x49, 0x4d, 0x6d, 0x71, 0x62, 0x54, 0x79, +0x55, 0x76, 0x53, 0x2f, 0x2f, 0x6c, 0x54, 0x42, 0x2f, 0x73, 0x68, 0x6c, 0x49, 0x46, 0x53, 0x55, +0x46, 0x37, 0x51, 0x75, 0x6c, 0x64, 0x59, 0x7a, 0x76, 0x30, 0x6d, 0x7a, 0x33, 0x79, 0x38, 0x31, +0x58, 0x4a, 0x42, 0x67, 0x41, 0x57, 0x4c, 0x63, 0x4f, 0x2b, 0x39, 0x52, 0x54, 0x32, 0x4e, 0x76, +0x76, 0x77, 0x4a, 0x35, 0x78, 0x6d, 0x6b, 0x39, 0x77, 0x6d, 0x61, 0x7a, 0x36, 0x73, 0x74, 0x2f, +0x4b, 0x33, 0x78, 0x66, 0x4b, 0x69, 0x6e, 0x44, 0x70, 0x73, 0x70, 0x4c, 0x73, 0x70, 0x36, 0x74, +0x58, 0x4e, 0x4e, 0x43, 0x31, 0x62, 0x54, 0x76, 0x56, 0x30, 0x57, 0x41, 0x36, 0x79, 0x35, 0x76, +0x59, 0x30, 0x46, 0x58, 0x42, 0x2b, 0x73, 0x34, 0x4e, 0x78, 0x50, 0x55, 0x39, 0x74, 0x4b, 0x32, +0x73, 0x52, 0x51, 0x71, 0x62, 0x4f, 0x67, 0x48, 0x42, 0x6f, 0x4b, 0x49, 0x6f, 0x6c, 0x58, 0x67, +0x6d, 0x64, 0x70, 0x6c, 0x6e, 0x61, 0x38, 0x34, 0x38, 0x6b, 0x77, 0x33, 0x4c, 0x6c, 0x70, 0x50, +0x39, 0x59, 0x67, 0x33, 0x57, 0x53, 0x48, 0x6f, 0x48, 0x44, 0x32, 0x58, 0x77, 0x6c, 0x43, 0x6c, +0x59, 0x61, 0x35, 0x46, 0x52, 0x52, 0x43, 0x34, 0x72, 0x30, 0x4d, 0x4b, 0x5a, 0x41, 0x4a, 0x32, +0x33, 0x72, 0x32, 0x64, 0x51, 0x62, 0x6d, 0x67, 0x2f, 0x75, 0x67, 0x35, 0x56, 0x33, 0x72, 0x2b, +0x33, 0x61, 0x4f, 0x55, 0x76, 0x2b, 0x68, 0x7a, 0x55, 0x53, 0x75, 0x6f, 0x2f, 0x36, 0x63, 0x58, +0x38, 0x58, 0x6e, 0x48, 0x38, 0x38, 0x4a, 0x6e, 0x73, 0x56, 0x58, 0x6b, 0x69, 0x37, 0x4a, 0x48, +0x42, 0x76, 0x68, 0x30, 0x69, 0x43, 0x63, 0x6b, 0x52, 0x4f, 0x74, 0x76, 0x73, 0x37, 0x41, 0x72, +0x34, 0x54, 0x5a, 0x35, 0x58, 0x32, 0x69, 0x2f, 0x6b, 0x6c, 0x33, 0x38, 0x39, 0x33, 0x6a, 0x73, +0x46, 0x6e, 0x57, 0x4d, 0x51, 0x4b, 0x33, 0x6c, 0x2b, 0x35, 0x76, 0x4e, 0x4d, 0x47, 0x44, 0x4f, +0x42, 0x70, 0x64, 0x31, 0x4c, 0x53, 0x36, 0x48, 0x49, 0x57, 0x6e, 0x43, 0x79, 0x48, 0x37, 0x2b, +0x37, 0x33, 0x72, 0x73, 0x72, 0x52, 0x53, 0x45, 0x6d, 0x2f, 0x34, 0x77, 0x30, 0x74, 0x6e, 0x34, +0x73, 0x33, 0x55, 0x39, 0x33, 0x77, 0x7a, 0x47, 0x67, 0x62, 0x51, 0x48, 0x4b, 0x65, 0x2b, 0x59, +0x51, 0x78, 0x57, 0x46, 0x31, 0x52, 0x55, 0x4c, 0x4c, 0x43, 0x75, 0x78, 0x4c, 0x45, 0x76, 0x73, +0x6a, 0x67, 0x65, 0x30, 0x5a, 0x59, 0x50, 0x7a, 0x42, 0x35, 0x56, 0x43, 0x30, 0x64, 0x70, 0x4e, +0x5a, 0x63, 0x65, 0x6e, 0x70, 0x2b, 0x55, 0x6f, 0x42, 0x6b, 0x4f, 0x51, 0x62, 0x74, 0x45, 0x61, +0x34, 0x33, 0x58, 0x66, 0x2f, 0x69, 0x67, 0x62, 0x67, 0x54, 0x59, 0x42, 0x48, 0x6c, 0x37, 0x55, +0x78, 0x4c, 0x6a, 0x41, 0x6f, 0x4b, 0x5a, 0x6b, 0x66, 0x5a, 0x4a, 0x45, 0x2b, 0x33, 0x66, 0x76, +0x79, 0x46, 0x52, 0x74, 0x59, 0x4a, 0x42, 0x58, 0x5a, 0x38, 0x6a, 0x6f, 0x4f, 0x6e, 0x6e, 0x77, +0x37, 0x55, 0x6d, 0x75, 0x45, 0x56, 0x43, 0x69, 0x70, 0x55, 0x63, 0x72, 0x46, 0x34, 0x2f, 0x66, +0x65, 0x65, 0x32, 0x38, 0x58, 0x6d, 0x64, 0x76, 0x2b, 0x59, 0x75, 0x7a, 0x53, 0x70, 0x61, 0x52, +0x5a, 0x70, 0x61, 0x58, 0x45, 0x2f, 0x75, 0x5a, 0x72, 0x36, 0x47, 0x2f, 0x73, 0x57, 0x4d, 0x79, +0x37, 0x37, 0x38, 0x49, 0x31, 0x66, 0x61, 0x44, 0x51, 0x67, 0x63, 0x63, 0x74, 0x58, 0x43, 0x4f, +0x77, 0x4e, 0x2f, 0x76, 0x78, 0x75, 0x31, 0x78, 0x69, 0x71, 0x30, 0x73, 0x31, 0x67, 0x4d, 0x44, +0x4b, 0x56, 0x41, 0x41, 0x6b, 0x69, 0x55, 0x4f, 0x52, 0x41, 0x74, 0x32, 0x72, 0x36, 0x48, 0x79, +0x71, 0x51, 0x50, 0x38, 0x4a, 0x77, 0x39, 0x73, 0x2b, 0x56, 0x35, 0x4f, 0x4d, 0x66, 0x35, 0x52, +0x45, 0x42, 0x79, 0x33, 0x43, 0x5a, 0x33, 0x51, 0x57, 0x6e, 0x72, 0x36, 0x46, 0x74, 0x4b, 0x6b, +0x77, 0x45, 0x4e, 0x49, 0x6c, 0x54, 0x69, 0x30, 0x57, 0x45, 0x4d, 0x37, 0x74, 0x43, 0x38, 0x62, +0x6e, 0x69, 0x48, 0x52, 0x41, 0x6e, 0x31, 0x4c, 0x2b, 0x36, 0x37, 0x76, 0x79, 0x46, 0x35, 0x73, +0x67, 0x42, 0x73, 0x68, 0x75, 0x32, 0x4c, 0x43, 0x4a, 0x72, 0x4c, 0x42, 0x66, 0x6f, 0x7a, 0x34, +0x46, 0x51, 0x63, 0x42, 0x6e, 0x6e, 0x33, 0x32, 0x47, 0x4f, 0x66, 0x77, 0x59, 0x37, 0x43, 0x73, +0x7a, 0x36, 0x54, 0x6e, 0x33, 0x44, 0x45, 0x34, 0x35, 0x56, 0x37, 0x6b, 0x4e, 0x4c, 0x78, 0x34, +0x31, 0x35, 0x77, 0x6a, 0x57, 0x77, 0x57, 0x6f, 0x54, 0x68, 0x46, 0x32, 0x53, 0x30, 0x47, 0x4e, +0x73, 0x76, 0x57, 0x4c, 0x32, 0x4e, 0x4b, 0x44, 0x54, 0x4d, 0x37, 0x39, 0x66, 0x31, 0x64, 0x2b, +0x66, 0x4f, 0x35, 0x4b, 0x64, 0x44, 0x6e, 0x73, 0x44, 0x46, 0x57, 0x58, 0x5a, 0x65, 0x34, 0x64, +0x78, 0x43, 0x47, 0x31, 0x59, 0x76, 0x48, 0x45, 0x52, 0x58, 0x58, 0x58, 0x72, 0x6d, 0x50, 0x58, +0x4b, 0x4a, 0x49, 0x54, 0x53, 0x2f, 0x67, 0x38, 0x6a, 0x51, 0x7a, 0x63, 0x41, 0x33, 0x64, 0x32, +0x65, 0x2b, 0x64, 0x33, 0x66, 0x66, 0x78, 0x6c, 0x6a, 0x6f, 0x4b, 0x4b, 0x43, 0x2b, 0x6d, 0x75, +0x76, 0x4a, 0x66, 0x2f, 0x53, 0x69, 0x77, 0x54, 0x6c, 0x46, 0x51, 0x7a, 0x65, 0x62, 0x54, 0x65, +0x43, 0x69, 0x67, 0x6f, 0x58, 0x77, 0x6f, 0x74, 0x6a, 0x64, 0x4a, 0x6e, 0x62, 0x6b, 0x36, 0x36, +0x41, 0x36, 0x67, 0x73, 0x47, 0x45, 0x57, 0x39, 0x66, 0x47, 0x75, 0x42, 0x4e, 0x56, 0x6b, 0x35, +0x54, 0x35, 0x50, 0x46, 0x4e, 0x38, 0x65, 0x52, 0x57, 0x75, 0x54, 0x2b, 0x72, 0x51, 0x4c, 0x48, +0x68, 0x62, 0x7a, 0x6e, 0x73, 0x66, 0x6d, 0x58, 0x77, 0x6e, 0x53, 0x33, 0x67, 0x38, 0x54, 0x49, +0x30, 0x6b, 0x43, 0x46, 0x30, 0x59, 0x55, 0x76, 0x50, 0x2b, 0x4b, 0x39, 0x31, 0x58, 0x73, 0x51, +0x76, 0x58, 0x6e, 0x43, 0x4d, 0x54, 0x38, 0x4c, 0x38, 0x31, 0x6f, 0x44, 0x78, 0x54, 0x6c, 0x54, +0x56, 0x48, 0x34, 0x6f, 0x72, 0x6a, 0x50, 0x74, 0x73, 0x2f, 0x61, 0x37, 0x49, 0x6c, 0x50, 0x6d, +0x31, 0x51, 0x47, 0x59, 0x6c, 0x43, 0x6f, 0x58, 0x4f, 0x4b, 0x42, 0x63, 0x66, 0x4e, 0x59, 0x58, +0x79, 0x6b, 0x34, 0x63, 0x6f, 0x6a, 0x71, 0x37, 0x76, 0x67, 0x34, 0x42, 0x38, 0x53, 0x57, 0x4a, +0x2f, 0x4b, 0x4c, 0x44, 0x64, 0x73, 0x6b, 0x54, 0x37, 0x53, 0x71, 0x43, 0x38, 0x42, 0x67, 0x69, +0x69, 0x43, 0x48, 0x76, 0x6b, 0x6b, 0x65, 0x37, 0x35, 0x63, 0x38, 0x38, 0x56, 0x35, 0x6e, 0x71, +0x33, 0x33, 0x55, 0x6f, 0x64, 0x74, 0x67, 0x4d, 0x63, 0x52, 0x6b, 0x48, 0x67, 0x64, 0x34, 0x6d, +0x36, 0x72, 0x62, 0x65, 0x62, 0x56, 0x72, 0x38, 0x54, 0x64, 0x46, 0x34, 0x43, 0x7a, 0x48, 0x48, +0x71, 0x72, 0x30, 0x42, 0x72, 0x76, 0x36, 0x6f, 0x72, 0x6b, 0x36, 0x37, 0x77, 0x4c, 0x73, 0x6d, +0x73, 0x51, 0x76, 0x69, 0x45, 0x73, 0x79, 0x38, 0x2f, 0x38, 0x6e, 0x33, 0x32, 0x50, 0x50, 0x62, +0x6e, 0x61, 0x51, 0x4c, 0x61, 0x4a, 0x2b, 0x34, 0x36, 0x69, 0x39, 0x71, 0x48, 0x4c, 0x33, 0x48, +0x74, 0x39, 0x34, 0x79, 0x56, 0x5a, 0x70, 0x55, 0x75, 0x5a, 0x76, 0x67, 0x42, 0x6d, 0x4c, 0x2b, +0x34, 0x2f, 0x2f, 0x33, 0x47, 0x50, 0x2f, 0x43, 0x2f, 0x6a, 0x51, 0x58, 0x32, 0x67, 0x71, 0x4c, +0x79, 0x75, 0x57, 0x4c, 0x31, 0x33, 0x30, 0x4e, 0x35, 0x66, 0x53, 0x67, 0x75, 0x56, 0x65, 0x33, +0x37, 0x31, 0x4a, 0x2b, 0x43, 0x6f, 0x66, 0x6f, 0x79, 0x76, 0x38, 0x63, 0x44, 0x4b, 0x43, 0x38, +0x41, 0x59, 0x67, 0x6c, 0x35, 0x34, 0x61, 0x4c, 0x46, 0x50, 0x6d, 0x4d, 0x33, 0x51, 0x70, 0x47, +0x6d, 0x32, 0x52, 0x65, 0x71, 0x38, 0x4e, 0x79, 0x35, 0x75, 0x67, 0x4b, 0x45, 0x44, 0x2f, 0x30, +0x4e, 0x75, 0x66, 0x46, 0x6e, 0x56, 0x4f, 0x78, 0x2f, 0x49, 0x4b, 0x61, 0x37, 0x4b, 0x37, 0x58, +0x76, 0x6b, 0x36, 0x73, 0x70, 0x73, 0x76, 0x6d, 0x54, 0x66, 0x34, 0x30, 0x79, 0x78, 0x6d, 0x4b, +0x4e, 0x4a, 0x71, 0x79, 0x72, 0x59, 0x2b, 0x51, 0x64, 0x74, 0x35, 0x4e, 0x74, 0x66, 0x4c, 0x65, +0x47, 0x47, 0x37, 0x61, 0x41, 0x46, 0x5a, 0x46, 0x4c, 0x58, 0x4e, 0x44, 0x58, 0x32, 0x35, 0x39, +0x63, 0x6c, 0x58, 0x46, 0x5a, 0x54, 0x4e, 0x77, 0x39, 0x62, 0x46, 0x59, 0x4a, 0x54, 0x37, 0x77, +0x30, 0x6d, 0x50, 0x6a, 0x5a, 0x70, 0x37, 0x45, 0x33, 0x58, 0x45, 0x2f, 0x30, 0x36, 0x2f, 0x2b, +0x68, 0x36, 0x2b, 0x38, 0x6e, 0x49, 0x76, 0x30, 0x47, 0x6d, 0x48, 0x51, 0x54, 0x54, 0x4f, 0x43, +0x76, 0x31, 0x6d, 0x32, 0x4a, 0x55, 0x59, 0x46, 0x44, 0x6d, 0x2f, 0x57, 0x45, 0x32, 0x68, 0x46, +0x77, 0x35, 0x4d, 0x4c, 0x62, 0x55, 0x72, 0x73, 0x4f, 0x39, 0x71, 0x69, 0x51, 0x32, 0x33, 0x36, +0x35, 0x46, 0x34, 0x63, 0x66, 0x2f, 0x77, 0x46, 0x31, 0x35, 0x52, 0x74, 0x52, 0x43, 0x74, 0x6f, +0x4a, 0x2b, 0x4f, 0x50, 0x31, 0x2b, 0x37, 0x46, 0x71, 0x67, 0x30, 0x4d, 0x6f, 0x4b, 0x68, 0x4f, +0x69, 0x74, 0x51, 0x74, 0x58, 0x71, 0x51, 0x30, 0x72, 0x30, 0x77, 0x6b, 0x7a, 0x52, 0x62, 0x6e, +0x70, 0x67, 0x31, 0x77, 0x5a, 0x37, 0x4c, 0x49, 0x7a, 0x59, 0x61, 0x34, 0x43, 0x79, 0x73, 0x74, +0x39, 0x6f, 0x68, 0x43, 0x44, 0x69, 0x66, 0x4b, 0x59, 0x58, 0x45, 0x79, 0x6f, 0x46, 0x41, 0x4c, +0x6f, 0x2f, 0x70, 0x38, 0x32, 0x6d, 0x69, 0x71, 0x62, 0x43, 0x73, 0x79, 0x66, 0x72, 0x76, 0x4a, +0x2b, 0x78, 0x66, 0x64, 0x65, 0x2f, 0x2f, 0x53, 0x35, 0x38, 0x76, 0x75, 0x31, 0x61, 0x78, 0x54, +0x42, 0x70, 0x37, 0x32, 0x38, 0x39, 0x39, 0x2b, 0x77, 0x49, 0x36, 0x73, 0x4c, 0x48, 0x4e, 0x47, +0x48, 0x38, 0x62, 0x2f, 0x75, 0x75, 0x50, 0x78, 0x4d, 0x4f, 0x47, 0x6d, 0x63, 0x6f, 0x6b, 0x63, +0x57, 0x34, 0x64, 0x67, 0x52, 0x6d, 0x4b, 0x4c, 0x4e, 0x53, 0x39, 0x50, 0x33, 0x39, 0x33, 0x68, +0x32, 0x4c, 0x54, 0x79, 0x2b, 0x58, 0x56, 0x4e, 0x54, 0x70, 0x72, 0x6e, 0x35, 0x51, 0x70, 0x69, +0x6c, 0x51, 0x47, 0x6e, 0x46, 0x74, 0x77, 0x64, 0x4c, 0x76, 0x74, 0x33, 0x51, 0x78, 0x2b, 0x61, +0x66, 0x37, 0x5a, 0x6d, 0x2f, 0x71, 0x34, 0x69, 0x51, 0x2b, 0x30, 0x42, 0x35, 0x44, 0x58, 0x32, +0x79, 0x4d, 0x68, 0x63, 0x7a, 0x72, 0x56, 0x63, 0x5a, 0x76, 0x38, 0x6f, 0x4a, 0x61, 0x42, 0x52, +0x6b, 0x2f, 0x4a, 0x35, 0x37, 0x45, 0x6b, 0x6a, 0x76, 0x56, 0x77, 0x67, 0x41, 0x35, 0x61, 0x47, +0x34, 0x79, 0x69, 0x5a, 0x43, 0x56, 0x7a, 0x6a, 0x47, 0x56, 0x77, 0x59, 0x6c, 0x33, 0x58, 0x38, +0x54, 0x46, 0x4e, 0x76, 0x36, 0x69, 0x54, 0x44, 0x59, 0x34, 0x39, 0x68, 0x62, 0x55, 0x46, 0x4c, +0x7a, 0x39, 0x74, 0x4e, 0x58, 0x73, 0x74, 0x31, 0x68, 0x50, 0x2b, 0x4f, 0x6f, 0x73, 0x2b, 0x34, +0x65, 0x75, 0x50, 0x31, 0x39, 0x54, 0x4d, 0x32, 0x76, 0x67, 0x7a, 0x4b, 0x58, 0x51, 0x4d, 0x47, +0x74, 0x52, 0x50, 0x49, 0x56, 0x35, 0x56, 0x4d, 0x42, 0x6f, 0x45, 0x6c, 0x51, 0x51, 0x63, 0x36, +0x4d, 0x56, 0x51, 0x55, 0x59, 0x64, 0x42, 0x39, 0x56, 0x4f, 0x39, 0x55, 0x41, 0x55, 0x69, 0x45, +0x68, 0x30, 0x30, 0x51, 0x6c, 0x41, 0x50, 0x50, 0x74, 0x48, 0x67, 0x78, 0x64, 0x63, 0x43, 0x46, +0x79, 0x79, 0x65, 0x63, 0x6b, 0x2f, 0x2f, 0x69, 0x55, 0x72, 0x4e, 0x51, 0x75, 0x6d, 0x55, 0x63, +0x69, 0x50, 0x41, 0x71, 0x5a, 0x66, 0x49, 0x78, 0x57, 0x35, 0x4d, 0x61, 0x4e, 0x34, 0x30, 0x50, +0x65, 0x4a, 0x58, 0x64, 0x70, 0x54, 0x4a, 0x6a, 0x4a, 0x45, 0x42, 0x68, 0x54, 0x69, 0x41, 0x44, +0x34, 0x30, 0x77, 0x77, 0x77, 0x42, 0x78, 0x6e, 0x72, 0x49, 0x67, 0x52, 0x42, 0x45, 0x46, 0x43, +0x31, 0x77, 0x34, 0x35, 0x6b, 0x55, 0x51, 0x5a, 0x6a, 0x51, 0x34, 0x62, 0x6d, 0x6b, 0x72, 0x41, +0x66, 0x61, 0x53, 0x5a, 0x57, 0x57, 0x5a, 0x53, 0x56, 0x4e, 0x63, 0x33, 0x57, 0x36, 0x72, 0x4f, +0x79, 0x4a, 0x76, 0x61, 0x37, 0x47, 0x64, 0x59, 0x45, 0x33, 0x5a, 0x32, 0x45, 0x50, 0x37, 0x71, +0x63, 0x6c, 0x71, 0x4e, 0x61, 0x42, 0x6f, 0x62, 0x53, 0x4a, 0x6c, 0x74, 0x4e, 0x69, 0x36, 0x47, +0x30, 0x56, 0x6a, 0x73, 0x41, 0x78, 0x74, 0x71, 0x31, 0x42, 0x4c, 0x32, 0x4e, 0x74, 0x46, 0x62, +0x36, 0x2f, 0x33, 0x64, 0x54, 0x46, 0x70, 0x48, 0x4a, 0x38, 0x76, 0x45, 0x6a, 0x45, 0x36, 0x69, +0x76, 0x37, 0x30, 0x5a, 0x72, 0x57, 0x4c, 0x4d, 0x2b, 0x52, 0x34, 0x4f, 0x31, 0x31, 0x4e, 0x64, +0x31, 0x75, 0x37, 0x71, 0x31, 0x52, 0x58, 0x56, 0x62, 0x59, 0x49, 0x6c, 0x62, 0x78, 0x57, 0x4a, +0x4a, 0x4d, 0x4c, 0x69, 0x42, 0x55, 0x4f, 0x63, 0x4a, 0x76, 0x44, 0x30, 0x4c, 0x55, 0x44, 0x35, +0x34, 0x69, 0x4e, 0x73, 0x31, 0x42, 0x6f, 0x52, 0x68, 0x53, 0x42, 0x41, 0x45, 0x6c, 0x49, 0x30, +0x5a, 0x53, 0x36, 0x5a, 0x68, 0x71, 0x50, 0x4d, 0x62, 0x41, 0x4a, 0x58, 0x6e, 0x31, 0x64, 0x4f, +0x37, 0x73, 0x38, 0x76, 0x4c, 0x56, 0x34, 0x6a, 0x78, 0x6c, 0x6d, 0x46, 0x74, 0x72, 0x6d, 0x42, +0x44, 0x47, 0x34, 0x6c, 0x46, 0x59, 0x52, 0x49, 0x50, 0x72, 0x58, 0x57, 0x5a, 0x64, 0x54, 0x65, +0x38, 0x55, 0x41, 0x36, 0x54, 0x38, 0x34, 0x51, 0x54, 0x68, 0x68, 0x50, 0x73, 0x31, 0x35, 0x34, +0x79, 0x2f, 0x71, 0x4e, 0x76, 0x6e, 0x67, 0x54, 0x41, 0x69, 0x42, 0x71, 0x2f, 0x72, 0x39, 0x34, +0x59, 0x72, 0x41, 0x6e, 0x64, 0x79, 0x6d, 0x39, 0x44, 0x72, 0x43, 0x32, 0x30, 0x38, 0x5a, 0x67, +0x4b, 0x32, 0x47, 0x61, 0x51, 0x77, 0x74, 0x71, 0x57, 0x6c, 0x4c, 0x69, 0x53, 0x65, 0x6d, 0x6c, +0x31, 0x71, 0x39, 0x55, 0x42, 0x4c, 0x55, 0x6d, 0x37, 0x48, 0x44, 0x59, 0x68, 0x49, 0x63, 0x43, +0x68, 0x65, 0x38, 0x50, 0x4f, 0x4b, 0x2b, 0x48, 0x67, 0x4f, 0x73, 0x56, 0x52, 0x39, 0x53, 0x31, +0x46, 0x78, 0x43, 0x6e, 0x68, 0x55, 0x30, 0x6c, 0x77, 0x6c, 0x34, 0x52, 0x68, 0x43, 0x67, 0x5a, +0x2f, 0x42, 0x52, 0x53, 0x5a, 0x50, 0x6c, 0x44, 0x6d, 0x30, 0x30, 0x35, 0x33, 0x49, 0x61, 0x55, +0x34, 0x49, 0x6d, 0x68, 0x74, 0x64, 0x61, 0x76, 0x6c, 0x56, 0x77, 0x6d, 0x41, 0x43, 0x45, 0x4b, +0x6a, 0x6f, 0x4c, 0x6f, 0x6c, 0x44, 0x5a, 0x38, 0x6d, 0x52, 0x34, 0x49, 0x70, 0x53, 0x49, 0x36, +0x78, 0x46, 0x57, 0x4d, 0x4c, 0x66, 0x67, 0x37, 0x72, 0x63, 0x2f, 0x63, 0x68, 0x6b, 0x45, 0x6f, +0x7a, 0x62, 0x45, 0x69, 0x74, 0x55, 0x2b, 0x32, 0x39, 0x69, 0x69, 0x2b, 0x31, 0x54, 0x7a, 0x66, +0x76, 0x4e, 0x51, 0x4f, 0x58, 0x6a, 0x73, 0x74, 0x77, 0x33, 0x4c, 0x6e, 0x33, 0x4d, 0x6e, 0x72, +0x6b, 0x45, 0x41, 0x38, 0x6c, 0x48, 0x36, 0x44, 0x39, 0x2f, 0x32, 0x35, 0x57, 0x33, 0x32, 0x49, +0x6f, 0x74, 0x4a, 0x45, 0x6f, 0x4e, 0x4f, 0x46, 0x77, 0x43, 0x54, 0x56, 0x39, 0x79, 0x74, 0x63, +0x6f, 0x6c, 0x36, 0x4b, 0x4d, 0x77, 0x76, 0x67, 0x62, 0x34, 0x31, 0x30, 0x67, 0x55, 0x70, 0x48, +0x78, 0x39, 0x59, 0x63, 0x44, 0x51, 0x4b, 0x47, 0x54, 0x32, 0x4c, 0x2f, 0x78, 0x39, 0x53, 0x63, +0x72, 0x73, 0x38, 0x4b, 0x74, 0x67, 0x52, 0x6b, 0x56, 0x45, 0x62, 0x59, 0x4d, 0x38, 0x56, 0x45, +0x48, 0x55, 0x63, 0x41, 0x4e, 0x4a, 0x4d, 0x37, 0x74, 0x52, 0x4d, 0x41, 0x70, 0x35, 0x66, 0x34, +0x42, 0x53, 0x43, 0x75, 0x73, 0x6a, 0x71, 0x67, 0x42, 0x4b, 0x73, 0x75, 0x6e, 0x38, 0x72, 0x50, +0x66, 0x6e, 0x6f, 0x54, 0x32, 0x47, 0x2b, 0x79, 0x53, 0x66, 0x54, 0x5a, 0x61, 0x4f, 0x36, 0x47, +0x71, 0x6a, 0x58, 0x61, 0x70, 0x36, 0x49, 0x33, 0x50, 0x53, 0x4f, 0x30, 0x7a, 0x56, 0x6c, 0x74, +0x72, 0x2b, 0x63, 0x4f, 0x4e, 0x56, 0x78, 0x49, 0x77, 0x73, 0x38, 0x63, 0x53, 0x6d, 0x56, 0x4b, +0x30, 0x6e, 0x36, 0x4b, 0x41, 0x2b, 0x6b, 0x74, 0x67, 0x67, 0x53, 0x55, 0x49, 0x51, 0x4a, 0x4e, +0x69, 0x4f, 0x58, 0x73, 0x6d, 0x31, 0x39, 0x44, 0x62, 0x4d, 0x6f, 0x79, 0x6c, 0x58, 0x37, 0x7a, +0x48, 0x4c, 0x6c, 0x4e, 0x33, 0x32, 0x58, 0x52, 0x57, 0x55, 0x69, 0x6a, 0x41, 0x4b, 0x34, 0x75, +0x6f, 0x61, 0x64, 0x30, 0x6e, 0x2f, 0x65, 0x47, 0x4b, 0x43, 0x74, 0x79, 0x66, 0x58, 0x76, 0x6a, +0x37, 0x43, 0x6e, 0x39, 0x53, 0x39, 0x4c, 0x76, 0x6b, 0x71, 0x43, 0x6b, 0x71, 0x31, 0x77, 0x6e, +0x55, 0x66, 0x76, 0x6f, 0x70, 0x6b, 0x62, 0x64, 0x70, 0x67, 0x66, 0x54, 0x2f, 0x33, 0x4d, 0x44, +0x74, 0x32, 0x6c, 0x71, 0x2b, 0x2f, 0x2f, 0x36, 0x4a, 0x35, 0x67, 0x7a, 0x41, 0x49, 0x61, 0x39, +0x4e, 0x41, 0x48, 0x78, 0x57, 0x6d, 0x44, 0x53, 0x6c, 0x6d, 0x4f, 0x6c, 0x33, 0x54, 0x54, 0x53, +0x4c, 0x35, 0x48, 0x50, 0x79, 0x7a, 0x75, 0x37, 0x4a, 0x65, 0x62, 0x4a, 0x6e, 0x77, 0x72, 0x52, +0x7a, 0x62, 0x6d, 0x44, 0x47, 0x52, 0x34, 0x63, 0x55, 0x47, 0x71, 0x5a, 0x69, 0x46, 0x78, 0x71, +0x54, 0x42, 0x68, 0x65, 0x76, 0x30, 0x55, 0x36, 0x4b, 0x59, 0x6b, 0x6f, 0x36, 0x38, 0x50, 0x64, +0x39, 0x6a, 0x69, 0x49, 0x4d, 0x6f, 0x62, 0x49, 0x53, 0x79, 0x73, 0x75, 0x68, 0x75, 0x73, 0x37, +0x39, 0x31, 0x42, 0x6a, 0x51, 0x34, 0x33, 0x78, 0x2f, 0x35, 0x36, 0x58, 0x5a, 0x72, 0x74, 0x4a, +0x72, 0x63, 0x6c, 0x78, 0x58, 0x43, 0x59, 0x2f, 0x30, 0x56, 0x68, 0x62, 0x51, 0x66, 0x58, 0x34, +0x77, 0x7a, 0x50, 0x35, 0x39, 0x55, 0x47, 0x78, 0x39, 0x7a, 0x75, 0x52, 0x6f, 0x33, 0x73, 0x52, +0x33, 0x41, 0x35, 0x55, 0x5a, 0x4f, 0x51, 0x41, 0x53, 0x73, 0x50, 0x66, 0x4b, 0x77, 0x4a, 0x70, +0x4f, 0x6a, 0x30, 0x79, 0x4c, 0x33, 0x4e, 0x6c, 0x2b, 0x79, 0x32, 0x4b, 0x55, 0x55, 0x69, 0x6b, +0x53, 0x4d, 0x4c, 0x6e, 0x66, 0x37, 0x71, 0x2f, 0x62, 0x46, 0x53, 0x70, 0x49, 0x71, 0x48, 0x2f, +0x4b, 0x44, 0x67, 0x79, 0x63, 0x62, 0x54, 0x4f, 0x35, 0x44, 0x6f, 0x53, 0x2f, 0x4c, 0x52, 0x77, +0x39, 0x2f, 0x30, 0x62, 0x37, 0x42, 0x2b, 0x72, 0x2f, 0x75, 0x43, 0x73, 0x6f, 0x51, 0x4b, 0x45, +0x39, 0x6e, 0x62, 0x37, 0x7a, 0x49, 0x49, 0x77, 0x64, 0x71, 0x4e, 0x79, 0x79, 0x41, 0x68, 0x73, +0x6b, 0x78, 0x39, 0x70, 0x78, 0x70, 0x65, 0x69, 0x2b, 0x76, 0x76, 0x65, 0x71, 0x71, 0x4c, 0x7a, +0x71, 0x38, 0x37, 0x34, 0x73, 0x73, 0x42, 0x65, 0x6c, 0x37, 0x4e, 0x48, 0x33, 0x74, 0x33, 0x33, +0x4c, 0x39, 0x4f, 0x33, 0x44, 0x49, 0x52, 0x52, 0x6a, 0x32, 0x59, 0x75, 0x5a, 0x62, 0x69, 0x41, +0x73, 0x75, 0x2b, 0x6a, 0x7a, 0x31, 0x70, 0x42, 0x67, 0x49, 0x64, 0x67, 0x4a, 0x2b, 0x7a, 0x38, +0x4b, 0x75, 0x52, 0x72, 0x63, 0x2f, 0x33, 0x6e, 0x6a, 0x70, 0x61, 0x55, 0x70, 0x53, 0x6b, 0x39, +0x73, 0x43, 0x6f, 0x61, 0x4a, 0x55, 0x4f, 0x34, 0x2f, 0x6e, 0x53, 0x50, 0x68, 0x4d, 0x71, 0x47, +0x65, 0x64, 0x48, 0x6e, 0x70, 0x6a, 0x4b, 0x52, 0x69, 0x4d, 0x61, 0x6d, 0x2f, 0x53, 0x49, 0x67, +0x49, 0x66, 0x30, 0x62, 0x4a, 0x50, 0x64, 0x42, 0x77, 0x39, 0x79, 0x4c, 0x65, 0x6d, 0x39, 0x74, +0x4d, 0x37, 0x57, 0x44, 0x46, 0x44, 0x71, 0x32, 0x77, 0x6f, 0x58, 0x2b, 0x57, 0x33, 0x55, 0x30, +0x63, 0x57, 0x57, 0x42, 0x31, 0x78, 0x2b, 0x78, 0x4c, 0x78, 0x2f, 0x66, 0x39, 0x77, 0x6b, 0x33, +0x51, 0x56, 0x32, 0x66, 0x6b, 0x54, 0x63, 0x34, 0x78, 0x31, 0x37, 0x62, 0x78, 0x38, 0x32, 0x4f, +0x47, 0x63, 0x50, 0x37, 0x42, 0x51, 0x34, 0x72, 0x4b, 0x6c, 0x35, 0x62, 0x62, 0x31, 0x44, 0x75, +0x55, 0x4d, 0x56, 0x78, 0x77, 0x33, 0x75, 0x6d, 0x67, 0x38, 0x36, 0x37, 0x53, 0x54, 0x4e, 0x62, +0x76, 0x70, 0x48, 0x54, 0x78, 0x32, 0x36, 0x2f, 0x77, 0x6e, 0x61, 0x66, 0x48, 0x44, 0x62, 0x2f, +0x2b, 0x69, 0x46, 0x2b, 0x2f, 0x42, 0x4b, 0x76, 0x62, 0x6f, 0x43, 0x4c, 0x6e, 0x32, 0x69, 0x30, +0x55, 0x42, 0x53, 0x69, 0x35, 0x33, 0x36, 0x43, 0x56, 0x70, 0x4d, 0x30, 0x57, 0x53, 0x51, 0x70, +0x74, 0x59, 0x63, 0x68, 0x6c, 0x59, 0x63, 0x45, 0x44, 0x67, 0x30, 0x70, 0x71, 0x4d, 0x55, 0x43, +0x44, 0x31, 0x70, 0x69, 0x31, 0x61, 0x32, 0x6e, 0x33, 0x41, 0x4a, 0x36, 0x42, 0x7a, 0x6f, 0x54, +0x6f, 0x4a, 0x74, 0x7a, 0x63, 0x64, 0x2f, 0x42, 0x49, 0x35, 0x30, 0x2b, 0x66, 0x42, 0x4a, 0x6b, +0x4a, 0x37, 0x6e, 0x38, 0x58, 0x79, 0x6e, 0x39, 0x59, 0x50, 0x69, 0x43, 0x61, 0x4e, 0x50, 0x50, +0x78, 0x77, 0x79, 0x58, 0x46, 0x64, 0x56, 0x45, 0x71, 0x37, 0x77, 0x33, 0x7a, 0x54, 0x71, 0x64, +0x4f, 0x74, 0x62, 0x4e, 0x6b, 0x55, 0x4f, 0x4d, 0x6d, 0x43, 0x66, 0x76, 0x45, 0x71, 0x34, 0x36, +0x6b, 0x50, 0x55, 0x6f, 0x52, 0x54, 0x51, 0x69, 0x6c, 0x69, 0x49, 0x52, 0x41, 0x52, 0x39, 0x31, +0x6b, 0x63, 0x6c, 0x55, 0x73, 0x2f, 0x73, 0x6d, 0x66, 0x79, 0x47, 0x58, 0x4b, 0x67, 0x41, 0x4a, +0x4d, 0x4f, 0x2f, 0x6c, 0x6e, 0x49, 0x57, 0x4d, 0x4d, 0x6d, 0x35, 0x6c, 0x76, 0x67, 0x65, 0x6b, +0x73, 0x6d, 0x58, 0x7a, 0x6a, 0x63, 0x36, 0x4d, 0x62, 0x42, 0x4d, 0x61, 0x49, 0x67, 0x6d, 0x42, +0x4d, 0x31, 0x6a, 0x46, 0x56, 0x59, 0x4f, 0x4a, 0x68, 0x4e, 0x37, 0x7a, 0x61, 0x76, 0x2f, 0x38, +0x4a, 0x76, 0x61, 0x70, 0x69, 0x2b, 0x6a, 0x65, 0x4f, 0x37, 0x6c, 0x4d, 0x65, 0x4d, 0x43, 0x41, +0x56, 0x47, 0x7a, 0x69, 0x6a, 0x33, 0x2f, 0x6a, 0x33, 0x76, 0x66, 0x59, 0x64, 0x39, 0x2b, 0x4c, +0x76, 0x74, 0x75, 0x4c, 0x2f, 0x66, 0x76, 0x77, 0x46, 0x32, 0x4b, 0x2b, 0x6a, 0x6f, 0x39, 0x39, +0x7a, 0x59, 0x38, 0x44, 0x30, 0x64, 0x76, 0x50, 0x42, 0x69, 0x42, 0x45, 0x59, 0x59, 0x50, 0x75, +0x46, 0x43, 0x36, 0x47, 0x75, 0x62, 0x6b, 0x41, 0x61, 0x7a, 0x6f, 0x34, 0x48, 0x4f, 0x76, 0x65, +0x61, 0x7a, 0x78, 0x2b, 0x32, 0x50, 0x4a, 0x72, 0x32, 0x36, 0x73, 0x45, 0x75, 0x62, 0x35, 0x32, +0x33, 0x2b, 0x52, 0x4e, 0x31, 0x51, 0x52, 0x6e, 0x72, 0x31, 0x54, 0x44, 0x76, 0x67, 0x54, 0x52, +0x4f, 0x7a, 0x58, 0x6a, 0x67, 0x77, 0x70, 0x63, 0x41, 0x75, 0x47, 0x6d, 0x79, 0x71, 0x31, 0x68, +0x62, 0x69, 0x2f, 0x56, 0x6d, 0x67, 0x7a, 0x59, 0x4f, 0x33, 0x4b, 0x4e, 0x4e, 0x67, 0x44, 0x49, +0x5a, 0x6c, 0x41, 0x6c, 0x4c, 0x2f, 0x76, 0x39, 0x4d, 0x61, 0x63, 0x75, 0x44, 0x55, 0x37, 0x76, +0x68, 0x76, 0x51, 0x58, 0x6a, 0x4e, 0x2b, 0x71, 0x48, 0x75, 0x65, 0x36, 0x75, 0x56, 0x37, 0x6e, +0x74, 0x6f, 0x6c, 0x74, 0x68, 0x34, 0x69, 0x36, 0x51, 0x7a, 0x5a, 0x53, 0x6b, 0x78, 0x66, 0x36, +0x4b, 0x59, 0x33, 0x77, 0x32, 0x6d, 0x2f, 0x32, 0x50, 0x73, 0x76, 0x49, 0x4f, 0x4d, 0x74, 0x33, +0x6b, 0x61, 0x6c, 0x76, 0x35, 0x35, 0x32, 0x72, 0x4e, 0x39, 0x6d, 0x4e, 0x71, 0x2f, 0x75, 0x33, +0x79, 0x55, 0x75, 0x61, 0x35, 0x37, 0x4c, 0x49, 0x70, 0x66, 0x75, 0x42, 0x39, 0x56, 0x6c, 0x6d, +0x74, 0x2f, 0x49, 0x35, 0x48, 0x6c, 0x55, 0x5a, 0x59, 0x58, 0x49, 0x6a, 0x56, 0x37, 0x79, 0x72, +0x30, 0x4f, 0x49, 0x75, 0x6e, 0x6e, 0x6e, 0x71, 0x43, 0x76, 0x62, 0x61, 0x45, 0x37, 0x55, 0x66, +0x44, 0x33, 0x43, 0x2f, 0x67, 0x69, 0x77, 0x30, 0x57, 0x48, 0x35, 0x58, 0x33, 0x4b, 0x34, 0x33, +0x31, 0x4a, 0x6c, 0x63, 0x47, 0x62, 0x55, 0x4b, 0x30, 0x74, 0x71, 0x54, 0x2f, 0x51, 0x4b, 0x54, +0x74, 0x2f, 0x37, 0x4c, 0x32, 0x33, 0x6e, 0x46, 0x53, 0x56, 0x4e, 0x6e, 0x37, 0x2f, 0x37, 0x75, +0x71, 0x65, 0x33, 0x4a, 0x67, 0x4d, 0x73, 0x4d, 0x4d, 0x51, 0x78, 0x49, 0x51, 0x45, 0x55, 0x55, +0x77, 0x52, 0x38, 0x53, 0x34, 0x78, 0x6b, 0x56, 0x58, 0x58, 0x62, 0x4f, 0x4c, 0x75, 0x75, 0x61, +0x77, 0x70, 0x6a, 0x57, 0x41, 0x61, 0x31, 0x79, 0x7a, 0x72, 0x71, 0x4a, 0x72, 0x57, 0x6e, 0x4e, +0x61, 0x2f, 0x61, 0x69, 0x73, 0x73, 0x69, 0x70, 0x47, 0x7a, 0x46, 0x6c, 0x41, 0x42, 0x41, 0x4f, +0x53, 0x30, 0x38, 0x44, 0x41, 0x77, 0x41, 0x77, 0x54, 0x65, 0x72, 0x72, 0x72, 0x70, 0x75, 0x38, +0x66, 0x39, 0x31, 0x5a, 0x31, 0x39, 0x38, 0x79, 0x41, 0x37, 0x73, 0x39, 0x66, 0x38, 0x61, 0x70, +0x58, 0x31, 0x54, 0x52, 0x64, 0x58, 0x56, 0x58, 0x33, 0x6e, 0x6e, 0x50, 0x76, 0x75, 0x65, 0x63, +0x38, 0x35, 0x7a, 0x6d, 0x63, 0x2f, 0x31, 0x41, 0x48, 0x47, 0x73, 0x68, 0x33, 0x55, 0x4e, 0x35, +0x77, 0x65, 0x76, 0x49, 0x38, 0x44, 0x37, 0x2b, 0x6b, 0x68, 0x4b, 0x4a, 0x4c, 0x4c, 0x30, 0x46, +0x33, 0x4a, 0x72, 0x4a, 0x4d, 0x79, 0x4d, 0x67, 0x63, 0x46, 0x59, 0x49, 0x6d, 0x78, 0x32, 0x70, +0x38, 0x77, 0x33, 0x34, 0x33, 0x32, 0x50, 0x35, 0x44, 0x59, 0x62, 0x52, 0x42, 0x47, 0x6f, 0x6e, +0x57, 0x42, 0x71, 0x70, 0x79, 0x75, 0x4f, 0x53, 0x53, 0x44, 0x63, 0x52, 0x69, 0x4d, 0x63, 0x36, +0x5a, 0x63, 0x49, 0x35, 0x62, 0x30, 0x6c, 0x6b, 0x6e, 0x72, 0x74, 0x53, 0x53, 0x35, 0x78, 0x39, +0x38, 0x48, 0x6f, 0x41, 0x70, 0x6b, 0x33, 0x64, 0x4d, 0x51, 0x31, 0x46, 0x56, 0x4b, 0x44, 0x2b, +0x61, 0x77, 0x6c, 0x7a, 0x77, 0x34, 0x6f, 0x56, 0x55, 0x2f, 0x2f, 0x6e, 0x50, 0x57, 0x61, 0x5a, +0x73, 0x43, 0x49, 0x6c, 0x64, 0x4e, 0x47, 0x30, 0x61, 0x7a, 0x59, 0x6c, 0x57, 0x62, 0x70, 0x6c, +0x77, 0x76, 0x6f, 0x57, 0x69, 0x68, 0x34, 0x7a, 0x51, 0x6a, 0x6d, 0x4a, 0x4c, 0x78, 0x32, 0x4e, +0x55, 0x39, 0x2b, 0x74, 0x6e, 0x51, 0x36, 0x6d, 0x39, 0x72, 0x47, 0x6d, 0x58, 0x4c, 0x31, 0x38, +0x4f, 0x65, 0x67, 0x4f, 0x78, 0x6d, 0x68, 0x74, 0x64, 0x72, 0x79, 0x6b, 0x77, 0x42, 0x74, 0x38, +0x6f, 0x43, 0x34, 0x68, 0x78, 0x79, 0x7a, 0x56, 0x6a, 0x51, 0x6d, 0x69, 0x33, 0x64, 0x48, 0x67, +0x46, 0x6a, 0x54, 0x47, 0x53, 0x31, 0x70, 0x39, 0x75, 0x42, 0x32, 0x44, 0x53, 0x2b, 0x63, 0x50, +0x53, 0x7a, 0x57, 0x66, 0x43, 0x43, 0x6b, 0x53, 0x6b, 0x43, 0x37, 0x30, 0x6f, 0x37, 0x66, 0x78, +0x55, 0x6d, 0x5a, 0x56, 0x37, 0x44, 0x4e, 0x50, 0x4f, 0x2f, 0x77, 0x51, 0x4e, 0x46, 0x47, 0x64, +0x41, 0x71, 0x51, 0x6d, 0x64, 0x63, 0x42, 0x6c, 0x6c, 0x78, 0x62, 0x71, 0x33, 0x75, 0x33, 0x48, +0x4c, 0x69, 0x6b, 0x62, 0x58, 0x2f, 0x74, 0x64, 0x63, 0x63, 0x30, 0x30, 0x6b, 0x50, 0x35, 0x6c, +0x57, 0x61, 0x46, 0x67, 0x46, 0x53, 0x79, 0x6b, 0x58, 0x70, 0x6e, 0x63, 0x68, 0x65, 0x69, 0x30, +0x6c, 0x4e, 0x33, 0x5a, 0x31, 0x55, 0x66, 0x4c, 0x71, 0x71, 0x77, 0x43, 0x55, 0x6c, 0x70, 0x62, +0x32, 0x6b, 0x48, 0x39, 0x64, 0x6b, 0x4d, 0x65, 0x57, 0x46, 0x31, 0x2b, 0x4d, 0x6c, 0x70, 0x4b, +0x4b, 0x75, 0x6a, 0x72, 0x49, 0x7a, 0x65, 0x30, 0x68, 0x76, 0x34, 0x32, 0x4e, 0x6a, 0x63, 0x51, +0x37, 0x67, 0x47, 0x49, 0x74, 0x4f, 0x65, 0x37, 0x64, 0x2b, 0x79, 0x67, 0x39, 0x39, 0x55, 0x2b, +0x49, 0x58, 0x66, 0x61, 0x77, 0x67, 0x71, 0x38, 0x4e, 0x78, 0x6f, 0x54, 0x67, 0x46, 0x48, 0x63, +0x52, 0x36, 0x55, 0x37, 0x77, 0x50, 0x49, 0x39, 0x72, 0x6a, 0x36, 0x68, 0x6c, 0x34, 0x47, 0x52, +0x37, 0x77, 0x38, 0x59, 0x32, 0x57, 0x39, 0x58, 0x46, 0x72, 0x68, 0x4c, 0x43, 0x6f, 0x70, 0x6f, +0x32, 0x64, 0x42, 0x45, 0x56, 0x50, 0x58, 0x54, 0x65, 0x2f, 0x6b, 0x41, 0x5a, 0x36, 0x76, 0x74, +0x34, 0x4c, 0x6e, 0x47, 0x6a, 0x64, 0x4d, 0x4f, 0x54, 0x30, 0x37, 0x36, 0x72, 0x2b, 0x48, 0x72, +0x6d, 0x4d, 0x71, 0x44, 0x4d, 0x42, 0x75, 0x42, 0x39, 0x66, 0x73, 0x6e, 0x79, 0x43, 0x37, 0x63, +0x4e, 0x4f, 0x47, 0x72, 0x2f, 0x62, 0x4f, 0x58, 0x66, 0x6c, 0x4e, 0x4c, 0x71, 0x36, 0x4a, 0x31, +0x43, 0x4b, 0x4b, 0x6a, 0x76, 0x2b, 0x78, 0x51, 0x5a, 0x79, 0x59, 0x76, 0x66, 0x64, 0x74, 0x43, +0x52, 0x56, 0x4f, 0x79, 0x78, 0x31, 0x61, 0x2b, 0x4c, 0x69, 0x47, 0x52, 0x65, 0x44, 0x2f, 0x44, +0x46, 0x6c, 0x39, 0x39, 0x5a, 0x42, 0x58, 0x66, 0x63, 0x42, 0x45, 0x46, 0x67, 0x79, 0x33, 0x71, +0x6e, 0x67, 0x6c, 0x52, 0x55, 0x74, 0x44, 0x53, 0x56, 0x53, 0x74, 0x6e, 0x79, 0x5a, 0x63, 0x6b, +0x6b, 0x76, 0x35, 0x2b, 0x77, 0x54, 0x2f, 0x53, 0x38, 0x78, 0x66, 0x6d, 0x77, 0x30, 0x31, 0x42, +0x44, 0x61, 0x53, 0x46, 0x38, 0x74, 0x51, 0x44, 0x61, 0x6b, 0x38, 0x59, 0x32, 0x67, 0x51, 0x6e, +0x68, 0x30, 0x65, 0x6c, 0x79, 0x59, 0x36, 0x48, 0x79, 0x6c, 0x78, 0x64, 0x37, 0x47, 0x62, 0x61, +0x6f, 0x59, 0x34, 0x55, 0x4e, 0x76, 0x62, 0x37, 0x47, 0x59, 0x4a, 0x52, 0x43, 0x4c, 0x56, 0x6c, +0x6d, 0x76, 0x63, 0x50, 0x4f, 0x69, 0x52, 0x51, 0x43, 0x73, 0x72, 0x51, 0x51, 0x2b, 0x4e, 0x30, +0x38, 0x2b, 0x36, 0x73, 0x53, 0x6a, 0x57, 0x69, 0x64, 0x42, 0x68, 0x53, 0x64, 0x4f, 0x43, 0x39, +0x41, 0x66, 0x43, 0x43, 0x35, 0x54, 0x48, 0x67, 0x45, 0x4e, 0x35, 0x2f, 0x42, 0x41, 0x66, 0x34, +0x4b, 0x70, 0x6d, 0x79, 0x74, 0x72, 0x47, 0x39, 0x48, 0x43, 0x75, 0x71, 0x4c, 0x36, 0x36, 0x4d, +0x6b, 0x46, 0x47, 0x4e, 0x67, 0x37, 0x59, 0x5a, 0x6b, 0x4e, 0x45, 0x42, 0x4a, 0x78, 0x78, 0x4f, +0x70, 0x6a, 0x43, 0x47, 0x75, 0x46, 0x57, 0x4c, 0x52, 0x6f, 0x68, 0x35, 0x51, 0x32, 0x49, 0x69, +0x56, 0x31, 0x6f, 0x39, 0x6a, 0x4d, 0x44, 0x53, 0x31, 0x62, 0x62, 0x43, 0x4b, 0x72, 0x31, 0x77, +0x5a, 0x4b, 0x78, 0x47, 0x77, 0x78, 0x63, 0x59, 0x41, 0x57, 0x54, 0x63, 0x66, 0x33, 0x61, 0x38, +0x66, 0x4f, 0x69, 0x63, 0x6e, 0x57, 0x6e, 0x6f, 0x5a, 0x59, 0x36, 0x4b, 0x63, 0x44, 0x32, 0x73, +0x49, 0x47, 0x70, 0x44, 0x72, 0x4d, 0x70, 0x52, 0x64, 0x70, 0x33, 0x30, 0x6d, 0x50, 0x66, 0x44, +0x30, 0x41, 0x71, 0x4d, 0x6c, 0x58, 0x6b, 0x35, 0x66, 0x6d, 0x33, 0x6e, 0x6e, 0x74, 0x70, 0x57, +0x4f, 0x55, 0x6b, 0x74, 0x46, 0x5a, 0x62, 0x6e, 0x53, 0x31, 0x58, 0x69, 0x46, 0x54, 0x4a, 0x50, +0x6d, 0x42, 0x4b, 0x37, 0x49, 0x61, 0x6b, 0x4f, 0x6c, 0x72, 0x65, 0x31, 0x6e, 0x57, 0x39, 0x2b, +0x67, 0x4d, 0x74, 0x6f, 0x66, 0x49, 0x64, 0x49, 0x6c, 0x33, 0x36, 0x4e, 0x49, 0x51, 0x50, 0x72, +0x39, 0x63, 0x65, 0x30, 0x76, 0x6f, 0x37, 0x73, 0x62, 0x56, 0x71, 0x31, 0x71, 0x7a, 0x4f, 0x61, +0x32, 0x64, 0x4a, 0x69, 0x63, 0x51, 0x46, 0x69, 0x53, 0x6d, 0x54, 0x44, 0x30, 0x72, 0x6f, 0x4f, +0x41, 0x52, 0x78, 0x4d, 0x4a, 0x2b, 0x76, 0x58, 0x76, 0x54, 0x34, 0x62, 0x64, 0x30, 0x30, 0x50, +0x2b, 0x6a, 0x64, 0x59, 0x6b, 0x6c, 0x79, 0x35, 0x31, 0x4e, 0x51, 0x45, 0x64, 0x57, 0x33, 0x49, +0x33, 0x2b, 0x5a, 0x56, 0x53, 0x45, 0x74, 0x65, 0x41, 0x30, 0x49, 0x59, 0x43, 0x38, 0x76, 0x48, +0x70, 0x54, 0x67, 0x41, 0x41, 0x49, 0x41, 0x42, 0x4a, 0x52, 0x45, 0x46, 0x55, 0x49, 0x57, 0x68, +0x2f, 0x34, 0x45, 0x47, 0x4b, 0x4f, 0x7a, 0x74, 0x68, 0x2f, 0x77, 0x4d, 0x78, 0x58, 0x71, 0x67, +0x41, 0x5a, 0x4f, 0x32, 0x2b, 0x4f, 0x33, 0x6f, 0x65, 0x35, 0x4c, 0x72, 0x30, 0x4a, 0x2b, 0x58, +0x71, 0x74, 0x55, 0x6b, 0x4e, 0x4f, 0x39, 0x66, 0x4e, 0x42, 0x68, 0x51, 0x6e, 0x6a, 0x35, 0x37, +0x4b, 0x49, 0x7a, 0x4d, 0x50, 0x4a, 0x31, 0x44, 0x77, 0x37, 0x71, 0x4c, 0x74, 0x6f, 0x7a, 0x42, +0x66, 0x65, 0x73, 0x65, 0x61, 0x56, 0x64, 0x73, 0x50, 0x39, 0x50, 0x39, 0x79, 0x78, 0x4c, 0x6b, +0x77, 0x59, 0x45, 0x2b, 0x4d, 0x65, 0x5a, 0x59, 0x6a, 0x4c, 0x6e, 0x32, 0x5a, 0x56, 0x2b, 0x36, +0x63, 0x43, 0x6d, 0x4f, 0x32, 0x73, 0x71, 0x62, 0x57, 0x35, 0x6a, 0x65, 0x2f, 0x35, 0x38, 0x74, +0x72, 0x53, 0x50, 0x79, 0x49, 0x69, 0x5a, 0x64, 0x6a, 0x31, 0x6a, 0x79, 0x50, 0x36, 0x58, 0x63, +0x61, 0x4a, 0x6c, 0x69, 0x4e, 0x57, 0x66, 0x32, 0x73, 0x37, 0x5a, 0x52, 0x42, 0x6b, 0x7a, 0x44, +0x47, 0x50, 0x72, 0x69, 0x64, 0x73, 0x65, 0x33, 0x7a, 0x46, 0x36, 0x6f, 0x55, 0x72, 0x38, 0x36, +0x7a, 0x56, 0x73, 0x35, 0x65, 0x49, 0x38, 0x73, 0x32, 0x71, 0x2f, 0x77, 0x52, 0x4f, 0x45, 0x5a, +0x72, 0x47, 0x6f, 0x41, 0x79, 0x72, 0x57, 0x6c, 0x77, 0x79, 0x69, 0x38, 0x44, 0x53, 0x34, 0x67, +0x71, 0x55, 0x69, 0x6d, 0x45, 0x4b, 0x31, 0x55, 0x6d, 0x6b, 0x6b, 0x6d, 0x43, 0x6c, 0x4b, 0x31, +0x62, 0x4b, 0x4c, 0x71, 0x53, 0x70, 0x49, 0x49, 0x55, 0x74, 0x56, 0x4a, 0x6b, 0x50, 0x4c, 0x50, +0x39, 0x76, 0x52, 0x46, 0x31, 0x55, 0x46, 0x56, 0x69, 0x2b, 0x50, 0x51, 0x6e, 0x57, 0x4e, 0x52, +0x6b, 0x45, 0x58, 0x38, 0x6d, 0x72, 0x49, 0x6d, 0x6e, 0x30, 0x72, 0x74, 0x57, 0x72, 0x72, 0x70, +0x76, 0x59, 0x4f, 0x50, 0x41, 0x6a, 0x70, 0x59, 0x35, 0x45, 0x72, 0x72, 0x77, 0x4e, 0x33, 0x55, +0x47, 0x45, 0x30, 0x7a, 0x33, 0x75, 0x4c, 0x41, 0x6e, 0x4c, 0x42, 0x41, 0x4b, 0x62, 0x57, 0x64, +0x2b, 0x46, 0x64, 0x5a, 0x68, 0x63, 0x4d, 0x71, 0x2f, 0x58, 0x57, 0x73, 0x48, 0x4e, 0x78, 0x38, +0x53, 0x35, 0x2b, 0x4d, 0x46, 0x44, 0x7a, 0x47, 0x67, 0x2b, 0x6d, 0x4a, 0x75, 0x66, 0x71, 0x4f, +0x4e, 0x73, 0x32, 0x66, 0x35, 0x33, 0x44, 0x46, 0x4b, 0x70, 0x34, 0x45, 0x38, 0x67, 0x62, 0x58, +0x30, 0x6a, 0x47, 0x4f, 0x46, 0x56, 0x71, 0x36, 0x71, 0x62, 0x56, 0x67, 0x75, 0x58, 0x6f, 0x65, +0x44, 0x62, 0x68, 0x43, 0x6b, 0x50, 0x64, 0x7a, 0x68, 0x41, 0x4f, 0x54, 0x43, 0x73, 0x47, 0x6a, +0x37, 0x50, 0x63, 0x73, 0x4c, 0x4b, 0x52, 0x46, 0x4b, 0x30, 0x74, 0x43, 0x65, 0x34, 0x49, 0x69, +0x46, 0x36, 0x79, 0x67, 0x49, 0x55, 0x69, 0x54, 0x45, 0x64, 0x49, 0x6f, 0x50, 0x50, 0x4d, 0x77, +0x43, 0x7a, 0x6d, 0x4b, 0x78, 0x72, 0x44, 0x36, 0x77, 0x78, 0x57, 0x48, 0x74, 0x53, 0x32, 0x78, +0x4f, 0x2b, 0x63, 0x4d, 0x45, 0x47, 0x6f, 0x79, 0x49, 0x43, 0x45, 0x50, 0x52, 0x4d, 0x6e, 0x4a, +0x6e, 0x68, 0x54, 0x49, 0x67, 0x4d, 0x35, 0x4a, 0x6e, 0x67, 0x67, 0x77, 0x2b, 0x76, 0x55, 0x43, +0x46, 0x51, 0x42, 0x77, 0x37, 0x43, 0x49, 0x54, 0x31, 0x2b, 0x6b, 0x43, 0x53, 0x75, 0x2b, 0x4f, +0x4f, 0x2b, 0x46, 0x75, 0x4e, 0x68, 0x4f, 0x71, 0x61, 0x39, 0x4f, 0x7a, 0x76, 0x6e, 0x49, 0x77, +0x69, 0x4a, 0x59, 0x6a, 0x74, 0x6d, 0x63, 0x42, 0x2f, 0x50, 0x38, 0x66, 0x47, 0x36, 0x4b, 0x55, +0x74, 0x37, 0x32, 0x61, 0x6b, 0x78, 0x4b, 0x75, 0x75, 0x4a, 0x6e, 0x66, 0x36, 0x64, 0x4a, 0x59, +0x73, 0x57, 0x55, 0x4a, 0x46, 0x52, 0x55, 0x55, 0x45, 0x72, 0x4f, 0x74, 0x4e, 0x31, 0x72, 0x54, +0x7a, 0x38, 0x42, 0x73, 0x68, 0x36, 0x44, 0x6a, 0x6b, 0x45, 0x42, 0x72, 0x43, 0x57, 0x50, 0x34, +0x6d, 0x6c, 0x44, 0x2f, 0x64, 0x2f, 0x32, 0x37, 0x67, 0x38, 0x62, 0x79, 0x73, 0x36, 0x45, 0x43, +0x6d, 0x2f, 0x4e, 0x70, 0x55, 0x69, 0x4e, 0x4a, 0x53, 0x59, 0x68, 0x4d, 0x6e, 0x6b, 0x76, 0x4f, +0x76, 0x66, 0x39, 0x48, 0x32, 0x77, 0x4d, 0x50, 0x4d, 0x65, 0x50, 0x59, 0x54, 0x70, 0x75, 0x39, +0x38, 0x44, 0x49, 0x46, 0x32, 0x78, 0x43, 0x44, 0x61, 0x31, 0x5a, 0x6c, 0x58, 0x36, 0x57, 0x4e, +0x64, 0x65, 0x54, 0x37, 0x50, 0x58, 0x50, 0x51, 0x36, 0x6e, 0x44, 0x54, 0x5a, 0x5a, 0x67, 0x78, +0x71, 0x32, 0x4b, 0x33, 0x2f, 0x54, 0x50, 0x36, 0x34, 0x39, 0x57, 0x76, 0x63, 0x2f, 0x50, 0x45, +0x70, 0x6e, 0x50, 0x44, 0x53, 0x44, 0x51, 0x77, 0x75, 0x57, 0x38, 0x62, 0x56, 0x34, 0x2b, 0x35, +0x44, 0x79, 0x68, 0x53, 0x76, 0x2f, 0x37, 0x78, 0x4c, 0x56, 0x72, 0x78, 0x66, 0x4f, 0x45, 0x35, +0x51, 0x4f, 0x74, 0x74, 0x67, 0x69, 0x31, 0x32, 0x68, 0x4c, 0x49, 0x66, 0x48, 0x70, 0x73, 0x2f, +0x6d, 0x72, 0x57, 0x39, 0x2b, 0x68, 0x4a, 0x6f, 0x4b, 0x69, 0x41, 0x6e, 0x49, 0x2f, 0x65, 0x55, +0x31, 0x64, 0x4f, 0x5a, 0x6d, 0x6a, 0x49, 0x47, 0x4f, 0x4c, 0x7a, 0x46, 0x4e, 0x7a, 0x32, 0x4b, +0x43, 0x5a, 0x6b, 0x78, 0x71, 0x48, 0x57, 0x62, 0x44, 0x47, 0x35, 0x6a, 0x38, 0x48, 0x45, 0x7a, +0x70, 0x42, 0x45, 0x7a, 0x46, 0x63, 0x52, 0x6a, 0x6a, 0x52, 0x77, 0x30, 0x51, 0x5a, 0x70, 0x56, +0x70, 0x5a, 0x31, 0x34, 0x57, 0x71, 0x52, 0x52, 0x54, 0x35, 0x79, 0x69, 0x6b, 0x30, 0x75, 0x79, +0x39, 0x39, 0x65, 0x59, 0x48, 0x67, 0x66, 0x44, 0x36, 0x59, 0x30, 0x57, 0x4b, 0x37, 0x5a, 0x56, +0x69, 0x2b, 0x2b, 0x37, 0x78, 0x35, 0x6c, 0x51, 0x4b, 0x6b, 0x30, 0x71, 0x68, 0x6b, 0x79, 0x6b, +0x4c, 0x55, 0x41, 0x71, 0x72, 0x46, 0x6e, 0x65, 0x6c, 0x30, 0x45, 0x47, 0x53, 0x48, 0x43, 0x47, +0x4a, 0x75, 0x30, 0x37, 0x77, 0x77, 0x43, 0x5a, 0x55, 0x37, 0x62, 0x45, 0x48, 0x6c, 0x55, 0x57, +0x46, 0x48, 0x44, 0x4c, 0x47, 0x4d, 0x48, 0x75, 0x70, 0x34, 0x5a, 0x76, 0x35, 0x68, 0x6b, 0x52, +0x67, 0x38, 0x4c, 0x58, 0x42, 0x56, 0x33, 0x61, 0x50, 0x4b, 0x59, 0x4e, 0x52, 0x42, 0x69, 0x38, +0x41, 0x4f, 0x74, 0x78, 0x36, 0x55, 0x71, 0x57, 0x72, 0x32, 0x6b, 0x62, 0x6c, 0x31, 0x58, 0x30, +0x66, 0x30, 0x39, 0x34, 0x4f, 0x67, 0x61, 0x57, 0x45, 0x69, 0x6d, 0x4c, 0x67, 0x62, 0x67, 0x59, +0x4b, 0x42, 0x55, 0x67, 0x64, 0x44, 0x31, 0x35, 0x35, 0x48, 0x73, 0x67, 0x38, 0x6a, 0x49, 0x6d, +0x44, 0x6b, 0x63, 0x69, 0x76, 0x4f, 0x33, 0x6e, 0x73, 0x6f, 0x49, 0x43, 0x4a, 0x32, 0x38, 0x42, +0x37, 0x2b, 0x65, 0x66, 0x77, 0x77, 0x36, 0x78, 0x37, 0x2b, 0x4d, 0x66, 0x2b, 0x78, 0x33, 0x4c, +0x31, 0x57, 0x77, 0x45, 0x48, 0x37, 0x31, 0x4b, 0x45, 0x4d, 0x51, 0x46, 0x65, 0x4c, 0x4a, 0x2b, +0x32, 0x76, 0x30, 0x4b, 0x2f, 0x73, 0x2b, 0x77, 0x53, 0x4d, 0x56, 0x4a, 0x2b, 0x6d, 0x52, 0x34, +0x41, 0x34, 0x70, 0x37, 0x42, 0x2b, 0x44, 0x47, 0x72, 0x39, 0x42, 0x6d, 0x78, 0x38, 0x45, 0x77, +0x73, 0x66, 0x4e, 0x4a, 0x52, 0x77, 0x51, 0x56, 0x75, 0x61, 0x52, 0x53, 0x67, 0x32, 0x48, 0x2f, +0x70, 0x65, 0x67, 0x71, 0x44, 0x46, 0x4e, 0x64, 0x73, 0x56, 0x63, 0x4f, 0x4e, 0x34, 0x77, 0x36, +0x6a, 0x34, 0x37, 0x38, 0x76, 0x55, 0x33, 0x54, 0x71, 0x4f, 0x56, 0x6e, 0x39, 0x62, 0x49, 0x79, +0x78, 0x4d, 0x31, 0x68, 0x4a, 0x47, 0x31, 0x34, 0x73, 0x42, 0x53, 0x61, 0x5a, 0x5a, 0x65, 0x71, +0x6e, 0x39, 0x37, 0x54, 0x53, 0x68, 0x37, 0x4f, 0x2f, 0x4d, 0x51, 0x49, 0x76, 0x6e, 0x69, 0x43, +0x2f, 0x45, 0x48, 0x68, 0x2f, 0x50, 0x47, 0x72, 0x48, 0x76, 0x79, 0x4c, 0x2f, 0x52, 0x79, 0x69, +0x38, 0x47, 0x44, 0x67, 0x51, 0x2b, 0x4a, 0x44, 0x69, 0x4c, 0x37, 0x4a, 0x5a, 0x65, 0x55, 0x4d, +0x6f, 0x74, 0x64, 0x59, 0x4b, 0x76, 0x65, 0x34, 0x78, 0x45, 0x43, 0x76, 0x4a, 0x33, 0x66, 0x4d, +0x4b, 0x4d, 0x50, 0x45, 0x73, 0x2b, 0x66, 0x45, 0x38, 0x6a, 0x34, 0x71, 0x7a, 0x7a, 0x36, 0x61, +0x34, 0x6f, 0x70, 0x69, 0x69, 0x6e, 0x4b, 0x49, 0x65, 0x31, 0x35, 0x74, 0x76, 0x76, 0x73, 0x46, +0x38, 0x2b, 0x53, 0x57, 0x6d, 0x74, 0x52, 0x56, 0x7a, 0x2b, 0x65, 0x55, 0x59, 0x49, 0x56, 0x69, +0x32, 0x36, 0x36, 0x34, 0x30, 0x70, 0x46, 0x4a, 0x5a, 0x55, 0x50, 0x71, 0x6c, 0x70, 0x35, 0x2f, +0x4f, 0x67, 0x46, 0x4e, 0x4f, 0x51, 0x62, 0x57, 0x32, 0x32, 0x71, 0x69, 0x42, 0x38, 0x78, 0x54, +0x72, 0x56, 0x43, 0x6f, 0x61, 0x37, 0x4e, 0x63, 0x39, 0x2b, 0x4b, 0x42, 0x64, 0x59, 0x6f, 0x55, +0x52, 0x43, 0x43, 0x6d, 0x4a, 0x56, 0x31, 0x54, 0x77, 0x37, 0x66, 0x6e, 0x6e, 0x57, 0x77, 0x73, +0x67, 0x76, 0x76, 0x2f, 0x2b, 0x73, 0x4d, 0x30, 0x32, 0x78, 0x49, 0x51, 0x6b, 0x5a, 0x38, 0x6f, +0x55, 0x39, 0x6d, 0x72, 0x36, 0x68, 0x72, 0x61, 0x33, 0x4f, 0x33, 0x6c, 0x6b, 0x2b, 0x4a, 0x47, +0x32, 0x77, 0x71, 0x68, 0x51, 0x44, 0x70, 0x41, 0x52, 0x77, 0x68, 0x45, 0x31, 0x71, 0x64, 0x70, +0x43, 0x59, 0x44, 0x48, 0x71, 0x43, 0x57, 0x73, 0x4e, 0x57, 0x4c, 0x4f, 0x6a, 0x47, 0x72, 0x79, +0x72, 0x6d, 0x58, 0x78, 0x41, 0x2b, 0x4b, 0x49, 0x4e, 0x47, 0x48, 0x4d, 0x4c, 0x5a, 0x2b, 0x39, +0x70, 0x4f, 0x47, 0x75, 0x50, 0x62, 0x69, 0x61, 0x30, 0x37, 0x37, 0x48, 0x78, 0x45, 0x45, 0x31, +0x39, 0x2f, 0x31, 0x6f, 0x6f, 0x7a, 0x49, 0x4e, 0x46, 0x53, 0x55, 0x34, 0x37, 0x2b, 0x41, 0x46, +0x67, 0x4b, 0x2b, 0x69, 0x7a, 0x50, 0x63, 0x78, 0x4d, 0x75, 0x47, 0x4b, 0x55, 0x6d, 0x39, 0x38, +0x79, 0x4b, 0x62, 0x57, 0x4d, 0x4d, 0x56, 0x43, 0x77, 0x44, 0x53, 0x59, 0x57, 0x59, 0x4d, 0x78, +0x61, 0x54, 0x4b, 0x37, 0x42, 0x35, 0x4e, 0x5a, 0x6a, 0x69, 0x6e, 0x66, 0x44, 0x6c, 0x4a, 0x2b, +0x53, 0x72, 0x63, 0x44, 0x4f, 0x68, 0x41, 0x39, 0x6b, 0x64, 0x74, 0x70, 0x6b, 0x67, 0x55, 0x72, +0x78, 0x2f, 0x45, 0x78, 0x46, 0x33, 0x2b, 0x6b, 0x76, 0x4d, 0x71, 0x51, 0x36, 0x46, 0x36, 0x4e, +0x55, 0x78, 0x47, 0x51, 0x54, 0x7a, 0x62, 0x4a, 0x4b, 0x34, 0x5a, 0x57, 0x56, 0x77, 0x51, 0x55, +0x58, 0x59, 0x48, 0x59, 0x5a, 0x59, 0x66, 0x38, 0x76, 0x78, 0x4f, 0x32, 0x6e, 0x6b, 0x6c, 0x62, +0x67, 0x6f, 0x77, 0x48, 0x41, 0x4b, 0x58, 0x38, 0x71, 0x68, 0x65, 0x37, 0x71, 0x69, 0x67, 0x59, +0x46, 0x49, 0x34, 0x4a, 0x30, 0x69, 0x63, 0x32, 0x5a, 0x4d, 0x7a, 0x48, 0x54, 0x70, 0x32, 0x50, +0x61, 0x32, 0x75, 0x41, 0x50, 0x66, 0x38, 0x44, 0x7a, 0x44, 0x47, 0x4d, 0x47, 0x47, 0x52, 0x49, +0x46, 0x43, 0x35, 0x6e, 0x32, 0x62, 0x61, 0x65, 0x62, 0x6d, 0x5a, 0x51, 0x37, 0x32, 0x6a, 0x31, +0x56, 0x57, 0x41, 0x42, 0x6c, 0x62, 0x31, 0x4b, 0x68, 0x56, 0x42, 0x54, 0x36, 0x7a, 0x42, 0x7a, +0x39, 0x79, 0x63, 0x75, 0x6a, 0x34, 0x4d, 0x30, 0x33, 0x4e, 0x37, 0x32, 0x45, 0x38, 0x58, 0x31, +0x71, 0x57, 0x31, 0x75, 0x4a, 0x31, 0x64, 0x63, 0x7a, 0x65, 0x56, 0x49, 0x4c, 0x4b, 0x31, 0x61, +0x73, 0x63, 0x78, 0x42, 0x62, 0x77, 0x5a, 0x54, 0x36, 0x4f, 0x43, 0x63, 0x39, 0x48, 0x33, 0x44, +0x36, 0x33, 0x41, 0x65, 0x6f, 0x48, 0x6e, 0x4d, 0x69, 0x44, 0x33, 0x31, 0x78, 0x4b, 0x44, 0x6c, +0x43, 0x73, 0x4c, 0x36, 0x31, 0x67, 0x4d, 0x4d, 0x50, 0x57, 0x55, 0x55, 0x51, 0x42, 0x41, 0x77, +0x63, 0x6d, 0x4d, 0x4e, 0x62, 0x62, 0x34, 0x4e, 0x53, 0x4a, 0x2f, 0x5a, 0x36, 0x2f, 0x32, 0x6a, +0x33, 0x59, 0x35, 0x52, 0x39, 0x2b, 0x47, 0x47, 0x76, 0x39, 0x78, 0x2f, 0x5a, 0x32, 0x6b, 0x72, +0x79, 0x32, 0x73, 0x50, 0x74, 0x37, 0x43, 0x38, 0x44, 0x56, 0x39, 0x56, 0x57, 0x55, 0x74, 0x58, +0x5a, 0x78, 0x58, 0x63, 0x71, 0x59, 0x45, 0x31, 0x2b, 0x6e, 0x4b, 0x36, 0x2f, 0x54, 0x38, 0x49, +0x45, 0x67, 0x6f, 0x35, 0x50, 0x50, 0x36, 0x44, 0x6d, 0x69, 0x5a, 0x65, 0x6a, 0x65, 0x34, 0x58, +0x2b, 0x6c, 0x71, 0x70, 0x4c, 0x2f, 0x38, 0x5a, 0x4e, 0x45, 0x33, 0x64, 0x6e, 0x62, 0x55, 0x75, +0x48, 0x57, 0x79, 0x4b, 0x70, 0x71, 0x49, 0x33, 0x73, 0x37, 0x36, 0x71, 0x49, 0x74, 0x56, 0x70, +0x4a, 0x46, 0x55, 0x31, 0x67, 0x74, 0x5a, 0x58, 0x46, 0x33, 0x48, 0x66, 0x2b, 0x43, 0x75, 0x43, +0x64, 0x33, 0x77, 0x61, 0x46, 0x37, 0x7a, 0x59, 0x6f, 0x68, 0x65, 0x64, 0x42, 0x30, 0x32, 0x31, +0x49, 0x6b, 0x59, 0x74, 0x76, 0x55, 0x67, 0x53, 0x4e, 0x4e, 0x35, 0x4a, 0x54, 0x65, 0x30, 0x32, +0x76, 0x38, 0x75, 0x64, 0x73, 0x75, 0x4f, 0x7a, 0x72, 0x35, 0x38, 0x33, 0x44, 0x50, 0x50, 0x77, +0x77, 0x35, 0x72, 0x4c, 0x4c, 0x4d, 0x45, 0x38, 0x2b, 0x69, 0x54, 0x45, 0x6d, 0x72, 0x66, 0x7a, +0x64, 0x6f, 0x50, 0x51, 0x62, 0x58, 0x6e, 0x79, 0x52, 0x38, 0x69, 0x46, 0x44, 0x43, 0x46, 0x61, +0x73, 0x49, 0x46, 0x33, 0x35, 0x4a, 0x35, 0x75, 0x65, 0x62, 0x63, 0x4e, 0x4c, 0x4c, 0x36, 0x55, +0x78, 0x43, 0x53, 0x37, 0x55, 0x6d, 0x44, 0x64, 0x6f, 0x45, 0x49, 0x31, 0x67, 0x42, 0x77, 0x44, +0x35, 0x35, 0x70, 0x76, 0x34, 0x62, 0x57, 0x32, 0x49, 0x66, 0x39, 0x35, 0x4c, 0x53, 0x67, 0x53, +0x38, 0x56, 0x7a, 0x4b, 0x4b, 0x64, 0x33, 0x59, 0x37, 0x67, 0x62, 0x36, 0x61, 0x71, 0x4d, 0x47, +0x45, 0x4d, 0x34, 0x4f, 0x6b, 0x6f, 0x78, 0x69, 0x75, 0x72, 0x63, 0x6f, 0x48, 0x2b, 0x74, 0x4d, +0x61, 0x69, 0x31, 0x45, 0x34, 0x61, 0x52, 0x4c, 0x65, 0x67, 0x42, 0x5a, 0x69, 0x52, 0x78, 0x65, +0x54, 0x50, 0x47, 0x4e, 0x78, 0x56, 0x6b, 0x45, 0x4e, 0x62, 0x2b, 0x38, 0x43, 0x63, 0x69, 0x62, +0x32, 0x49, 0x66, 0x58, 0x67, 0x61, 0x75, 0x52, 0x72, 0x36, 0x79, 0x4f, 0x6f, 0x6f, 0x6a, 0x39, +0x67, 0x41, 0x47, 0x76, 0x66, 0x66, 0x68, 0x74, 0x76, 0x6d, 0x32, 0x76, 0x54, 0x61, 0x77, 0x74, +0x2f, 0x41, 0x4a, 0x69, 0x4e, 0x6f, 0x44, 0x62, 0x2b, 0x4b, 0x75, 0x55, 0x50, 0x42, 0x34, 0x43, +0x6f, 0x59, 0x54, 0x45, 0x6f, 0x38, 0x76, 0x6a, 0x59, 0x50, 0x34, 0x7a, 0x52, 0x6c, 0x51, 0x6c, +0x4b, 0x69, 0x37, 0x62, 0x6c, 0x68, 0x2f, 0x5a, 0x31, 0x2f, 0x4e, 0x69, 0x2b, 0x6e, 0x67, 0x6c, +0x6c, 0x33, 0x51, 0x54, 0x51, 0x70, 0x4f, 0x76, 0x55, 0x32, 0x79, 0x70, 0x53, 0x6f, 0x5a, 0x39, +0x43, 0x63, 0x39, 0x69, 0x33, 0x4c, 0x39, 0x46, 0x2f, 0x31, 0x69, 0x75, 0x6b, 0x6e, 0x4d, 0x6d, +0x71, 0x4d, 0x6d, 0x65, 0x75, 0x4d, 0x4a, 0x31, 0x7a, 0x79, 0x42, 0x42, 0x61, 0x55, 0x79, 0x6d, +0x72, 0x78, 0x43, 0x46, 0x2f, 0x58, 0x71, 0x6a, 0x30, 0x51, 0x59, 0x42, 0x4a, 0x4a, 0x69, 0x30, +0x77, 0x4b, 0x66, 0x79, 0x73, 0x71, 0x77, 0x73, 0x54, 0x70, 0x46, 0x42, 0x4a, 0x31, 0x34, 0x6c, +0x4b, 0x52, 0x47, 0x34, 0x4f, 0x4d, 0x33, 0x59, 0x73, 0x5a, 0x73, 0x30, 0x61, 0x7a, 0x4c, 0x68, +0x78, 0x7a, 0x74, 0x6d, 0x6c, 0x6d, 0x64, 0x59, 0x36, 0x6a, 0x55, 0x66, 0x62, 0x48, 0x32, 0x4c, +0x31, 0x77, 0x48, 0x55, 0x57, 0x71, 0x52, 0x5a, 0x79, 0x45, 0x7a, 0x6f, 0x30, 0x33, 0x5a, 0x43, +0x38, 0x49, 0x58, 0x44, 0x77, 0x56, 0x38, 0x44, 0x6b, 0x72, 0x50, 0x65, 0x50, 0x6f, 0x4c, 0x7a, +0x64, 0x46, 0x62, 0x47, 0x37, 0x41, 0x70, 0x6f, 0x30, 0x30, 0x55, 0x6b, 0x6b, 0x67, 0x4f, 0x35, +0x36, 0x65, 0x65, 0x75, 0x5a, 0x50, 0x4c, 0x58, 0x54, 0x57, 0x76, 0x37, 0x31, 0x33, 0x72, 0x48, +0x45, 0x39, 0x7a, 0x58, 0x38, 0x36, 0x65, 0x69, 0x41, 0x68, 0x6e, 0x62, 0x46, 0x31, 0x57, 0x2b, +0x56, 0x38, 0x65, 0x6d, 0x6a, 0x37, 0x32, 0x4f, 0x4d, 0x5a, 0x5a, 0x56, 0x74, 0x61, 0x57, 0x6c, +0x68, 0x61, 0x53, 0x78, 0x47, 0x35, 0x59, 0x55, 0x58, 0x32, 0x6b, 0x6f, 0x30, 0x44, 0x6f, 0x6f, +0x61, 0x63, 0x74, 0x47, 0x56, 0x76, 0x2f, 0x55, 0x57, 0x79, 0x6f, 0x39, 0x7a, 0x34, 0x6d, 0x57, +0x66, 0x4f, 0x4c, 0x43, 0x50, 0x69, 0x6b, 0x41, 0x2f, 0x2f, 0x66, 0x73, 0x57, 0x38, 0x65, 0x78, +0x64, 0x54, 0x38, 0x41, 0x70, 0x53, 0x59, 0x53, 0x53, 0x70, 0x4b, 0x51, 0x67, 0x6b, 0x49, 0x4c, +0x41, 0x4b, 0x4a, 0x71, 0x30, 0x59, 0x50, 0x69, 0x61, 0x56, 0x6e, 0x4a, 0x62, 0x57, 0x73, 0x6d, +0x37, 0x36, 0x43, 0x72, 0x30, 0x53, 0x38, 0x39, 0x54, 0x66, 0x64, 0x6c, 0x6b, 0x54, 0x43, 0x79, +0x47, 0x55, 0x6f, 0x71, 0x59, 0x57, 0x77, 0x70, 0x6f, 0x72, 0x57, 0x6e, 0x35, 0x75, 0x59, 0x35, +0x56, 0x72, 0x61, 0x57, 0x73, 0x61, 0x49, 0x35, 0x48, 0x63, 0x68, 0x72, 0x65, 0x49, 0x77, 0x68, +0x6c, 0x56, 0x79, 0x70, 0x6e, 0x65, 0x65, 0x72, 0x6f, 0x4f, 0x64, 0x70, 0x56, 0x49, 0x54, 0x62, +0x59, 0x39, 0x78, 0x75, 0x68, 0x38, 0x4a, 0x6e, 0x74, 0x6e, 0x41, 0x57, 0x6c, 0x6c, 0x67, 0x69, +0x5a, 0x67, 0x39, 0x46, 0x39, 0x79, 0x4d, 0x74, 0x70, 0x32, 0x57, 0x54, 0x37, 0x64, 0x35, 0x64, +0x66, 0x44, 0x4a, 0x69, 0x52, 0x49, 0x32, 0x31, 0x75, 0x7a, 0x63, 0x76, 0x2f, 0x77, 0x58, 0x6a, +0x57, 0x59, 0x6d, 0x31, 0x34, 0x35, 0x7a, 0x31, 0x61, 0x64, 0x74, 0x6d, 0x4a, 0x50, 0x74, 0x32, +0x67, 0x33, 0x49, 0x58, 0x6a, 0x78, 0x6c, 0x45, 0x30, 0x64, 0x69, 0x79, 0x35, 0x41, 0x77, 0x65, +0x69, 0x74, 0x65, 0x58, 0x36, 0x30, 0x38, 0x34, 0x43, 0x32, 0x50, 0x6a, 0x36, 0x36, 0x32, 0x67, +0x68, 0x4b, 0x4e, 0x6c, 0x76, 0x76, 0x37, 0x51, 0x46, 0x34, 0x43, 0x61, 0x7a, 0x6e, 0x4b, 0x6f, +0x71, 0x79, 0x6d, 0x62, 0x4d, 0x63, 0x45, 0x75, 0x41, 0x78, 0x6b, 0x62, 0x6b, 0x37, 0x62, 0x65, +0x54, 0x6b, 0x70, 0x4b, 0x53, 0x50, 0x35, 0x33, 0x4d, 0x45, 0x55, 0x63, 0x64, 0x77, 0x34, 0x52, +0x66, 0x4d, 0x48, 0x38, 0x39, 0x7a, 0x2b, 0x4f, 0x4f, 0x59, 0x2f, 0x70, 0x53, 0x32, 0x76, 0x2f, +0x61, 0x62, 0x50, 0x44, 0x4e, 0x63, 0x37, 0x31, 0x66, 0x6b, 0x2f, 0x4e, 0x58, 0x51, 0x2f, 0x79, +0x79, 0x37, 0x4f, 0x76, 0x4c, 0x6d, 0x70, 0x76, 0x52, 0x67, 0x77, 0x62, 0x2f, 0x4b, 0x6b, 0x58, +0x66, 0x31, 0x4e, 0x62, 0x57, 0x64, 0x6c, 0x47, 0x33, 0x30, 0x56, 0x65, 0x7a, 0x49, 0x74, 0x48, +0x42, 0x4e, 0x32, 0x75, 0x62, 0x47, 0x56, 0x67, 0x36, 0x6e, 0x33, 0x6c, 0x72, 0x35, 0x31, 0x46, +0x5a, 0x56, 0x4e, 0x58, 0x6a, 0x2b, 0x63, 0x4f, 0x6a, 0x63, 0x73, 0x6c, 0x49, 0x49, 0x59, 0x66, +0x36, 0x58, 0x72, 0x4e, 0x66, 0x5a, 0x61, 0x39, 0x5a, 0x72, 0x32, 0x61, 0x5a, 0x71, 0x70, 0x48, +0x5a, 0x37, 0x49, 0x36, 0x5a, 0x31, 0x45, 0x35, 0x69, 0x4e, 0x32, 0x43, 0x34, 0x77, 0x63, 0x52, +0x73, 0x36, 0x71, 0x55, 0x57, 0x47, 0x69, 0x31, 0x55, 0x64, 0x47, 0x36, 0x6b, 0x63, 0x55, 0x64, +0x51, 0x77, 0x6d, 0x44, 0x5a, 0x71, 0x77, 0x31, 0x6d, 0x42, 0x34, 0x2f, 0x6b, 0x78, 0x32, 0x34, +0x4a, 0x34, 0x48, 0x6d, 0x59, 0x67, 0x32, 0x78, 0x39, 0x78, 0x65, 0x57, 0x70, 0x35, 0x54, 0x79, +0x77, 0x39, 0x67, 0x45, 0x2b, 0x32, 0x50, 0x69, 0x42, 0x52, 0x61, 0x5a, 0x6c, 0x4b, 0x6e, 0x2b, +0x59, 0x53, 0x4b, 0x4d, 0x6c, 0x79, 0x70, 0x66, 0x51, 0x41, 0x57, 0x74, 0x6a, 0x4d, 0x55, 0x72, +0x4f, 0x4f, 0x51, 0x65, 0x31, 0x5a, 0x45, 0x6b, 0x45, 0x4a, 0x43, 0x6c, 0x38, 0x2b, 0x32, 0x33, +0x4d, 0x78, 0x6f, 0x31, 0x30, 0x48, 0x48, 0x59, 0x34, 0x75, 0x72, 0x32, 0x74, 0x78, 0x2b, 0x42, +0x6c, 0x70, 0x43, 0x51, 0x2b, 0x5a, 0x41, 0x67, 0x72, 0x5a, 0x38, 0x32, 0x69, 0x59, 0x52, 0x4a, +0x63, 0x63, 0x73, 0x67, 0x6c, 0x4c, 0x47, 0x74, 0x66, 0x35, 0x67, 0x42, 0x62, 0x67, 0x74, 0x4e, +0x4e, 0x6b, 0x6b, 0x4f, 0x6d, 0x4a, 0x33, 0x6c, 0x73, 0x33, 0x34, 0x41, 0x2f, 0x33, 0x53, 0x47, +0x6f, 0x50, 0x31, 0x42, 0x78, 0x39, 0x6e, 0x2b, 0x53, 0x54, 0x43, 0x31, 0x61, 0x7a, 0x50, 0x55, +0x76, 0x62, 0x59, 0x74, 0x55, 0x6b, 0x73, 0x47, 0x6c, 0x67, 0x2f, 0x6e, 0x6f, 0x35, 0x6f, 0x39, +0x59, 0x51, 0x42, 0x6f, 0x4b, 0x61, 0x36, 0x54, 0x4d, 0x79, 0x6e, 0x6f, 0x7a, 0x71, 0x53, 0x52, +0x42, 0x62, 0x6c, 0x47, 0x6b, 0x64, 0x47, 0x6e, 0x4f, 0x53, 0x65, 0x57, 0x41, 0x50, 0x42, 0x4b, +0x53, 0x43, 0x54, 0x76, 0x7a, 0x43, 0x30, 0x46, 0x4b, 0x57, 0x68, 0x6a, 0x35, 0x76, 0x2f, 0x76, +0x6d, 0x4d, 0x37, 0x45, 0x5a, 0x62, 0x76, 0x33, 0x6b, 0x5a, 0x38, 0x53, 0x4b, 0x4a, 0x36, 0x6a, +0x34, 0x34, 0x79, 0x6e, 0x57, 0x71, 0x6e, 0x49, 0x4f, 0x31, 0x39, 0x44, 0x6b, 0x56, 0x6b, 0x70, +0x42, 0x4d, 0x75, 0x53, 0x38, 0x31, 0x78, 0x48, 0x64, 0x66, 0x50, 0x70, 0x63, 0x52, 0x65, 0x63, +0x57, 0x58, 0x2b, 0x2b, 0x73, 0x41, 0x5a, 0x6e, 0x6d, 0x70, 0x46, 0x79, 0x31, 0x61, 0x68, 0x56, +0x39, 0x2b, 0x2f, 0x62, 0x74, 0x33, 0x58, 0x72, 0x35, 0x42, 0x66, 0x6e, 0x2f, 0x39, 0x74, 0x74, +0x76, 0x47, 0x54, 0x74, 0x32, 0x4c, 0x42, 0x64, 0x64, 0x64, 0x42, 0x48, 0x72, 0x31, 0x71, 0x33, +0x4c, 0x63, 0x75, 0x49, 0x4a, 0x6f, 0x54, 0x6a, 0x39, 0x69, 0x4d, 0x55, 0x59, 0x49, 0x37, 0x6e, +0x6c, 0x32, 0x54, 0x35, 0x49, 0x65, 0x59, 0x56, 0x31, 0x73, 0x6b, 0x6f, 0x4c, 0x68, 0x75, 0x76, +0x62, 0x74, 0x79, 0x38, 0x33, 0x33, 0x58, 0x51, 0x54, 0x69, 0x31, 0x6f, 0x57, 0x41, 0x52, 0x61, +0x4e, 0x61, 0x45, 0x78, 0x47, 0x4e, 0x61, 0x6c, 0x74, 0x68, 0x71, 0x43, 0x33, 0x48, 0x6d, 0x51, +0x74, 0x68, 0x4b, 0x35, 0x6d, 0x64, 0x4b, 0x37, 0x42, 0x66, 0x50, 0x6b, 0x75, 0x4c, 0x61, 0x4e, +0x32, 0x70, 0x53, 0x77, 0x44, 0x79, 0x6a, 0x78, 0x30, 0x36, 0x74, 0x52, 0x65, 0x6f, 0x66, 0x77, +0x36, 0x6d, 0x61, 0x54, 0x6c, 0x6c, 0x56, 0x66, 0x51, 0x51, 0x55, 0x44, 0x4e, 0x70, 0x5a, 0x64, +0x6d, 0x52, 0x51, 0x48, 0x43, 0x35, 0x78, 0x39, 0x37, 0x79, 0x43, 0x46, 0x75, 0x43, 0x53, 0x41, +0x6c, 0x72, 0x56, 0x4a, 0x53, 0x65, 0x4e, 0x61, 0x5a, 0x69, 0x49, 0x4d, 0x50, 0x77, 0x30, 0x6a, +0x6e, 0x76, 0x44, 0x48, 0x70, 0x6f, 0x39, 0x59, 0x75, 0x47, 0x6b, 0x44, 0x61, 0x69, 0x35, 0x35, +0x49, 0x53, 0x6e, 0x49, 0x6d, 0x61, 0x43, 0x34, 0x37, 0x49, 0x38, 0x62, 0x53, 0x44, 0x59, 0x61, +0x39, 0x42, 0x6e, 0x37, 0x4a, 0x78, 0x44, 0x45, 0x76, 0x63, 0x74, 0x58, 0x62, 0x5a, 0x7a, 0x4f, +0x33, 0x61, 0x52, 0x44, 0x44, 0x4b, 0x68, 0x5a, 0x7a, 0x32, 0x77, 0x47, 0x33, 0x63, 0x4e, 0x65, +0x6e, 0x78, 0x2f, 0x4b, 0x66, 0x48, 0x2f, 0x64, 0x4b, 0x46, 0x79, 0x42, 0x52, 0x4d, 0x4c, 0x67, +0x53, 0x33, 0x76, 0x38, 0x4c, 0x37, 0x48, 0x62, 0x43, 0x6e, 0x2f, 0x2b, 0x33, 0x68, 0x58, 0x37, +0x32, 0x70, 0x6c, 0x2b, 0x2f, 0x4c, 0x32, 0x31, 0x43, 0x41, 0x66, 0x6a, 0x34, 0x48, 0x4c, 0x2f, +0x46, 0x48, 0x31, 0x6a, 0x64, 0x75, 0x5a, 0x70, 0x33, 0x56, 0x6e, 0x7a, 0x41, 0x6d, 0x56, 0x75, +0x66, 0x51, 0x6d, 0x56, 0x2b, 0x5a, 0x59, 0x38, 0x4f, 0x42, 0x4c, 0x75, 0x47, 0x4a, 0x35, 0x42, +0x52, 0x56, 0x61, 0x53, 0x39, 0x5a, 0x72, 0x33, 0x4b, 0x75, 0x4e, 0x6d, 0x76, 0x52, 0x6d, 0x76, +0x57, 0x54, 0x43, 0x68, 0x6f, 0x68, 0x4f, 0x57, 0x57, 0x49, 0x56, 0x6d, 0x49, 0x52, 0x58, 0x4b, +0x5a, 0x62, 0x63, 0x48, 0x30, 0x31, 0x35, 0x68, 0x79, 0x5a, 0x64, 0x64, 0x39, 0x44, 0x75, 0x2b, +0x76, 0x6c, 0x51, 0x30, 0x33, 0x61, 0x57, 0x33, 0x6a, 0x31, 0x58, 0x62, 0x39, 0x5a, 0x64, 0x78, +0x6e, 0x59, 0x43, 0x6f, 0x39, 0x39, 0x50, 0x35, 0x32, 0x41, 0x41, 0x68, 0x6e, 0x74, 0x50, 0x66, +0x61, 0x33, 0x75, 0x4f, 0x2b, 0x74, 0x66, 0x66, 0x52, 0x6c, 0x47, 0x79, 0x79, 0x45, 0x4f, 0x71, +0x73, 0x6d, 0x56, 0x38, 0x67, 0x54, 0x41, 0x59, 0x72, 0x73, 0x55, 0x6d, 0x48, 0x53, 0x53, 0x4b, +0x4c, 0x4b, 0x34, 0x54, 0x44, 0x68, 0x75, 0x38, 0x5a, 0x70, 0x4d, 0x43, 0x74, 0x47, 0x63, 0x50, +0x31, 0x66, 0x79, 0x59, 0x55, 0x56, 0x6b, 0x4d, 0x45, 0x68, 0x62, 0x56, 0x35, 0x47, 0x6a, 0x59, +0x52, 0x36, 0x5a, 0x36, 0x74, 0x4e, 0x57, 0x66, 0x50, 0x39, 0x44, 0x6e, 0x31, 0x48, 0x5a, 0x2f, +0x31, 0x54, 0x66, 0x6c, 0x63, 0x4d, 0x37, 0x32, 0x4d, 0x71, 0x55, 0x56, 0x4c, 0x75, 0x58, 0x36, +0x73, 0x69, 0x59, 0x68, 0x44, 0x6c, 0x55, 0x6d, 0x54, 0x6f, 0x6b, 0x62, 0x68, 0x76, 0x55, 0x7a, +0x49, 0x71, 0x77, 0x4e, 0x67, 0x61, 0x57, 0x4d, 0x73, 0x47, 0x33, 0x51, 0x49, 0x39, 0x31, 0x58, +0x4b, 0x6d, 0x65, 0x72, 0x70, 0x41, 0x55, 0x42, 0x49, 0x71, 0x2f, 0x77, 0x70, 0x45, 0x5a, 0x43, +0x53, 0x41, 0x64, 0x38, 0x57, 0x77, 0x46, 0x6c, 0x62, 0x6c, 0x37, 0x48, 0x44, 0x75, 0x67, 0x53, +0x54, 0x39, 0x6a, 0x38, 0x55, 0x30, 0x39, 0x43, 0x41, 0x7a, 0x73, 0x2f, 0x50, 0x36, 0x73, 0x4e, +0x77, 0x36, 0x54, 0x64, 0x37, 0x77, 0x53, 0x6e, 0x55, 0x7a, 0x62, 0x6d, 0x59, 0x59, 0x4f, 0x6e, +0x53, 0x72, 0x47, 0x66, 0x6f, 0x6a, 0x72, 0x32, 0x50, 0x6e, 0x73, 0x31, 0x42, 0x63, 0x58, 0x4f, +0x47, 0x44, 0x47, 0x45, 0x6d, 0x48, 0x36, 0x4c, 0x31, 0x33, 0x37, 0x4c, 0x6b, 0x35, 0x39, 0x63, +0x4f, 0x41, 0x47, 0x44, 0x37, 0x62, 0x73, 0x36, 0x63, 0x4f, 0x58, 0x7a, 0x32, 0x32, 0x57, 0x63, +0x73, 0x58, 0x72, 0x77, 0x34, 0x65, 0x38, 0x6b, 0x51, 0x42, 0x45, 0x79, 0x64, 0x6d, 0x6d, 0x45, +0x35, 0x75, 0x43, 0x56, 0x45, 0x47, 0x4e, 0x6f, 0x62, 0x4f, 0x74, 0x54, 0x43, 0x56, 0x37, 0x61, +0x34, 0x64, 0x67, 0x76, 0x4f, 0x6d, 0x48, 0x41, 0x47, 0x69, 0x7a, 0x63, 0x75, 0x6a, 0x70, 0x69, +0x5a, 0x41, 0x2b, 0x31, 0x59, 0x71, 0x54, 0x4f, 0x6f, 0x36, 0x41, 0x4e, 0x6a, 0x2b, 0x39, 0x39, +0x63, 0x4c, 0x35, 0x68, 0x35, 0x6d, 0x61, 0x49, 0x79, 0x68, 0x48, 0x4a, 0x72, 0x33, 0x66, 0x76, +0x7a, 0x51, 0x35, 0x71, 0x64, 0x57, 0x53, 0x6d, 0x38, 0x54, 0x63, 0x68, 0x2f, 0x76, 0x42, 0x6a, +0x59, 0x71, 0x41, 0x77, 0x33, 0x48, 0x58, 0x73, 0x58, 0x77, 0x58, 0x71, 0x51, 0x54, 0x38, 0x36, +0x50, 0x7a, 0x48, 0x79, 0x70, 0x30, 0x31, 0x56, 0x46, 0x70, 0x4c, 0x49, 0x65, 0x38, 0x73, 0x6a, +0x62, 0x61, 0x32, 0x44, 0x47, 0x44, 0x59, 0x2f, 0x41, 0x2f, 0x67, 0x38, 0x69, 0x6c, 0x45, 0x2f, +0x66, 0x45, 0x76, 0x68, 0x2b, 0x33, 0x55, 0x34, 0x38, 0x50, 0x79, 0x2b, 0x50, 0x62, 0x66, 0x75, +0x31, 0x63, 0x75, 0x75, 0x42, 0x31, 0x2f, 0x4c, 0x34, 0x72, 0x45, 0x4e, 0x35, 0x2f, 0x4e, 0x73, +0x7a, 0x2b, 0x48, 0x62, 0x74, 0x57, 0x41, 0x61, 0x55, 0x68, 0x7a, 0x6e, 0x2f, 0x6e, 0x6d, 0x55, +0x63, 0x63, 0x6d, 0x43, 0x64, 0x7a, 0x35, 0x37, 0x64, 0x6f, 0x33, 0x75, 0x46, 0x37, 0x76, 0x39, +0x6c, 0x71, 0x39, 0x42, 0x54, 0x64, 0x4e, 0x62, 0x4c, 0x68, 0x31, 0x74, 0x74, 0x59, 0x53, 0x30, +0x6e, 0x62, 0x58, 0x6c, 0x73, 0x6a, 0x35, 0x63, 0x4f, 0x71, 0x61, 0x4b, 0x69, 0x4c, 0x62, 0x44, +0x4b, 0x66, 0x33, 0x44, 0x6a, 0x4a, 0x2b, 0x79, 0x34, 0x66, 0x6a, 0x62, 0x55, 0x31, 0x61, 0x4f, +0x6c, 0x39, 0x56, 0x4b, 0x54, 0x45, 0x62, 0x50, 0x32, 0x33, 0x4b, 0x67, 0x62, 0x79, 0x2f, 0x41, +0x44, 0x32, 0x4f, 0x74, 0x74, 0x2f, 0x67, 0x41, 0x35, 0x59, 0x2f, 0x45, 0x4a, 0x38, 0x4c, 0x51, +0x6c, 0x63, 0x2f, 0x42, 0x30, 0x36, 0x48, 0x56, 0x57, 0x47, 0x63, 0x36, 0x6e, 0x6a, 0x41, 0x6f, +0x32, 0x67, 0x63, 0x54, 0x76, 0x74, 0x42, 0x33, 0x59, 0x71, 0x6c, 0x74, 0x35, 0x71, 0x66, 0x56, +0x6c, 0x50, 0x74, 0x37, 0x34, 0x45, 0x51, 0x56, 0x2b, 0x49, 0x66, 0x30, 0x4c, 0x2b, 0x71, 0x65, +0x68, 0x31, 0x4b, 0x37, 0x53, 0x55, 0x4a, 0x54, 0x72, 0x33, 0x77, 0x31, 0x4b, 0x71, 0x77, 0x45, +0x6a, 0x48, 0x43, 0x75, 0x73, 0x45, 0x46, 0x47, 0x4e, 0x4f, 0x47, 0x49, 0x78, 0x2f, 0x49, 0x59, +0x47, 0x36, 0x4f, 0x69, 0x77, 0x79, 0x54, 0x49, 0x4f, 0x69, 0x75, 0x70, 0x33, 0x59, 0x34, 0x55, +0x6c, 0x73, 0x4d, 0x6b, 0x77, 0x74, 0x51, 0x57, 0x31, 0x57, 0x65, 0x58, 0x42, 0x58, 0x74, 0x70, +0x64, 0x63, 0x50, 0x68, 0x32, 0x42, 0x56, 0x78, 0x77, 0x35, 0x68, 0x72, 0x2b, 0x66, 0x64, 0x74, +0x2f, 0x65, 0x4f, 0x36, 0x74, 0x33, 0x7a, 0x4e, 0x51, 0x39, 0x38, 0x36, 0x4b, 0x48, 0x4e, 0x37, +0x66, 0x63, 0x2f, 0x66, 0x58, 0x30, 0x70, 0x71, 0x6f, 0x6e, 0x68, 0x2f, 0x44, 0x39, 0x7a, 0x7a, +0x36, 0x31, 0x52, 0x52, 0x47, 0x54, 0x4e, 0x42, 0x53, 0x6d, 0x63, 0x6a, 0x6e, 0x41, 0x68, 0x71, +0x53, 0x62, 0x51, 0x52, 0x53, 0x55, 0x46, 0x56, 0x63, 0x52, 0x71, 0x43, 0x45, 0x73, 0x77, 0x51, +0x45, 0x51, 0x56, 0x36, 0x4b, 0x35, 0x58, 0x31, 0x7a, 0x30, 0x62, 0x76, 0x76, 0x68, 0x6a, 0x45, +0x65, 0x34, 0x59, 0x49, 0x77, 0x73, 0x36, 0x69, 0x71, 0x31, 0x70, 0x70, 0x42, 0x51, 0x48, 0x35, +0x6e, 0x4b, 0x35, 0x51, 0x58, 0x75, 0x58, 0x77, 0x4e, 0x46, 0x53, 0x6b, 0x37, 0x47, 0x52, 0x56, +0x78, 0x77, 0x35, 0x69, 0x38, 0x63, 0x59, 0x4f, 0x66, 0x36, 0x56, 0x6a, 0x50, 0x4b, 0x4e, 0x4a, +0x4c, 0x79, 0x4f, 0x37, 0x79, 0x45, 0x39, 0x36, 0x72, 0x35, 0x35, 0x61, 0x57, 0x6e, 0x2f, 0x41, +0x35, 0x75, 0x72, 0x4e, 0x53, 0x79, 0x77, 0x77, 0x6e, 0x59, 0x68, 0x67, 0x57, 0x44, 0x69, 0x32, +0x44, 0x69, 0x4e, 0x55, 0x36, 0x62, 0x48, 0x38, 0x4e, 0x77, 0x6b, 0x6a, 0x36, 0x46, 0x66, 0x39, +0x4b, 0x56, 0x6d, 0x71, 0x74, 0x4f, 0x50, 0x4a, 0x42, 0x78, 0x61, 0x75, 0x33, 0x39, 0x6d, 0x53, +0x56, 0x7a, 0x6e, 0x78, 0x2b, 0x44, 0x38, 0x6a, 0x74, 0x33, 0x78, 0x38, 0x74, 0x42, 0x4a, 0x36, +0x44, 0x77, 0x66, 0x63, 0x6d, 0x2f, 0x39, 0x37, 0x58, 0x59, 0x48, 0x61, 0x73, 0x66, 0x69, 0x69, +0x4e, 0x39, 0x6b, 0x74, 0x61, 0x73, 0x45, 0x51, 0x32, 0x6d, 0x44, 0x47, 0x45, 0x66, 0x32, 0x56, +0x69, 0x79, 0x43, 0x54, 0x67, 0x77, 0x37, 0x68, 0x62, 0x75, 0x71, 0x48, 0x37, 0x74, 0x45, 0x4e, +0x79, 0x5a, 0x71, 0x44, 0x2b, 0x62, 0x47, 0x49, 0x42, 0x76, 0x59, 0x49, 0x78, 0x74, 0x33, 0x39, +0x73, 0x49, 0x52, 0x61, 0x52, 0x2b, 0x6f, 0x73, 0x78, 0x76, 0x32, 0x35, 0x62, 0x48, 0x46, 0x69, +0x7a, 0x37, 0x73, 0x32, 0x2f, 0x44, 0x4d, 0x31, 0x47, 0x35, 0x30, 0x6d, 0x30, 0x33, 0x41, 0x77, +0x52, 0x5a, 0x41, 0x61, 0x36, 0x44, 0x32, 0x44, 0x4d, 0x4f, 0x55, 0x73, 0x35, 0x36, 0x66, 0x4e, +0x54, 0x2b, 0x52, 0x73, 0x74, 0x50, 0x5a, 0x36, 0x75, 0x4f, 0x34, 0x79, 0x54, 0x62, 0x75, 0x63, +0x2b, 0x30, 0x48, 0x54, 0x58, 0x61, 0x50, 0x49, 0x56, 0x36, 0x41, 0x42, 0x4d, 0x44, 0x46, 0x4a, +0x64, 0x54, 0x69, 0x6c, 0x4b, 0x77, 0x55, 0x2b, 0x43, 0x56, 0x68, 0x44, 0x45, 0x51, 0x41, 0x58, +0x32, 0x50, 0x4d, 0x66, 0x56, 0x65, 0x69, 0x63, 0x47, 0x62, 0x51, 0x45, 0x45, 0x35, 0x35, 0x33, +0x4d, 0x4a, 0x54, 0x39, 0x63, 0x59, 0x6f, 0x6d, 0x53, 0x2f, 0x59, 0x77, 0x6d, 0x44, 0x32, 0x2f, +0x30, 0x43, 0x37, 0x53, 0x36, 0x71, 0x79, 0x37, 0x76, 0x43, 0x54, 0x2b, 0x74, 0x57, 0x62, 0x38, +0x65, 0x75, 0x58, 0x77, 0x35, 0x7a, 0x57, 0x50, 0x47, 0x39, 0x45, 0x44, 0x65, 0x51, 0x66, 0x62, +0x7a, 0x37, 0x33, 0x6f, 0x2b, 0x6d, 0x32, 0x52, 0x44, 0x62, 0x72, 0x6f, 0x59, 0x2b, 0x6f, 0x36, +0x48, 0x56, 0x61, 0x74, 0x57, 0x55, 0x58, 0x39, 0x55, 0x66, 0x61, 0x39, 0x69, 0x38, 0x50, 0x32, +0x50, 0x50, 0x64, 0x46, 0x39, 0x34, 0x58, 0x48, 0x34, 0x39, 0x33, 0x4e, 0x6f, 0x4c, 0x61, 0x78, +0x68, 0x79, 0x38, 0x47, 0x54, 0x36, 0x66, 0x6d, 0x55, 0x37, 0x6d, 0x6b, 0x4f, 0x6d, 0x51, 0x46, +0x72, 0x57, 0x36, 0x7a, 0x4d, 0x4a, 0x45, 0x67, 0x66, 0x4f, 0x2b, 0x7a, 0x37, 0x7a, 0x58, 0x6a, +0x33, 0x59, 0x79, 0x6f, 0x4b, 0x4c, 0x47, 0x4e, 0x56, 0x70, 0x73, 0x38, 0x69, 0x37, 0x4d, 0x50, +0x61, 0x6e, 0x58, 0x66, 0x65, 0x4a, 0x46, 0x7a, 0x32, 0x31, 0x2f, 0x52, 0x66, 0x2f, 0x79, 0x56, +0x4c, 0x30, 0x72, 0x42, 0x6c, 0x44, 0x5a, 0x6f, 0x30, 0x79, 0x6a, 0x41, 0x54, 0x63, 0x52, 0x67, +0x36, 0x2f, 0x62, 0x72, 0x4c, 0x30, 0x50, 0x6a, 0x78, 0x34, 0x2f, 0x6c, 0x4e, 0x32, 0x37, 0x6e, +0x75, 0x66, 0x54, 0x66, 0x48, 0x53, 0x74, 0x30, 0x64, 0x31, 0x61, 0x75, 0x42, 0x66, 0x48, 0x68, +0x72, 0x4c, 0x6d, 0x79, 0x37, 0x65, 0x6e, 0x57, 0x76, 0x38, 0x68, 0x31, 0x73, 0x32, 0x4d, 0x41, +0x48, 0x4f, 0x2b, 0x35, 0x49, 0x41, 0x4f, 0x7a, 0x39, 0x2f, 0x76, 0x74, 0x51, 0x55, 0x65, 0x48, +0x65, 0x30, 0x53, 0x4a, 0x59, 0x77, 0x38, 0x33, 0x37, 0x75, 0x41, 0x44, 0x7a, 0x79, 0x43, 0x68, +0x34, 0x61, 0x53, 0x66, 0x6f, 0x48, 0x47, 0x42, 0x2f, 0x2b, 0x42, 0x64, 0x70, 0x73, 0x54, 0x50, +0x77, 0x2f, 0x65, 0x62, 0x4a, 0x37, 0x50, 0x66, 0x70, 0x62, 0x73, 0x2f, 0x33, 0x31, 0x6a, 0x47, +0x5a, 0x65, 0x2b, 0x56, 0x78, 0x67, 0x36, 0x45, 0x6a, 0x45, 0x38, 0x72, 0x70, 0x6f, 0x4a, 0x59, +0x36, 0x73, 0x43, 0x47, 0x73, 0x38, 0x4a, 0x36, 0x5a, 0x70, 0x4c, 0x44, 0x68, 0x65, 0x54, 0x37, +0x38, 0x66, 0x76, 0x65, 0x48, 0x38, 0x4c, 0x43, 0x4a, 0x4e, 0x6f, 0x59, 0x51, 0x74, 0x79, 0x2f, +0x54, 0x70, 0x72, 0x69, 0x78, 0x61, 0x44, 0x78, 0x6a, 0x6c, 0x50, 0x76, 0x63, 0x6a, 0x71, 0x4c, +0x47, 0x6d, 0x65, 0x74, 0x54, 0x58, 0x2f, 0x35, 0x37, 0x78, 0x74, 0x50, 0x36, 0x31, 0x4f, 0x2f, +0x33, 0x68, 0x52, 0x32, 0x34, 0x69, 0x6e, 0x32, 0x2b, 0x66, 0x32, 0x34, 0x37, 0x43, 0x76, 0x50, +0x44, 0x39, 0x49, 0x64, 0x73, 0x43, 0x4c, 0x44, 0x57, 0x6d, 0x74, 0x61, 0x32, 0x44, 0x75, 0x4c, +0x50, 0x50, 0x4d, 0x4f, 0x37, 0x51, 0x52, 0x33, 0x58, 0x50, 0x50, 0x51, 0x44, 0x31, 0x31, 0x52, +0x2b, 0x53, 0x32, 0x47, 0x75, 0x7a, 0x2b, 0x57, 0x72, 0x2b, 0x33, 0x4e, 0x6d, 0x76, 0x7a, 0x59, +0x6d, 0x54, 0x4e, 0x69, 0x42, 0x67, 0x39, 0x6f, 0x6d, 0x51, 0x35, 0x30, 0x62, 0x42, 0x4d, 0x50, +0x42, 0x55, 0x47, 0x74, 0x49, 0x61, 0x4a, 0x43, 0x77, 0x70, 0x50, 0x38, 0x64, 0x50, 0x4a, 0x38, +0x2f, 0x69, 0x69, 0x75, 0x66, 0x61, 0x65, 0x5a, 0x70, 0x2f, 0x78, 0x55, 0x43, 0x66, 0x45, 0x35, +0x62, 0x75, 0x51, 0x76, 0x58, 0x44, 0x56, 0x2f, 0x4d, 0x6f, 0x62, 0x76, 0x56, 0x73, 0x66, 0x32, +0x6a, 0x48, 0x61, 0x54, 0x42, 0x36, 0x75, 0x47, 0x4c, 0x68, 0x35, 0x32, 0x51, 0x79, 0x2f, 0x6a, +0x72, 0x72, 0x73, 0x70, 0x75, 0x62, 0x34, 0x31, 0x6c, 0x64, 0x6e, 0x62, 0x72, 0x37, 0x55, 0x42, +0x4c, 0x67, 0x69, 0x43, 0x45, 0x45, 0x55, 0x75, 0x53, 0x67, 0x58, 0x52, 0x77, 0x57, 0x34, 0x30, +0x4b, 0x4a, 0x4f, 0x33, 0x50, 0x5a, 0x57, 0x63, 0x73, 0x6c, 0x67, 0x78, 0x59, 0x77, 0x34, 0x4b, +0x57, 0x59, 0x51, 0x7a, 0x4c, 0x6d, 0x30, 0x2f, 0x4c, 0x6d, 0x70, 0x71, 0x73, 0x32, 0x62, 0x61, +0x33, 0x66, 0x63, 0x70, 0x72, 0x62, 0x64, 0x6e, 0x33, 0x6c, 0x35, 0x6f, 0x4c, 0x44, 0x69, 0x39, +0x46, 0x4b, 0x55, 0x55, 0x71, 0x6c, 0x59, 0x72, 0x57, 0x78, 0x5a, 0x37, 0x6e, 0x4d, 0x57, 0x53, +0x2f, 0x4d, 0x65, 0x67, 0x4f, 0x6d, 0x79, 0x59, 0x52, 0x79, 0x6e, 0x48, 0x39, 0x44, 0x62, 0x30, +0x49, 0x54, 0x50, 0x65, 0x78, 0x6f, 0x6a, 0x75, 0x63, 0x50, 0x55, 0x4d, 0x57, 0x70, 0x2f, 0x78, +0x75, 0x42, 0x73, 0x50, 0x33, 0x32, 0x4a, 0x61, 0x50, 0x50, 0x2f, 0x71, 0x5a, 0x70, 0x6d, 0x62, +0x41, 0x59, 0x52, 0x71, 0x75, 0x4f, 0x48, 0x45, 0x62, 0x35, 0x74, 0x31, 0x30, 0x48, 0x30, 0x59, +0x70, 0x74, 0x72, 0x6e, 0x36, 0x51, 0x76, 0x35, 0x79, 0x31, 0x35, 0x63, 0x59, 0x34, 0x64, 0x4f, +0x5a, 0x53, 0x4e, 0x49, 0x77, 0x72, 0x49, 0x42, 0x39, 0x76, 0x6e, 0x32, 0x44, 0x4a, 0x59, 0x63, +0x65, 0x77, 0x34, 0x32, 0x6e, 0x37, 0x5a, 0x35, 0x39, 0x2b, 0x31, 0x75, 0x78, 0x42, 0x56, 0x50, +0x75, 0x42, 0x43, 0x36, 0x33, 0x34, 0x71, 0x6a, 0x76, 0x42, 0x48, 0x30, 0x53, 0x36, 0x41, 0x72, +0x51, 0x39, 0x33, 0x53, 0x54, 0x34, 0x58, 0x58, 0x72, 0x75, 0x72, 0x56, 0x2f, 0x75, 0x72, 0x31, +0x79, 0x2b, 0x2f, 0x63, 0x44, 0x42, 0x59, 0x6b, 0x56, 0x4b, 0x33, 0x6f, 0x4d, 0x4b, 0x4f, 0x46, +0x33, 0x48, 0x70, 0x6d, 0x52, 0x50, 0x65, 0x2f, 0x39, 0x72, 0x2b, 0x31, 0x58, 0x2f, 0x46, 0x75, +0x68, 0x77, 0x4b, 0x4f, 0x36, 0x34, 0x4a, 0x45, 0x44, 0x2f, 0x73, 0x61, 0x39, 0x4d, 0x57, 0x68, +0x45, 0x4d, 0x72, 0x2b, 0x50, 0x5a, 0x6e, 0x36, 0x4e, 0x6f, 0x72, 0x47, 0x50, 0x7a, 0x54, 0x6b, +0x50, 0x71, 0x2f, 0x61, 0x6d, 0x49, 0x61, 0x44, 0x43, 0x41, 0x6a, 0x61, 0x30, 0x59, 0x4e, 0x72, +0x44, 0x76, 0x62, 0x44, 0x4b, 0x75, 0x6a, 0x6a, 0x6b, 0x72, 0x32, 0x55, 0x46, 0x70, 0x6d, 0x30, +0x44, 0x6b, 0x2f, 0x35, 0x38, 0x6b, 0x33, 0x74, 0x77, 0x67, 0x7a, 0x62, 0x4b, 0x51, 0x6a, 0x43, +0x31, 0x51, 0x73, 0x6e, 0x41, 0x56, 0x65, 0x45, 0x4a, 0x67, 0x53, 0x4c, 0x4b, 0x72, 0x56, 0x4d, +0x74, 0x67, 0x38, 0x75, 0x30, 0x38, 0x2b, 0x38, 0x47, 0x59, 0x79, 0x67, 0x66, 0x4e, 0x4a, 0x4c, +0x63, 0x76, 0x46, 0x7a, 0x6e, 0x51, 0x41, 0x6c, 0x7a, 0x6f, 0x53, 0x56, 0x4b, 0x32, 0x6f, 0x46, +0x41, 0x70, 0x4b, 0x7a, 0x5a, 0x72, 0x56, 0x79, 0x73, 0x32, 0x57, 0x68, 0x4e, 0x73, 0x72, 0x4f, +0x4e, 0x6a, 0x65, 0x74, 0x2b, 0x77, 0x41, 0x64, 0x71, 0x71, 0x79, 0x77, 0x45, 0x32, 0x42, 0x6a, +0x44, 0x33, 0x2f, 0x38, 0x36, 0x77, 0x6b, 0x4a, 0x53, 0x46, 0x59, 0x77, 0x59, 0x55, 0x72, 0x62, +0x5a, 0x74, 0x65, 0x45, 0x50, 0x43, 0x77, 0x4e, 0x4f, 0x66, 0x36, 0x57, 0x44, 0x31, 0x35, 0x38, +0x61, 0x77, 0x38, 0x51, 0x4c, 0x44, 0x79, 0x48, 0x35, 0x2f, 0x54, 0x78, 0x4d, 0x49, 0x73, 0x45, +0x52, 0x74, 0x58, 0x58, 0x30, 0x71, 0x53, 0x6e, 0x6a, 0x6a, 0x65, 0x2b, 0x37, 0x75, 0x4c, 0x62, +0x4b, 0x49, 0x35, 0x34, 0x66, 0x49, 0x38, 0x43, 0x50, 0x30, 0x71, 0x70, 0x44, 0x53, 0x50, 0x53, +0x55, 0x2b, 0x7a, 0x73, 0x34, 0x38, 0x61, 0x4e, 0x38, 0x58, 0x72, 0x2b, 0x6a, 0x67, 0x56, 0x4e, +0x4f, 0x32, 0x5a, 0x33, 0x59, 0x44, 0x31, 0x75, 0x67, 0x32, 0x39, 0x74, 0x5a, 0x58, 0x74, 0x75, +0x50, 0x6b, 0x72, 0x6f, 0x61, 0x58, 0x76, 0x6c, 0x5a, 0x63, 0x47, 0x37, 0x66, 0x46, 0x51, 0x54, +0x4b, 0x5a, 0x63, 0x67, 0x4a, 0x36, 0x30, 0x73, 0x49, 0x6e, 0x46, 0x4e, 0x72, 0x32, 0x71, 0x4d, +0x33, 0x41, 0x33, 0x44, 0x68, 0x51, 0x51, 0x37, 0x4b, 0x36, 0x6a, 0x7a, 0x51, 0x32, 0x6f, 0x52, +0x6f, 0x77, 0x52, 0x79, 0x4d, 0x68, 0x6a, 0x55, 0x62, 0x75, 0x78, 0x78, 0x57, 0x79, 0x45, 0x47, +0x56, 0x51, 0x79, 0x6a, 0x78, 0x76, 0x5a, 0x38, 0x41, 0x55, 0x46, 0x79, 0x63, 0x66, 0x76, 0x2f, +0x4c, 0x62, 0x36, 0x6d, 0x6d, 0x71, 0x75, 0x6c, 0x53, 0x2f, 0x6c, 0x4a, 0x52, 0x54, 0x57, 0x6c, +0x70, 0x36, 0x57, 0x62, 0x66, 0x76, 0x37, 0x48, 0x52, 0x31, 0x6f, 0x59, 0x34, 0x59, 0x71, 0x38, +0x36, 0x31, 0x2f, 0x2f, 0x57, 0x56, 0x39, 0x53, 0x76, 0x58, 0x30, 0x6e, 0x57, 0x64, 0x61, 0x47, +0x5a, 0x6d, 0x6e, 0x50, 0x6a, 0x58, 0x54, 0x5a, 0x4d, 0x35, 0x66, 0x77, 0x71, 0x36, 0x36, 0x2b, +0x34, 0x33, 0x6f, 0x72, 0x50, 0x67, 0x52, 0x6d, 0x73, 0x76, 0x43, 0x47, 0x72, 0x63, 0x51, 0x59, +0x77, 0x53, 0x57, 0x62, 0x49, 0x58, 0x53, 0x69, 0x48, 0x51, 0x67, 0x6d, 0x6d, 0x2f, 0x58, 0x4d, +0x61, 0x46, 0x58, 0x32, 0x4b, 0x4f, 0x58, 0x44, 0x68, 0x44, 0x41, 0x34, 0x34, 0x38, 0x32, 0x67, +0x57, 0x72, 0x65, 0x6a, 0x6b, 0x38, 0x39, 0x6d, 0x72, 0x55, 0x63, 0x5a, 0x6a, 0x32, 0x4f, 0x41, +0x4b, 0x68, 0x6f, 0x38, 0x70, 0x67, 0x69, 0x43, 0x46, 0x47, 0x56, 0x7a, 0x42, 0x51, 0x54, 0x73, +0x31, 0x49, 0x4b, 0x52, 0x69, 0x6a, 0x36, 0x30, 0x72, 0x32, 0x66, 0x47, 0x6a, 0x68, 0x2b, 0x43, +0x6c, 0x32, 0x35, 0x6a, 0x79, 0x2b, 0x6f, 0x39, 0x6f, 0x34, 0x4b, 0x6d, 0x33, 0x4a, 0x33, 0x48, +0x4b, 0x53, 0x44, 0x76, 0x36, 0x65, 0x4a, 0x36, 0x54, 0x33, 0x77, 0x73, 0x74, 0x54, 0x5a, 0x65, +0x6e, 0x4a, 0x62, 0x46, 0x7a, 0x4a, 0x44, 0x34, 0x32, 0x49, 0x39, 0x53, 0x63, 0x4b, 0x39, 0x41, +0x62, 0x4a, 0x44, 0x66, 0x39, 0x4a, 0x44, 0x6a, 0x76, 0x54, 0x39, 0x50, 0x77, 0x67, 0x61, 0x71, +0x71, 0x4b, 0x6b, 0x7a, 0x4c, 0x42, 0x74, 0x53, 0x33, 0x73, 0x2f, 0x46, 0x48, 0x62, 0x34, 0x64, +0x58, 0x58, 0x6f, 0x45, 0x78, 0x45, 0x4e, 0x78, 0x79, 0x43, 0x30, 0x59, 0x4b, 0x2b, 0x72, 0x69, +0x69, 0x48, 0x61, 0x61, 0x6c, 0x42, 0x66, 0x6e, 0x2b, 0x65, 0x33, 0x67, 0x37, 0x37, 0x67, 0x54, +0x39, 0x36, 0x6c, 0x69, 0x34, 0x63, 0x4f, 0x48, 0x2f, 0x4c, 0x2b, 0x33, 0x33, 0x6d, 0x36, 0x44, +0x41, 0x53, 0x53, 0x41, 0x58, 0x6a, 0x64, 0x2f, 0x55, 0x79, 0x4a, 0x42, 0x61, 0x79, 0x52, 0x5a, +0x7a, 0x46, 0x58, 0x76, 0x6c, 0x53, 0x42, 0x61, 0x30, 0x43, 0x6d, 0x59, 0x4f, 0x6c, 0x4c, 0x77, +0x33, 0x49, 0x6d, 0x42, 0x44, 0x6a, 0x73, 0x76, 0x70, 0x6c, 0x36, 0x34, 0x36, 0x72, 0x78, 0x49, +0x30, 0x46, 0x44, 0x56, 0x6b, 0x47, 0x4f, 0x30, 0x6d, 0x7a, 0x53, 0x71, 0x62, 0x53, 0x51, 0x77, +0x61, 0x4f, 0x6c, 0x36, 0x36, 0x51, 0x56, 0x47, 0x7a, 0x53, 0x43, 0x61, 0x53, 0x75, 0x53, 0x41, +0x38, 0x56, 0x72, 0x61, 0x73, 0x63, 0x32, 0x67, 0x30, 0x6a, 0x64, 0x41, 0x42, 0x79, 0x70, 0x4e, +0x34, 0x38, 0x54, 0x71, 0x45, 0x30, 0x6e, 0x52, 0x32, 0x4c, 0x6b, 0x51, 0x6b, 0x68, 0x63, 0x76, +0x44, 0x73, 0x47, 0x75, 0x72, 0x68, 0x71, 0x70, 0x61, 0x4a, 0x7a, 0x53, 0x4b, 0x33, 0x50, 0x78, +0x63, 0x57, 0x74, 0x65, 0x32, 0x41, 0x78, 0x5a, 0x2f, 0x44, 0x77, 0x71, 0x6c, 0x42, 0x4b, 0x4d, +0x47, 0x72, 0x75, 0x58, 0x4d, 0x43, 0x59, 0x75, 0x35, 0x2f, 0x2b, 0x55, 0x47, 0x5a, 0x76, 0x2b, +0x55, 0x6a, 0x39, 0x49, 0x70, 0x74, 0x42, 0x4a, 0x6f, 0x72, 0x53, 0x6b, 0x6f, 0x72, 0x72, 0x4b, +0x41, 0x6a, 0x66, 0x41, 0x4e, 0x58, 0x4f, 0x4d, 0x31, 0x4e, 0x71, 0x63, 0x73, 0x44, 0x6c, 0x7a, +0x70, 0x58, 0x6f, 0x55, 0x2b, 0x43, 0x75, 0x4e, 0x34, 0x48, 0x6f, 0x48, 0x55, 0x50, 0x43, 0x62, +0x2f, 0x44, 0x2b, 0x2f, 0x37, 0x34, 0x52, 0x52, 0x38, 0x39, 0x68, 0x36, 0x78, 0x6c, 0x68, 0x5a, +0x30, 0x56, 0x78, 0x65, 0x35, 0x35, 0x65, 0x56, 0x30, 0x53, 0x64, 0x68, 0x56, 0x47, 0x6a, 0x37, +0x5a, 0x66, 0x6a, 0x73, 0x6f, 0x53, 0x55, 0x4e, 0x36, 0x51, 0x79, 0x52, 0x6b, 0x62, 0x5a, 0x45, +0x48, 0x67, 0x65, 0x61, 0x6a, 0x70, 0x56, 0x4d, 0x77, 0x38, 0x38, 0x6f, 0x70, 0x2f, 0x66, 0x41, +0x74, 0x61, 0x47, 0x75, 0x48, 0x52, 0x42, 0x65, 0x6d, 0x72, 0x42, 0x53, 0x70, 0x59, 0x78, 0x79, +0x52, 0x53, 0x50, 0x4c, 0x66, 0x74, 0x6a, 0x47, 0x30, 0x70, 0x6a, 0x78, 0x71, 0x39, 0x74, 0x67, +0x52, 0x34, 0x6e, 0x45, 0x36, 0x55, 0x6f, 0x70, 0x55, 0x56, 0x34, 0x72, 0x34, 0x44, 0x33, 0x50, +0x49, 0x58, 0x44, 0x57, 0x31, 0x64, 0x4c, 0x71, 0x53, 0x58, 0x74, 0x6f, 0x36, 0x32, 0x4a, 0x4a, +0x43, 0x63, 0x64, 0x51, 0x75, 0x39, 0x52, 0x68, 0x6a, 0x75, 0x48, 0x50, 0x61, 0x66, 0x50, 0x44, +0x49, 0x38, 0x4f, 0x4e, 0x6f, 0x79, 0x6f, 0x76, 0x7a, 0x73, 0x70, 0x43, 0x57, 0x34, 0x66, 0x73, +0x76, 0x62, 0x35, 0x4c, 0x49, 0x56, 0x55, 0x74, 0x5a, 0x6c, 0x74, 0x70, 0x30, 0x58, 0x6e, 0x2f, +0x34, 0x2f, 0x74, 0x46, 0x53, 0x79, 0x6b, 0x42, 0x37, 0x51, 0x6a, 0x67, 0x6f, 0x73, 0x4b, 0x61, +0x7a, 0x73, 0x7a, 0x50, 0x4c, 0x57, 0x65, 0x64, 0x35, 0x48, 0x6b, 0x6f, 0x70, 0x53, 0x68, 0x74, +0x58, 0x6f, 0x6f, 0x4d, 0x55, 0x4a, 0x6b, 0x68, 0x42, 0x5a, 0x5a, 0x56, 0x44, 0x41, 0x67, 0x49, +0x6d, 0x67, 0x35, 0x56, 0x58, 0x57, 0x37, 0x68, 0x78, 0x65, 0x41, 0x7a, 0x4c, 0x6c, 0x55, 0x55, +0x6c, 0x32, 0x78, 0x79, 0x35, 0x54, 0x45, 0x4e, 0x78, 0x41, 0x79, 0x52, 0x68, 0x78, 0x73, 0x49, +0x75, 0x61, 0x76, 0x66, 0x66, 0x6a, 0x33, 0x33, 0x2f, 0x2f, 0x54, 0x78, 0x44, 0x2b, 0x39, 0x63, +0x77, 0x39, 0x50, 0x66, 0x37, 0x63, 0x50, 0x4d, 0x44, 0x50, 0x39, 0x67, 0x6f, 0x38, 0x70, 0x78, +0x46, 0x49, 0x4a, 0x4a, 0x34, 0x48, 0x69, 0x78, 0x66, 0x62, 0x37, 0x69, 0x32, 0x61, 0x69, 0x47, +0x78, 0x6a, 0x39, 0x2f, 0x42, 0x75, 0x2b, 0x77, 0x47, 0x48, 0x6e, 0x39, 0x78, 0x4c, 0x72, 0x66, +0x65, 0x39, 0x67, 0x58, 0x6e, 0x41, 0x32, 0x73, 0x4c, 0x44, 0x64, 0x65, 0x33, 0x72, 0x4f, 0x4c, +0x6f, 0x59, 0x73, 0x56, 0x57, 0x75, 0x51, 0x6f, 0x54, 0x63, 0x35, 0x77, 0x50, 0x57, 0x6c, 0x6a, +0x34, 0x63, 0x4d, 0x79, 0x6c, 0x68, 0x61, 0x75, 0x41, 0x4f, 0x63, 0x6d, 0x41, 0x65, 0x37, 0x6f, +0x45, 0x46, 0x44, 0x65, 0x34, 0x66, 0x44, 0x71, 0x37, 0x69, 0x62, 0x6c, 0x7a, 0x61, 0x50, 0x33, +0x6d, 0x4d, 0x2f, 0x71, 0x67, 0x79, 0x52, 0x6d, 0x33, 0x4c, 0x77, 0x43, 0x71, 0x63, 0x52, 0x55, +0x6d, 0x53, 0x45, 0x55, 0x4b, 0x48, 0x4d, 0x7a, 0x36, 0x6d, 0x75, 0x59, 0x5a, 0x30, 0x79, 0x6d, +0x58, 0x4b, 0x66, 0x4b, 0x4f, 0x2f, 0x4b, 0x4e, 0x6a, 0x74, 0x66, 0x4a, 0x2f, 0x57, 0x2f, 0x74, +0x31, 0x36, 0x37, 0x39, 0x6f, 0x73, 0x4e, 0x61, 0x61, 0x68, 0x76, 0x4e, 0x2f, 0x42, 0x70, 0x45, +0x6b, 0x32, 0x42, 0x77, 0x55, 0x47, 0x4d, 0x43, 0x72, 0x31, 0x75, 0x52, 0x4d, 0x6b, 0x4c, 0x5a, +0x2b, 0x33, 0x6b, 0x5a, 0x46, 0x55, 0x5a, 0x46, 0x67, 0x75, 0x79, 0x62, 0x4a, 0x31, 0x6c, 0x4d, +0x55, 0x68, 0x33, 0x30, 0x6f, 0x6d, 0x64, 0x64, 0x50, 0x38, 0x6d, 0x57, 0x44, 0x34, 0x49, 0x73, +0x47, 0x77, 0x66, 0x4c, 0x53, 0x77, 0x46, 0x61, 0x2f, 0x64, 0x61, 0x53, 0x4f, 0x4b, 0x47, 0x79, +0x74, 0x65, 0x5a, 0x63, 0x6a, 0x6e, 0x57, 0x6a, 0x56, 0x64, 0x4c, 0x55, 0x61, 0x53, 0x6d, 0x6f, +0x43, 0x59, 0x6e, 0x6b, 0x68, 0x6a, 0x33, 0x71, 0x61, 0x53, 0x79, 0x33, 0x69, 0x31, 0x50, 0x4f, +0x45, 0x54, 0x65, 0x4c, 0x36, 0x32, 0x7a, 0x71, 0x71, 0x79, 0x6c, 0x49, 0x49, 0x50, 0x32, 0x46, +0x35, 0x37, 0x37, 0x51, 0x6b, 0x4a, 0x61, 0x43, 0x30, 0x35, 0x6d, 0x4a, 0x69, 0x73, 0x56, 0x79, +0x55, 0x31, 0x6e, 0x51, 0x6b, 0x6b, 0x36, 0x78, 0x65, 0x50, 0x68, 0x6c, 0x6a, 0x6b, 0x6c, 0x47, +0x35, 0x73, 0x4e, 0x6f, 0x2b, 0x52, 0x56, 0x43, 0x64, 0x4e, 0x6b, 0x33, 0x74, 0x7a, 0x4f, 0x2f, +0x67, 0x73, 0x38, 0x5a, 0x77, 0x37, 0x34, 0x56, 0x66, 0x63, 0x63, 0x36, 0x64, 0x32, 0x33, 0x48, +0x32, 0x48, 0x61, 0x4f, 0x52, 0x49, 0x75, 0x42, 0x66, 0x6b, 0x33, 0x37, 0x6b, 0x31, 0x42, 0x73, +0x47, 0x4f, 0x50, 0x2b, 0x48, 0x5a, 0x54, 0x58, 0x47, 0x6d, 0x41, 0x67, 0x47, 0x47, 0x6a, 0x61, +0x63, 0x55, 0x43, 0x34, 0x4a, 0x52, 0x46, 0x70, 0x46, 0x4d, 0x71, 0x62, 0x6e, 0x37, 0x49, 0x66, +0x52, 0x34, 0x41, 0x61, 0x41, 0x64, 0x77, 0x75, 0x33, 0x59, 0x2b, 0x49, 0x57, 0x57, 0x31, 0x48, +0x59, 0x30, 0x6b, 0x69, 0x58, 0x4e, 0x48, 0x67, 0x56, 0x31, 0x65, 0x52, 0x76, 0x4d, 0x59, 0x67, +0x4e, 0x53, 0x31, 0x62, 0x7a, 0x66, 0x58, 0x73, 0x65, 0x77, 0x67, 0x47, 0x4d, 0x4c, 0x6e, 0x6e, +0x74, 0x49, 0x6e, 0x4b, 0x36, 0x32, 0x71, 0x6b, 0x36, 0x56, 0x72, 0x4c, 0x6d, 0x63, 0x51, 0x48, +0x39, 0x42, 0x33, 0x46, 0x2f, 0x63, 0x41, 0x6e, 0x50, 0x31, 0x2b, 0x33, 0x42, 0x59, 0x63, 0x4e, +0x47, 0x55, 0x6c, 0x79, 0x63, 0x6a, 0x31, 0x71, 0x34, 0x44, 0x46, 0x4e, 0x5a, 0x51, 0x36, 0x78, +0x2f, 0x4c, 0x57, 0x32, 0x4e, 0x4c, 0x63, 0x7a, 0x4a, 0x4c, 0x61, 0x42, 0x72, 0x76, 0x53, 0x46, +0x49, 0x53, 0x6c, 0x52, 0x65, 0x4d, 0x65, 0x65, 0x4f, 0x79, 0x30, 0x46, 0x71, 0x75, 0x50, 0x58, +0x4e, 0x44, 0x6b, 0x54, 0x4b, 0x32, 0x63, 0x52, 0x75, 0x52, 0x57, 0x45, 0x54, 0x68, 0x39, 0x49, +0x68, 0x54, 0x51, 0x39, 0x34, 0x34, 0x62, 0x4d, 0x56, 0x61, 0x47, 0x33, 0x6a, 0x79, 0x30, 0x4b, +0x45, 0x6b, 0x46, 0x75, 0x4e, 0x44, 0x6b, 0x75, 0x7a, 0x42, 0x54, 0x4a, 0x4c, 0x65, 0x41, 0x51, +0x32, 0x34, 0x55, 0x56, 0x4c, 0x5a, 0x57, 0x74, 0x4c, 0x2f, 0x49, 0x49, 0x6e, 0x50, 0x46, 0x77, +0x33, 0x47, 0x78, 0x33, 0x57, 0x4c, 0x4c, 0x42, 0x4f, 0x59, 0x74, 0x2f, 0x33, 0x49, 0x37, 0x50, +0x56, 0x39, 0x2f, 0x32, 0x30, 0x79, 0x52, 0x6b, 0x6b, 0x30, 0x61, 0x6b, 0x41, 0x49, 0x31, 0x4e, +0x34, 0x51, 0x57, 0x41, 0x48, 0x33, 0x33, 0x7a, 0x49, 0x69, 0x52, 0x74, 0x79, 0x59, 0x31, 0x62, +0x35, 0x70, 0x53, 0x66, 0x77, 0x50, 0x59, 0x55, 0x49, 0x37, 0x58, 0x77, 0x6a, 0x77, 0x41, 0x2f, +0x74, 0x66, 0x67, 0x45, 0x45, 0x65, 0x41, 0x68, 0x79, 0x66, 0x52, 0x46, 0x56, 0x6a, 0x46, 0x6d, +0x31, 0x75, 0x6f, 0x56, 0x72, 0x6d, 0x72, 0x66, 0x6c, 0x74, 0x48, 0x36, 0x46, 0x31, 0x4e, 0x39, +0x77, 0x4c, 0x56, 0x64, 0x65, 0x66, 0x61, 0x33, 0x39, 0x6a, 0x36, 0x35, 0x32, 0x53, 0x36, 0x45, +0x44, 0x33, 0x4c, 0x37, 0x6b, 0x41, 0x54, 0x6a, 0x2b, 0x47, 0x75, 0x5a, 0x30, 0x6a, 0x4f, 0x65, +0x69, 0x67, 0x35, 0x39, 0x6e, 0x7a, 0x4b, 0x34, 0x4e, 0x4a, 0x46, 0x4d, 0x70, 0x79, 0x39, 0x69, +0x6f, 0x44, 0x51, 0x76, 0x58, 0x4b, 0x32, 0x35, 0x71, 0x55, 0x6f, 0x77, 0x76, 0x46, 0x68, 0x7a, +0x57, 0x52, 0x31, 0x45, 0x5a, 0x44, 0x7a, 0x43, 0x65, 0x6b, 0x31, 0x38, 0x52, 0x30, 0x4a, 0x77, +0x4d, 0x65, 0x4b, 0x5a, 0x5a, 0x38, 0x48, 0x78, 0x7a, 0x51, 0x43, 0x65, 0x43, 0x73, 0x57, 0x54, +0x6a, 0x41, 0x48, 0x4c, 0x32, 0x33, 0x4a, 0x75, 0x79, 0x6b, 0x6d, 0x4c, 0x69, 0x6f, 0x37, 0x64, +0x50, 0x4b, 0x32, 0x46, 0x49, 0x4b, 0x75, 0x76, 0x61, 0x4c, 0x44, 0x35, 0x75, 0x48, 0x79, 0x72, +0x79, 0x63, 0x6f, 0x6e, 0x76, 0x74, 0x4a, 0x74, 0x54, 0x62, 0x67, 0x6b, 0x36, 0x39, 0x37, 0x65, +0x31, 0x58, 0x79, 0x2f, 0x4b, 0x48, 0x78, 0x31, 0x46, 0x45, 0x6f, 0x4b, 0x75, 0x7a, 0x55, 0x4f, +0x42, 0x4e, 0x5a, 0x42, 0x7a, 0x6f, 0x43, 0x52, 0x34, 0x53, 0x2b, 0x43, 0x56, 0x53, 0x2f, 0x77, +0x74, 0x4a, 0x59, 0x6b, 0x37, 0x4a, 0x66, 0x6d, 0x58, 0x42, 0x67, 0x53, 0x31, 0x69, 0x76, 0x79, +0x46, 0x67, 0x74, 0x30, 0x33, 0x43, 0x48, 0x61, 0x64, 0x4c, 0x56, 0x6d, 0x58, 0x49, 0x35, 0x6c, +0x56, 0x70, 0x2f, 0x68, 0x6b, 0x73, 0x47, 0x44, 0x31, 0x64, 0x67, 0x4a, 0x63, 0x39, 0x72, 0x44, +0x6e, 0x57, 0x45, 0x30, 0x37, 0x4f, 0x68, 0x58, 0x6d, 0x62, 0x68, 0x2f, 0x57, 0x78, 0x65, 0x6d, +0x38, 0x66, 0x42, 0x39, 0x79, 0x71, 0x31, 0x34, 0x6a, 0x4e, 0x36, 0x65, 0x58, 0x41, 0x59, 0x41, +0x30, 0x71, 0x36, 0x70, 0x36, 0x45, 0x44, 0x78, 0x76, 0x4e, 0x62, 0x43, 0x63, 0x4d, 0x46, 0x76, +0x72, 0x33, 0x6d, 0x39, 0x75, 0x70, 0x44, 0x6d, 0x52, 0x77, 0x31, 0x34, 0x4e, 0x2f, 0x38, 0x66, +0x53, 0x31, 0x6b, 0x48, 0x4d, 0x57, 0x7a, 0x65, 0x57, 0x55, 0x56, 0x74, 0x65, 0x78, 0x42, 0x57, +0x37, 0x2f, 0x59, 0x6b, 0x30, 0x4c, 0x33, 0x75, 0x43, 0x6d, 0x77, 0x36, 0x47, 0x30, 0x38, 0x35, +0x78, 0x42, 0x42, 0x31, 0x61, 0x32, 0x61, 0x6b, 0x49, 0x7a, 0x61, 0x6a, 0x42, 0x36, 0x7a, 0x6e, +0x76, 0x37, 0x68, 0x33, 0x74, 0x50, 0x59, 0x7a, 0x42, 0x4d, 0x2f, 0x44, 0x6e, 0x76, 0x32, 0x2f, +0x42, 0x36, 0x4f, 0x47, 0x74, 0x7a, 0x50, 0x6f, 0x68, 0x4a, 0x32, 0x77, 0x71, 0x44, 0x4e, 0x42, +0x77, 0x38, 0x43, 0x78, 0x75, 0x76, 0x6e, 0x51, 0x6f, 0x71, 0x35, 0x6f, 0x44, 0x35, 0x36, 0x6c, +0x4f, 0x41, 0x34, 0x4c, 0x2b, 0x64, 0x4f, 0x75, 0x69, 0x69, 0x4b, 0x64, 0x4e, 0x4b, 0x46, 0x73, +0x31, 0x57, 0x54, 0x70, 0x73, 0x65, 0x50, 0x2b, 0x71, 0x50, 0x50, 0x37, 0x76, 0x32, 0x6e, 0x63, +0x34, 0x2b, 0x2b, 0x67, 0x44, 0x38, 0x50, 0x4c, 0x7a, 0x65, 0x57, 0x46, 0x52, 0x6e, 0x4f, 0x47, +0x69, 0x69, 0x4a, 0x67, 0x77, 0x7a, 0x4e, 0x74, 0x59, 0x7a, 0x7a, 0x34, 0x44, 0x38, 0x39, 0x6b, +0x77, 0x64, 0x7a, 0x31, 0x43, 0x47, 0x54, 0x78, 0x70, 0x30, 0x45, 0x4a, 0x53, 0x66, 0x5a, 0x7a, +0x6c, 0x62, 0x61, 0x73, 0x35, 0x53, 0x62, 0x48, 0x6d, 0x62, 0x51, 0x6b, 0x53, 0x5a, 0x68, 0x31, +0x38, 0x4d, 0x67, 0x65, 0x56, 0x6c, 0x76, 0x44, 0x63, 0x34, 0x67, 0x61, 0x32, 0x4c, 0x35, 0x55, +0x6f, 0x62, 0x66, 0x69, 0x38, 0x5a, 0x47, 0x63, 0x4f, 0x32, 0x33, 0x6f, 0x35, 0x61, 0x2b, 0x61, +0x30, 0x6b, 0x41, 0x67, 0x43, 0x41, 0x71, 0x6c, 0x49, 0x43, 0x73, 0x58, 0x62, 0x73, 0x2b, 0x64, +0x53, 0x46, 0x42, 0x4e, 0x30, 0x4e, 0x75, 0x57, 0x52, 0x4b, 0x7a, 0x55, 0x51, 0x49, 0x4c, 0x56, +0x39, 0x45, 0x32, 0x58, 0x73, 0x73, 0x34, 0x2b, 0x6f, 0x4c, 0x30, 0x55, 0x62, 0x7a, 0x62, 0x78, +0x6c, 0x72, 0x61, 0x78, 0x63, 0x6e, 0x33, 0x44, 0x31, 0x41, 0x57, 0x44, 0x30, 0x6f, 0x44, 0x34, +0x6f, 0x62, 0x66, 0x6a, 0x71, 0x35, 0x2f, 0x56, 0x57, 0x30, 0x4c, 0x53, 0x42, 0x49, 0x4b, 0x43, +0x6b, 0x2f, 0x78, 0x72, 0x2b, 0x65, 0x6d, 0x73, 0x56, 0x79, 0x39, 0x65, 0x71, 0x43, 0x4d, 0x61, +0x4c, 0x43, 0x42, 0x44, 0x4b, 0x63, 0x4d, 0x42, 0x6c, 0x36, 0x78, 0x77, 0x76, 0x6e, 0x56, 0x31, +0x79, 0x43, 0x4b, 0x45, 0x64, 0x51, 0x61, 0x56, 0x68, 0x59, 0x47, 0x32, 0x63, 0x44, 0x2b, 0x39, +0x64, 0x79, 0x49, 0x58, 0x2f, 0x36, 0x42, 0x39, 0x5a, 0x46, 0x64, 0x62, 0x4b, 0x73, 0x63, 0x6c, +0x49, 0x76, 0x75, 0x2b, 0x37, 0x6b, 0x47, 0x65, 0x47, 0x77, 0x4b, 0x58, 0x73, 0x37, 0x4b, 0x55, +0x44, 0x67, 0x52, 0x63, 0x45, 0x42, 0x49, 0x43, 0x36, 0x46, 0x44, 0x7a, 0x50, 0x73, 0x65, 0x4b, +0x47, 0x32, 0x58, 0x70, 0x5a, 0x64, 0x4f, 0x79, 0x39, 0x79, 0x49, 0x2b, 0x78, 0x64, 0x52, 0x2f, +0x62, 0x64, 0x6f, 0x43, 0x32, 0x78, 0x43, 0x69, 0x47, 0x44, 0x61, 0x35, 0x49, 0x34, 0x38, 0x62, +0x47, 0x58, 0x35, 0x75, 0x65, 0x46, 0x6c, 0x4d, 0x32, 0x44, 0x41, 0x72, 0x41, 0x6c, 0x50, 0x73, +0x42, 0x47, 0x4e, 0x30, 0x58, 0x5a, 0x72, 0x78, 0x78, 0x4c, 0x4d, 0x62, 0x41, 0x38, 0x55, 0x63, +0x4e, 0x51, 0x34, 0x2b, 0x38, 0x45, 0x4b, 0x30, 0x55, 0x6b, 0x77, 0x64, 0x49, 0x4a, 0x69, 0x2b, +0x53, 0x76, 0x4c, 0x5a, 0x65, 0x38, 0x76, 0x46, 0x47, 0x77, 0x59, 0x52, 0x79, 0x77, 0x55, 0x48, +0x50, 0x2b, 0x53, 0x41, 0x38, 0x58, 0x6a, 0x30, 0x32, 0x34, 0x49, 0x6d, 0x6d, 0x67, 0x4f, 0x56, +0x64, 0x4c, 0x69, 0x79, 0x62, 0x34, 0x7a, 0x67, 0x4e, 0x67, 0x63, 0x4c, 0x72, 0x4a, 0x79, 0x4d, +0x6e, 0x2f, 0x41, 0x47, 0x7a, 0x73, 0x51, 0x31, 0x38, 0x44, 0x37, 0x46, 0x77, 0x6b, 0x59, 0x30, +0x53, 0x64, 0x58, 0x56, 0x5a, 0x72, 0x6b, 0x55, 0x68, 0x43, 0x42, 0x37, 0x36, 0x4a, 0x79, 0x59, +0x33, 0x7a, 0x30, 0x61, 0x4f, 0x59, 0x6a, 0x37, 0x42, 0x37, 0x4f, 0x2f, 0x77, 0x79, 0x30, 0x6f, +0x70, 0x76, 0x6d, 0x59, 0x79, 0x38, 0x75, 0x4b, 0x33, 0x66, 0x31, 0x50, 0x37, 0x62, 0x51, 0x34, +0x4b, 0x58, 0x44, 0x73, 0x75, 0x41, 0x62, 0x4a, 0x72, 0x38, 0x31, 0x42, 0x67, 0x48, 0x79, 0x42, +0x58, 0x49, 0x52, 0x63, 0x6f, 0x38, 0x76, 0x35, 0x6f, 0x45, 0x79, 0x66, 0x55, 0x65, 0x6f, 0x6e, +0x70, 0x45, 0x46, 0x41, 0x72, 0x6b, 0x44, 0x39, 0x61, 0x6e, 0x6a, 0x70, 0x55, 0x51, 0x4a, 0x2f, +0x4f, 0x4a, 0x41, 0x65, 0x76, 0x44, 0x54, 0x6a, 0x77, 0x61, 0x38, 0x48, 0x79, 0x6e, 0x34, 0x74, +0x34, 0x38, 0x63, 0x4f, 0x77, 0x70, 0x53, 0x32, 0x4c, 0x54, 0x65, 0x7a, 0x62, 0x6b, 0x30, 0x6b, +0x32, 0x50, 0x59, 0x56, 0x33, 0x33, 0x6e, 0x58, 0x6b, 0x4c, 0x46, 0x70, 0x49, 0x79, 0x76, 0x50, +0x49, 0x36, 0x64, 0x75, 0x39, 0x38, 0x37, 0x4a, 0x5a, 0x56, 0x54, 0x4f, 0x76, 0x4e, 0x79, 0x37, +0x36, 0x30, 0x42, 0x6e, 0x6b, 0x73, 0x6c, 0x66, 0x44, 0x69, 0x79, 0x78, 0x74, 0x48, 0x59, 0x7a, +0x55, 0x69, 0x6e, 0x30, 0x47, 0x50, 0x73, 0x76, 0x62, 0x69, 0x34, 0x2f, 0x73, 0x39, 0x58, 0x71, +0x6c, 0x4c, 0x65, 0x6a, 0x47, 0x68, 0x74, 0x65, 0x73, 0x42, 0x66, 0x44, 0x6e, 0x51, 0x33, 0x2f, +0x6b, 0x33, 0x48, 0x2f, 0x73, 0x67, 0x44, 0x48, 0x61, 0x4f, 0x67, 0x4f, 0x52, 0x61, 0x4b, 0x4d, +0x35, 0x59, 0x39, 0x2f, 0x58, 0x4f, 0x4f, 0x75, 0x48, 0x49, 0x36, 0x4c, 0x52, 0x45, 0x41, 0x4d, +0x6b, 0x4a, 0x59, 0x48, 0x55, 0x70, 0x45, 0x53, 0x6f, 0x2f, 0x44, 0x6f, 0x71, 0x77, 0x43, 0x46, +0x6c, 0x4f, 0x68, 0x76, 0x4d, 0x6c, 0x6b, 0x38, 0x50, 0x73, 0x38, 0x46, 0x73, 0x55, 0x67, 0x67, +0x6b, 0x71, 0x52, 0x71, 0x35, 0x48, 0x61, 0x2b, 0x74, 0x4b, 0x65, 0x46, 0x54, 0x66, 0x7a, 0x6a, +0x4a, 0x66, 0x76, 0x56, 0x34, 0x57, 0x6a, 0x46, 0x6a, 0x63, 0x59, 0x78, 0x6c, 0x77, 0x30, 0x61, +0x79, 0x37, 0x59, 0x34, 0x53, 0x30, 0x57, 0x4b, 0x54, 0x64, 0x37, 0x6a, 0x68, 0x62, 0x6e, 0x4a, +0x4b, 0x44, 0x57, 0x76, 0x2b, 0x65, 0x41, 0x54, 0x56, 0x2f, 0x33, 0x34, 0x5a, 0x78, 0x76, 0x70, +0x77, 0x64, 0x43, 0x75, 0x35, 0x62, 0x37, 0x2f, 0x42, 0x55, 0x31, 0x56, 0x48, 0x38, 0x76, 0x45, +0x53, 0x77, 0x59, 0x61, 0x38, 0x4f, 0x43, 0x4b, 0x51, 0x76, 0x50, 0x58, 0x64, 0x64, 0x38, 0x7a, +0x63, 0x6f, 0x67, 0x2b, 0x37, 0x35, 0x32, 0x68, 0x55, 0x4b, 0x6f, 0x46, 0x49, 0x65, 0x65, 0x54, +0x46, 0x66, 0x58, 0x59, 0x62, 0x4d, 0x70, 0x42, 0x31, 0x38, 0x37, 0x34, 0x67, 0x35, 0x76, 0x64, +0x48, 0x42, 0x4e, 0x49, 0x4e, 0x41, 0x4f, 0x6b, 0x31, 0x76, 0x56, 0x43, 0x61, 0x50, 0x55, 0x64, +0x59, 0x7a, 0x45, 0x4d, 0x79, 0x70, 0x66, 0x68, 0x32, 0x36, 0x51, 0x61, 0x55, 0x30, 0x75, 0x79, +0x35, 0x56, 0x54, 0x55, 0x37, 0x44, 0x79, 0x33, 0x48, 0x47, 0x4d, 0x4d, 0x6e, 0x50, 0x36, 0x79, +0x4e, 0x6b, 0x6d, 0x38, 0x49, 0x4a, 0x50, 0x4d, 0x33, 0x44, 0x71, 0x4f, 0x36, 0x36, 0x52, 0x4c, +0x6b, 0x79, 0x71, 0x55, 0x32, 0x56, 0x43, 0x59, 0x6b, 0x57, 0x67, 0x71, 0x65, 0x57, 0x48, 0x70, +0x73, 0x52, 0x6c, 0x77, 0x39, 0x35, 0x4c, 0x63, 0x4c, 0x6f, 0x76, 0x4f, 0x63, 0x59, 0x44, 0x42, +0x7a, 0x2b, 0x5a, 0x51, 0x33, 0x67, 0x70, 0x6e, 0x57, 0x2b, 0x6c, 0x41, 0x32, 0x5a, 0x30, 0x52, +0x4a, 0x51, 0x79, 0x77, 0x57, 0x63, 0x7a, 0x42, 0x58, 0x69, 0x50, 0x75, 0x67, 0x74, 0x57, 0x65, +0x58, 0x44, 0x4b, 0x6c, 0x55, 0x6c, 0x42, 0x48, 0x6e, 0x79, 0x51, 0x78, 0x57, 0x34, 0x6d, 0x37, +0x39, 0x76, 0x38, 0x6e, 0x79, 0x37, 0x72, 0x33, 0x30, 0x2f, 0x39, 0x77, 0x62, 0x37, 0x32, 0x62, +0x34, 0x32, 0x43, 0x4b, 0x59, 0x73, 0x39, 0x43, 0x43, 0x74, 0x45, 0x4b, 0x77, 0x56, 0x6d, 0x42, +0x72, 0x38, 0x70, 0x6c, 0x55, 0x43, 0x72, 0x6e, 0x33, 0x33, 0x6c, 0x6b, 0x55, 0x58, 0x53, 0x68, +0x46, 0x66, 0x45, 0x51, 0x39, 0x62, 0x33, 0x33, 0x54, 0x77, 0x52, 0x68, 0x41, 0x6f, 0x36, 0x68, +0x48, 0x63, 0x50, 0x74, 0x73, 0x6e, 0x2f, 0x4f, 0x32, 0x46, 0x71, 0x78, 0x4f, 0x43, 0x65, 0x70, +0x66, 0x42, 0x58, 0x56, 0x63, 0x4f, 0x30, 0x59, 0x4c, 0x36, 0x6c, 0x36, 0x41, 0x5a, 0x54, 0x76, +0x59, 0x4f, 0x48, 0x79, 0x34, 0x42, 0x4a, 0x48, 0x61, 0x50, 0x6e, 0x2f, 0x79, 0x33, 0x6f, 0x66, +0x77, 0x4b, 0x36, 0x70, 0x51, 0x4b, 0x31, 0x63, 0x34, 0x33, 0x35, 0x5a, 0x4e, 0x39, 0x54, 0x56, +0x61, 0x59, 0x51, 0x6f, 0x4c, 0x62, 0x52, 0x6e, 0x76, 0x2f, 0x37, 0x36, 0x4b, 0x53, 0x58, 0x5a, +0x6c, 0x6f, 0x43, 0x51, 0x46, 0x73, 0x51, 0x45, 0x44, 0x36, 0x46, 0x6a, 0x52, 0x52, 0x42, 0x44, +0x49, 0x33, 0x39, 0x52, 0x2b, 0x33, 0x61, 0x48, 0x41, 0x51, 0x32, 0x2f, 0x74, 0x73, 0x44, 0x4f, +0x2f, 0x53, 0x49, 0x4c, 0x73, 0x67, 0x69, 0x42, 0x42, 0x2f, 0x39, 0x33, 0x75, 0x41, 0x35, 0x6d, +0x45, 0x49, 0x4d, 0x45, 0x33, 0x35, 0x39, 0x66, 0x33, 0x68, 0x41, 0x49, 0x62, 0x49, 0x59, 0x6d, +0x50, 0x63, 0x63, 0x41, 0x58, 0x4c, 0x63, 0x6a, 0x39, 0x6f, 0x34, 0x54, 0x71, 0x46, 0x4b, 0x70, +0x52, 0x34, 0x71, 0x57, 0x53, 0x35, 0x4c, 0x71, 0x47, 0x61, 0x34, 0x6b, 0x56, 0x38, 0x6c, 0x6e, +0x74, 0x7a, 0x73, 0x79, 0x75, 0x33, 0x4a, 0x57, 0x57, 0x55, 0x58, 0x76, 0x42, 0x47, 0x39, 0x63, +0x41, 0x4f, 0x78, 0x50, 0x47, 0x74, 0x75, 0x50, 0x62, 0x44, 0x71, 0x4e, 0x39, 0x6d, 0x4b, 0x62, +0x34, 0x32, 0x71, 0x75, 0x4a, 0x50, 0x58, 0x41, 0x50, 0x38, 0x55, 0x51, 0x75, 0x78, 0x71, 0x52, +0x36, 0x36, 0x63, 0x51, 0x30, 0x71, 0x36, 0x6f, 0x31, 0x56, 0x31, 0x7a, 0x69, 0x68, 0x67, 0x32, +0x71, 0x34, 0x2f, 0x6c, 0x4a, 0x70, 0x69, 0x38, 0x2b, 0x69, 0x69, 0x33, 0x4c, 0x50, 0x36, 0x65, +0x75, 0x65, 0x41, 0x47, 0x76, 0x4c, 0x54, 0x69, 0x65, 0x50, 0x76, 0x6c, 0x72, 0x73, 0x67, 0x51, +0x67, 0x76, 0x4e, 0x37, 0x6f, 0x74, 0x48, 0x63, 0x66, 0x5a, 0x38, 0x34, 0x39, 0x39, 0x4d, 0x6f, +0x51, 0x74, 0x49, 0x75, 0x37, 0x61, 0x36, 0x57, 0x63, 0x77, 0x6d, 0x73, 0x65, 0x66, 0x75, 0x63, +0x67, 0x5a, 0x2f, 0x71, 0x45, 0x71, 0x79, 0x64, 0x44, 0x52, 0x47, 0x4f, 0x74, 0x37, 0x58, 0x6f, +0x72, 0x5a, 0x42, 0x77, 0x4f, 0x63, 0x77, 0x54, 0x43, 0x73, 0x6b, 0x72, 0x61, 0x72, 0x5a, 0x2b, +0x31, 0x6f, 0x31, 0x57, 0x79, 0x36, 0x31, 0x2f, 0x4e, 0x44, 0x66, 0x34, 0x42, 0x33, 0x4e, 0x34, +0x41, 0x6c, 0x57, 0x57, 0x47, 0x42, 0x53, 0x34, 0x4e, 0x75, 0x71, 0x72, 0x42, 0x73, 0x45, 0x59, +0x5a, 0x56, 0x67, 0x70, 0x44, 0x72, 0x4e, 0x43, 0x51, 0x55, 0x6f, 0x62, 0x6d, 0x71, 0x36, 0x2b, +0x69, 0x59, 0x4d, 0x33, 0x33, 0x71, 0x50, 0x59, 0x4f, 0x56, 0x6b, 0x38, 0x34, 0x69, 0x4a, 0x5a, +0x74, 0x39, 0x34, 0x4c, 0x67, 0x62, 0x47, 0x36, 0x65, 0x44, 0x52, 0x63, 0x65, 0x37, 0x69, 0x4e, +0x54, 0x58, 0x55, 0x7a, 0x76, 0x4c, 0x45, 0x59, 0x4b, 0x6a, 0x56, 0x41, 0x70, 0x35, 0x73, 0x35, +0x70, 0x5a, 0x4b, 0x61, 0x45, 0x41, 0x42, 0x2b, 0x52, 0x54, 0x46, 0x45, 0x6f, 0x57, 0x31, 0x6a, +0x2b, 0x2b, 0x66, 0x75, 0x73, 0x62, 0x56, 0x70, 0x44, 0x67, 0x53, 0x69, 0x6d, 0x56, 0x56, 0x67, +0x4c, 0x49, 0x49, 0x68, 0x43, 0x56, 0x76, 0x59, 0x64, 0x5a, 0x73, 0x78, 0x62, 0x69, 0x7a, 0x47, +0x61, 0x37, 0x35, 0x65, 0x33, 0x52, 0x6b, 0x6b, 0x36, 0x37, 0x38, 0x39, 0x72, 0x59, 0x6b, 0x4e, +0x48, 0x30, 0x6c, 0x46, 0x45, 0x32, 0x62, 0x5a, 0x51, 0x57, 0x6f, 0x4f, 0x55, 0x62, 0x42, 0x6e, +0x37, 0x6b, 0x51, 0x73, 0x72, 0x61, 0x6c, 0x69, 0x61, 0x6b, 0x6a, 0x5a, 0x31, 0x57, 0x78, 0x69, +0x65, 0x58, 0x48, 0x34, 0x63, 0x52, 0x2f, 0x64, 0x39, 0x6c, 0x6b, 0x43, 0x34, 0x6d, 0x56, 0x2b, +0x6d, 0x5a, 0x2f, 0x37, 0x77, 0x4f, 0x4b, 0x51, 0x6d, 0x7a, 0x6c, 0x66, 0x4d, 0x35, 0x54, 0x52, +0x6e, 0x4e, 0x59, 0x53, 0x35, 0x38, 0x6c, 0x4c, 0x32, 0x39, 0x4a, 0x32, 0x45, 0x39, 0x52, 0x52, +0x4e, 0x6b, 0x45, 0x4b, 0x35, 0x6e, 0x41, 0x6e, 0x66, 0x7a, 0x57, 0x43, 0x39, 0x39, 0x58, 0x39, +0x76, 0x38, 0x72, 0x49, 0x70, 0x2b, 0x64, 0x6c, 0x6d, 0x38, 0x6c, 0x38, 0x77, 0x6d, 0x52, 0x5a, +0x41, 0x35, 0x72, 0x62, 0x58, 0x58, 0x75, 0x69, 0x55, 0x49, 0x4f, 0x66, 0x4c, 0x7a, 0x35, 0x31, +0x31, 0x61, 0x50, 0x30, 0x57, 0x42, 0x6f, 0x4d, 0x78, 0x73, 0x4e, 0x2f, 0x38, 0x5a, 0x74, 0x69, +0x36, 0x46, 0x71, 0x45, 0x6c, 0x44, 0x79, 0x36, 0x57, 0x4c, 0x4e, 0x7a, 0x4b, 0x35, 0x69, 0x4d, +0x55, 0x65, 0x59, 0x49, 0x66, 0x44, 0x67, 0x6f, 0x59, 0x39, 0x53, 0x38, 0x66, 0x41, 0x6f, 0x2b, +0x66, 0x54, 0x6d, 0x6d, 0x6e, 0x64, 0x45, 0x33, 0x41, 0x36, 0x73, 0x43, 0x68, 0x4d, 0x54, 0x32, +0x4c, 0x6d, 0x4e, 0x52, 0x41, 0x2f, 0x49, 0x53, 0x6a, 0x38, 0x58, 0x66, 0x59, 0x43, 0x59, 0x59, +0x4f, 0x73, 0x2f, 0x6a, 0x2b, 0x56, 0x4d, 0x70, 0x5a, 0x41, 0x41, 0x6e, 0x6b, 0x56, 0x31, 0x2f, +0x61, 0x44, 0x4d, 0x43, 0x39, 0x78, 0x6c, 0x73, 0x6e, 0x6e, 0x4a, 0x62, 0x45, 0x50, 0x42, 0x2b, +0x56, 0x54, 0x4f, 0x47, 0x58, 0x56, 0x35, 0x41, 0x37, 0x2f, 0x57, 0x30, 0x37, 0x73, 0x66, 0x79, +0x47, 0x39, 0x75, 0x73, 0x4f, 0x42, 0x56, 0x34, 0x39, 0x4c, 0x51, 0x30, 0x46, 0x62, 0x74, 0x6a, +0x33, 0x63, 0x52, 0x42, 0x4a, 0x6c, 0x72, 0x78, 0x78, 0x55, 0x6d, 0x51, 0x42, 0x6c, 0x42, 0x37, +0x53, 0x44, 0x51, 0x6f, 0x73, 0x67, 0x64, 0x52, 0x30, 0x54, 0x63, 0x34, 0x65, 0x41, 0x58, 0x4b, +0x6c, 0x78, 0x4b, 0x38, 0x4c, 0x38, 0x50, 0x73, 0x48, 0x36, 0x43, 0x63, 0x43, 0x59, 0x74, 0x38, +0x4a, 0x32, 0x73, 0x6e, 0x6e, 0x35, 0x36, 0x71, 0x78, 0x7a, 0x4b, 0x72, 0x61, 0x69, 0x54, 0x6b, +0x56, 0x4f, 0x37, 0x4b, 0x71, 0x73, 0x4a, 0x34, 0x75, 0x6b, 0x38, 0x4f, 0x77, 0x66, 0x41, 0x48, +0x38, 0x6a, 0x4e, 0x62, 0x67, 0x65, 0x62, 0x5a, 0x6a, 0x50, 0x6c, 0x2f, 0x30, 0x48, 0x56, 0x76, +0x76, 0x47, 0x5a, 0x43, 0x73, 0x4e, 0x33, 0x77, 0x31, 0x35, 0x78, 0x33, 0x47, 0x62, 0x74, 0x39, +0x4a, 0x62, 0x69, 0x2b, 0x64, 0x46, 0x35, 0x70, 0x37, 0x55, 0x6f, 0x4b, 0x4f, 0x67, 0x58, 0x65, +0x6a, 0x77, 0x4b, 0x78, 0x79, 0x72, 0x4b, 0x34, 0x79, 0x34, 0x49, 0x4c, 0x55, 0x2b, 0x64, 0x78, +0x77, 0x78, 0x49, 0x4e, 0x38, 0x6d, 0x39, 0x6f, 0x4a, 0x6f, 0x58, 0x63, 0x6b, 0x76, 0x37, 0x32, +0x46, 0x79, 0x56, 0x4e, 0x4f, 0x77, 0x4e, 0x79, 0x61, 0x77, 0x65, 0x72, 0x61, 0x49, 0x4a, 0x45, +0x76, 0x67, 0x6a, 0x35, 0x45, 0x57, 0x47, 0x43, 0x46, 0x44, 0x4e, 0x4e, 0x67, 0x4e, 0x62, 0x4d, +0x58, 0x6c, 0x76, 0x44, 0x41, 0x78, 0x64, 0x39, 0x77, 0x35, 0x69, 0x33, 0x62, 0x59, 0x4c, 0x6e, +0x62, 0x46, 0x49, 0x39, 0x4f, 0x57, 0x73, 0x53, 0x66, 0x72, 0x75, 0x73, 0x50, 0x52, 0x6c, 0x76, +0x58, 0x6e, 0x77, 0x4b, 0x44, 0x5a, 0x73, 0x45, 0x62, 0x4f, 0x7a, 0x47, 0x67, 0x66, 0x34, 0x6e, +0x7a, 0x49, 0x38, 0x44, 0x4a, 0x74, 0x79, 0x79, 0x4b, 0x49, 0x4b, 0x55, 0x76, 0x58, 0x7a, 0x4d, +0x30, 0x4d, 0x73, 0x47, 0x36, 0x72, 0x35, 0x38, 0x38, 0x7a, 0x2b, 0x50, 0x7a, 0x41, 0x77, 0x2f, +0x6e, 0x77, 0x4c, 0x63, 0x31, 0x79, 0x6e, 0x68, 0x52, 0x5a, 0x61, 0x4f, 0x49, 0x39, 0x79, 0x43, +0x44, 0x41, 0x38, 0x46, 0x67, 0x36, 0x48, 0x50, 0x4e, 0x6a, 0x56, 0x54, 0x33, 0x4d, 0x61, 0x77, +0x2b, 0x34, 0x69, 0x42, 0x71, 0x70, 0x72, 0x35, 0x42, 0x73, 0x73, 0x32, 0x44, 0x6a, 0x35, 0x6f, +0x42, 0x61, 0x5a, 0x63, 0x58, 0x55, 0x6b, 0x66, 0x6c, 0x72, 0x77, 0x4b, 0x68, 0x43, 0x59, 0x79, +0x78, 0x33, 0x6d, 0x36, 0x68, 0x75, 0x4f, 0x42, 0x6f, 0x43, 0x46, 0x49, 0x66, 0x38, 0x46, 0x35, +0x69, 0x43, 0x32, 0x54, 0x75, 0x49, 0x4c, 0x5a, 0x74, 0x6d, 0x30, 0x48, 0x75, 0x32, 0x4c, 0x35, +0x38, 0x39, 0x5a, 0x59, 0x4e, 0x36, 0x53, 0x6d, 0x54, 0x64, 0x76, 0x44, 0x4e, 0x58, 0x74, 0x4a, +0x43, 0x49, 0x4b, 0x30, 0x2f, 0x70, 0x47, 0x38, 0x66, 0x57, 0x38, 0x5a, 0x39, 0x2b, 0x62, 0x6f, +0x4f, 0x50, 0x76, 0x35, 0x68, 0x48, 0x64, 0x5a, 0x39, 0x6f, 0x53, 0x4f, 0x72, 0x41, 0x61, 0x6c, +0x70, 0x61, 0x61, 0x36, 0x6c, 0x70, 0x43, 0x54, 0x74, 0x64, 0x64, 0x37, 0x2f, 0x6b, 0x72, 0x57, +0x59, 0x49, 0x43, 0x41, 0x56, 0x61, 0x44, 0x36, 0x65, 0x55, 0x74, 0x58, 0x6a, 0x33, 0x54, 0x50, +0x66, 0x66, 0x2f, 0x46, 0x35, 0x67, 0x37, 0x68, 0x74, 0x61, 0x73, 0x4c, 0x35, 0x54, 0x42, 0x77, +0x4f, 0x58, 0x2f, 0x52, 0x4f, 0x6f, 0x61, 0x61, 0x31, 0x64, 0x73, 0x4b, 0x62, 0x73, 0x76, 0x42, +0x71, 0x61, 0x52, 0x55, 0x6f, 0x74, 0x73, 0x2b, 0x2f, 0x75, 0x66, 0x75, 0x38, 0x4d, 0x61, 0x78, +0x65, 0x6e, 0x30, 0x44, 0x4b, 0x4d, 0x4e, 0x6f, 0x54, 0x51, 0x6f, 0x62, 0x54, 0x49, 0x44, 0x53, +0x68, 0x30, 0x6b, 0x73, 0x55, 0x71, 0x54, 0x54, 0x31, 0x56, 0x59, 0x55, 0x38, 0x63, 0x75, 0x57, +0x4c, 0x6a, 0x44, 0x76, 0x35, 0x55, 0x77, 0x37, 0x62, 0x71, 0x34, 0x46, 0x5a, 0x58, 0x7a, 0x56, +0x78, 0x31, 0x59, 0x55, 0x37, 0x73, 0x33, 0x57, 0x74, 0x49, 0x76, 0x6a, 0x72, 0x4a, 0x65, 0x51, +0x2b, 0x38, 0x67, 0x53, 0x6d, 0x73, 0x79, 0x73, 0x4e, 0x32, 0x4d, 0x4c, 0x51, 0x75, 0x4f, 0x2b, +0x2b, 0x2f, 0x50, 0x7a, 0x48, 0x53, 0x7a, 0x6e, 0x75, 0x2b, 0x6c, 0x58, 0x73, 0x73, 0x58, 0x38, +0x31, 0x4c, 0x2f, 0x33, 0x33, 0x58, 0x51, 0x51, 0x67, 0x70, 0x57, 0x41, 0x47, 0x41, 0x52, 0x4c, +0x4a, 0x50, 0x73, 0x55, 0x42, 0x78, 0x35, 0x51, 0x4c, 0x36, 0x6e, 0x4d, 0x43, 0x7a, 0x4d, 0x57, +0x32, 0x41, 0x73, 0x2f, 0x78, 0x51, 0x63, 0x41, 0x65, 0x2b, 0x59, 0x4b, 0x48, 0x6d, 0x67, 0x4c, +0x2b, 0x76, 0x63, 0x36, 0x42, 0x65, 0x6f, 0x79, 0x46, 0x34, 0x6e, 0x62, 0x63, 0x64, 0x6a, 0x64, +0x46, 0x66, 0x66, 0x76, 0x69, 0x47, 0x30, 0x50, 0x79, 0x67, 0x33, 0x66, 0x4a, 0x47, 0x37, 0x64, +0x76, 0x31, 0x45, 0x37, 0x69, 0x69, 0x38, 0x38, 0x78, 0x55, 0x70, 0x46, 0x33, 0x38, 0x57, 0x58, +0x52, 0x5a, 0x78, 0x31, 0x50, 0x50, 0x45, 0x6a, 0x52, 0x4f, 0x52, 0x66, 0x67, 0x65, 0x52, 0x36, +0x74, 0x59, 0x33, 0x63, 0x67, 0x2b, 0x61, 0x37, 0x38, 0x54, 0x65, 0x32, 0x33, 0x4f, 0x53, 0x67, +0x77, 0x63, 0x78, 0x38, 0x41, 0x6b, 0x66, 0x68, 0x6c, 0x4b, 0x4c, 0x44, 0x2b, 0x55, 0x64, 0x49, +0x31, 0x51, 0x35, 0x41, 0x37, 0x77, 0x6a, 0x70, 0x59, 0x32, 0x72, 0x37, 0x79, 0x57, 0x61, 0x4a, +0x47, 0x4d, 0x6d, 0x66, 0x4c, 0x6e, 0x66, 0x69, 0x36, 0x65, 0x6a, 0x64, 0x57, 0x35, 0x64, 0x66, +0x52, 0x53, 0x53, 0x35, 0x65, 0x4d, 0x67, 0x56, 0x42, 0x51, 0x49, 0x35, 0x4d, 0x6f, 0x6b, 0x74, +0x74, 0x53, 0x58, 0x43, 0x64, 0x41, 0x37, 0x45, 0x7a, 0x4a, 0x47, 0x61, 0x78, 0x59, 0x44, 0x66, +0x78, 0x51, 0x41, 0x51, 0x46, 0x48, 0x52, 0x2f, 0x63, 0x73, 0x33, 0x6c, 0x57, 0x31, 0x71, 0x45, +0x4b, 0x35, 0x6c, 0x67, 0x66, 0x51, 0x6d, 0x79, 0x35, 0x76, 0x54, 0x35, 0x4d, 0x55, 0x34, 0x30, +0x48, 0x41, 0x58, 0x2b, 0x37, 0x34, 0x58, 0x68, 0x2b, 0x72, 0x4e, 0x30, 0x61, 0x4a, 0x52, 0x55, +0x6a, 0x46, 0x6e, 0x36, 0x46, 0x4c, 0x78, 0x4c, 0x5a, 0x31, 0x33, 0x65, 0x46, 0x67, 0x42, 0x43, +0x46, 0x45, 0x75, 0x48, 0x36, 0x30, 0x53, 0x71, 0x31, 0x30, 0x5a, 0x6f, 0x7a, 0x62, 0x68, 0x6e, +0x46, 0x64, 0x73, 0x4d, 0x33, 0x63, 0x76, 0x59, 0x52, 0x69, 0x37, 0x6e, 0x33, 0x78, 0x58, 0x6f, +0x6d, 0x33, 0x74, 0x43, 0x41, 0x4d, 0x64, 0x70, 0x57, 0x72, 0x7a, 0x45, 0x47, 0x59, 0x68, 0x62, +0x61, 0x37, 0x4d, 0x63, 0x31, 0x4d, 0x63, 0x2f, 0x6c, 0x48, 0x6e, 0x6d, 0x6b, 0x38, 0x65, 0x51, +0x79, 0x52, 0x46, 0x6a, 0x31, 0x74, 0x75, 0x50, 0x75, 0x62, 0x55, 0x75, 0x54, 0x53, 0x52, 0x57, +0x7a, 0x79, 0x70, 0x34, 0x35, 0x41, 0x47, 0x52, 0x34, 0x2f, 0x51, 0x4d, 0x4d, 0x6b, 0x7a, 0x34, +0x30, 0x48, 0x44, 0x7a, 0x45, 0x73, 0x4b, 0x38, 0x51, 0x50, 0x44, 0x48, 0x48, 0x4d, 0x4c, 0x4d, +0x4a, 0x52, 0x36, 0x67, 0x68, 0x43, 0x61, 0x6d, 0x75, 0x51, 0x78, 0x62, 0x63, 0x51, 0x43, 0x6a, +0x4c, 0x6a, 0x69, 0x73, 0x55, 0x51, 0x55, 0x70, 0x78, 0x36, 0x2f, 0x39, 0x70, 0x54, 0x74, 0x6d, +0x7a, 0x6b, 0x64, 0x45, 0x73, 0x52, 0x77, 0x51, 0x42, 0x6e, 0x53, 0x72, 0x67, 0x39, 0x5a, 0x6e, +0x6c, 0x7a, 0x67, 0x49, 0x67, 0x63, 0x75, 0x70, 0x4a, 0x5a, 0x37, 0x47, 0x67, 0x44, 0x55, 0x6b, +0x68, 0x4f, 0x58, 0x6d, 0x76, 0x59, 0x52, 0x68, 0x6a, 0x75, 0x4f, 0x71, 0x35, 0x37, 0x2f, 0x41, +0x38, 0x36, 0x2b, 0x79, 0x30, 0x59, 0x55, 0x42, 0x72, 0x4d, 0x52, 0x43, 0x6b, 0x41, 0x53, 0x32, +0x68, 0x59, 0x41, 0x54, 0x43, 0x38, 0x67, 0x67, 0x45, 0x34, 0x70, 0x65, 0x68, 0x73, 0x46, 0x4a, +0x4b, 0x6b, 0x6b, 0x6d, 0x5a, 0x68, 0x76, 0x6b, 0x36, 0x76, 0x50, 0x38, 0x6d, 0x41, 0x56, 0x69, +0x70, 0x56, 0x4a, 0x53, 0x74, 0x35, 0x6b, 0x6b, 0x4c, 0x70, 0x57, 0x5a, 0x74, 0x47, 0x65, 0x31, +0x64, 0x65, 0x62, 0x52, 0x32, 0x45, 0x75, 0x55, 0x4b, 0x68, 0x4d, 0x73, 0x75, 0x6c, 0x59, 0x48, +0x74, 0x6a, 0x2b, 0x37, 0x68, 0x43, 0x45, 0x65, 0x4b, 0x43, 0x2f, 0x4b, 0x42, 0x4f, 0x70, 0x4a, +0x4a, 0x53, 0x64, 0x2f, 0x4b, 0x58, 0x4a, 0x35, 0x39, 0x36, 0x45, 0x41, 0x36, 0x72, 0x72, 0x2b, +0x47, 0x6a, 0x51, 0x58, 0x46, 0x6e, 0x46, 0x64, 0x2b, 0x4a, 0x6b, 0x2f, 0x6a, 0x31, 0x73, 0x78, +0x61, 0x67, 0x7a, 0x48, 0x73, 0x50, 0x76, 0x37, 0x66, 0x76, 0x50, 0x2f, 0x42, 0x44, 0x50, 0x72, +0x38, 0x36, 0x7a, 0x47, 0x2b, 0x33, 0x66, 0x38, 0x6a, 0x48, 0x74, 0x37, 0x78, 0x59, 0x6c, 0x35, +0x36, 0x31, 0x53, 0x71, 0x78, 0x51, 0x46, 0x4c, 0x66, 0x52, 0x33, 0x42, 0x4b, 0x73, 0x57, 0x43, +0x6e, 0x66, 0x47, 0x47, 0x72, 0x37, 0x36, 0x6a, 0x41, 0x52, 0x51, 0x45, 0x73, 0x4a, 0x58, 0x6a, +0x2f, 0x58, 0x4d, 0x48, 0x31, 0x78, 0x51, 0x48, 0x37, 0x31, 0x67, 0x68, 0x75, 0x61, 0x46, 0x59, +0x45, 0x7a, 0x57, 0x6b, 0x6b, 0x48, 0x6b, 0x42, 0x79, 0x32, 0x73, 0x75, 0x30, 0x66, 0x50, 0x45, +0x70, 0x70, 0x63, 0x33, 0x72, 0x79, 0x44, 0x2f, 0x69, 0x47, 0x4e, 0x74, 0x57, 0x6f, 0x64, 0x79, +0x37, 0x64, 0x6d, 0x75, 0x2f, 0x2f, 0x32, 0x37, 0x57, 0x66, 0x2f, 0x45, 0x78, 0x61, 0x6d, 0x30, +0x54, 0x70, 0x5a, 0x66, 0x39, 0x44, 0x61, 0x33, 0x31, 0x62, 0x32, 0x36, 0x2f, 0x7a, 0x55, 0x47, +0x42, 0x45, 0x51, 0x6b, 0x49, 0x45, 0x70, 0x75, 0x48, 0x41, 0x75, 0x63, 0x43, 0x63, 0x5a, 0x45, +0x69, 0x57, 0x54, 0x47, 0x41, 0x78, 0x53, 0x33, 0x31, 0x7a, 0x43, 0x2f, 0x64, 0x6d, 0x75, 0x38, +0x4f, 0x32, 0x59, 0x47, 0x57, 0x65, 0x42, 0x2b, 0x45, 0x39, 0x6f, 0x68, 0x4c, 0x52, 0x58, 0x2b, +0x6c, 0x30, 0x53, 0x71, 0x4a, 0x4c, 0x4d, 0x62, 0x53, 0x55, 0x79, 0x6e, 0x66, 0x65, 0x63, 0x37, +0x74, 0x4f, 0x75, 0x53, 0x33, 0x73, 0x4c, 0x4a, 0x75, 0x36, 0x6e, 0x70, 0x66, 0x43, 0x4c, 0x59, +0x57, 0x61, 0x32, 0x33, 0x73, 0x64, 0x57, 0x42, 0x64, 0x52, 0x4b, 0x33, 0x55, 0x2f, 0x58, 0x70, +0x6a, 0x46, 0x4d, 0x6e, 0x4f, 0x44, 0x6f, 0x72, 0x37, 0x6c, 0x4e, 0x70, 0x41, 0x4f, 0x42, 0x62, +0x4e, 0x5a, 0x5a, 0x54, 0x68, 0x35, 0x7a, 0x56, 0x39, 0x75, 0x4f, 0x69, 0x42, 0x4f, 0x72, 0x54, +0x53, 0x46, 0x50, 0x57, 0x78, 0x5a, 0x41, 0x31, 0x4b, 0x4b, 0x37, 0x54, 0x55, 0x42, 0x4d, 0x6c, +0x32, 0x36, 0x77, 0x62, 0x55, 0x32, 0x56, 0x44, 0x4b, 0x76, 0x75, 0x55, 0x35, 0x7a, 0x68, 0x54, +0x37, 0x5a, 0x53, 0x69, 0x6f, 0x37, 0x58, 0x6d, 0x4e, 0x77, 0x4b, 0x65, 0x38, 0x78, 0x4a, 0x46, +0x4b, 0x4b, 0x47, 0x79, 0x4a, 0x4b, 0x6f, 0x57, 0x6c, 0x51, 0x31, 0x4d, 0x57, 0x2b, 0x79, 0x4d, +0x4e, 0x7a, 0x46, 0x77, 0x44, 0x58, 0x31, 0x37, 0x77, 0x4c, 0x72, 0x72, 0x4a, 0x51, 0x61, 0x47, +0x31, 0x42, 0x68, 0x49, 0x49, 0x61, 0x65, 0x68, 0x58, 0x55, 0x2b, 0x79, 0x79, 0x35, 0x5a, 0x52, +0x62, 0x42, 0x72, 0x68, 0x55, 0x56, 0x6d, 0x46, 0x6e, 0x78, 0x50, 0x63, 0x57, 0x46, 0x47, 0x46, +0x55, 0x59, 0x48, 0x48, 0x31, 0x4a, 0x75, 0x34, 0x51, 0x63, 0x51, 0x48, 0x4a, 0x51, 0x43, 0x4b, +0x31, 0x6f, 0x62, 0x51, 0x6f, 0x4a, 0x38, 0x75, 0x54, 0x58, 0x4b, 0x78, 0x69, 0x76, 0x50, 0x4a, +0x31, 0x49, 0x38, 0x59, 0x59, 0x61, 0x73, 0x72, 0x79, 0x4d, 0x52, 0x71, 0x48, 0x62, 0x37, 0x41, +0x4f, 0x51, 0x36, 0x33, 0x74, 0x38, 0x71, 0x63, 0x37, 0x6c, 0x4c, 0x53, 0x75, 0x4b, 0x6b, 0x59, +0x73, 0x32, 0x5a, 0x2b, 0x47, 0x36, 0x74, 0x69, 0x76, 0x65, 0x76, 0x39, 0x45, 0x59, 0x47, 0x6d, +0x39, 0x43, 0x77, 0x74, 0x69, 0x4b, 0x41, 0x6c, 0x53, 0x2b, 0x70, 0x48, 0x33, 0x4f, 0x72, 0x72, +0x43, 0x73, 0x32, 0x76, 0x59, 0x57, 0x4e, 0x39, 0x2b, 0x61, 0x43, 0x6e, 0x78, 0x48, 0x49, 0x32, +0x34, 0x42, 0x67, 0x67, 0x73, 0x66, 0x56, 0x70, 0x4e, 0x57, 0x51, 0x77, 0x70, 0x2f, 0x53, 0x67, +0x76, 0x49, 0x35, 0x33, 0x53, 0x61, 0x36, 0x4b, 0x45, 0x72, 0x58, 0x43, 0x41, 0x55, 0x38, 0x72, +0x69, 0x42, 0x53, 0x44, 0x4a, 0x69, 0x53, 0x63, 0x4e, 0x34, 0x34, 0x52, 0x44, 0x52, 0x70, 0x43, +0x38, 0x35, 0x55, 0x71, 0x2b, 0x47, 0x33, 0x65, 0x56, 0x56, 0x31, 0x54, 0x4e, 0x41, 0x41, 0x41, +0x67, 0x41, 0x45, 0x6c, 0x45, 0x51, 0x56, 0x51, 0x61, 0x4c, 0x33, 0x33, 0x51, 0x53, 0x45, 0x57, +0x78, 0x64, 0x58, 0x78, 0x36, 0x57, 0x39, 0x58, 0x6a, 0x61, 0x61, 0x75, 0x41, 0x44, 0x56, 0x74, +0x57, 0x63, 0x4f, 0x49, 0x70, 0x4c, 0x33, 0x48, 0x71, 0x6e, 0x2f, 0x66, 0x6b, 0x67, 0x46, 0x4e, +0x50, 0x34, 0x4f, 0x7a, 0x54, 0x6a, 0x36, 0x5a, 0x70, 0x34, 0x68, 0x2f, 0x52, 0x64, 0x7a, 0x31, +0x45, 0x56, 0x62, 0x76, 0x6b, 0x75, 0x71, 0x70, 0x2b, 0x2b, 0x4c, 0x6d, 0x57, 0x39, 0x52, 0x6c, +0x6c, 0x5a, 0x33, 0x37, 0x50, 0x43, 0x46, 0x7a, 0x32, 0x6c, 0x6b, 0x55, 0x45, 0x65, 0x5a, 0x4a, +0x78, 0x42, 0x59, 0x6f, 0x39, 0x2b, 0x79, 0x76, 0x2b, 0x73, 0x6c, 0x41, 0x52, 0x41, 0x48, 0x48, +0x58, 0x66, 0x6e, 0x6c, 0x6a, 0x64, 0x36, 0x4a, 0x50, 0x63, 0x7a, 0x4e, 0x35, 0x4f, 0x2b, 0x32, +0x57, 0x66, 0x75, 0x2b, 0x2b, 0x74, 0x52, 0x43, 0x6b, 0x6f, 0x6e, 0x59, 0x73, 0x2f, 0x76, 0x33, +0x52, 0x78, 0x4c, 0x75, 0x36, 0x79, 0x44, 0x6e, 0x6f, 0x63, 0x43, 0x75, 0x6e, 0x57, 0x70, 0x4d, +0x49, 0x35, 0x47, 0x39, 0x71, 0x76, 0x38, 0x31, 0x42, 0x67, 0x58, 0x2b, 0x34, 0x63, 0x31, 0x65, +0x30, 0x45, 0x41, 0x78, 0x36, 0x62, 0x6a, 0x4e, 0x51, 0x34, 0x46, 0x66, 0x42, 0x50, 0x4d, 0x4e, +0x34, 0x58, 0x75, 0x4a, 0x45, 0x54, 0x4d, 0x6b, 0x75, 0x6b, 0x4d, 0x79, 0x33, 0x44, 0x67, 0x53, +0x53, 0x5a, 0x47, 0x4d, 0x50, 0x65, 0x39, 0x75, 0x68, 0x6b, 0x77, 0x4e, 0x37, 0x2b, 0x66, 0x53, +0x58, 0x45, 0x59, 0x44, 0x68, 0x39, 0x72, 0x2b, 0x77, 0x30, 0x76, 0x5a, 0x32, 0x2f, 0x61, 0x6b, +0x48, 0x54, 0x49, 0x72, 0x4f, 0x77, 0x78, 0x6b, 0x37, 0x50, 0x56, 0x76, 0x5a, 0x6f, 0x6f, 0x67, +0x47, 0x34, 0x31, 0x43, 0x42, 0x32, 0x6c, 0x4b, 0x64, 0x45, 0x54, 0x4c, 0x48, 0x47, 0x4a, 0x35, +0x37, 0x2b, 0x6f, 0x59, 0x73, 0x64, 0x4e, 0x2f, 0x6f, 0x72, 0x64, 0x37, 0x46, 0x54, 0x73, 0x30, +0x2b, 0x30, 0x39, 0x2f, 0x66, 0x67, 0x2b, 0x4a, 0x43, 0x69, 0x36, 0x78, 0x44, 0x61, 0x69, 0x53, +0x5a, 0x49, 0x7a, 0x4b, 0x30, 0x64, 0x58, 0x52, 0x77, 0x33, 0x4a, 0x73, 0x37, 0x6b, 0x45, 0x56, +0x34, 0x4b, 0x72, 0x56, 0x72, 0x75, 0x6f, 0x7a, 0x50, 0x64, 0x4c, 0x64, 0x7a, 0x71, 0x64, 0x4d, +0x76, 0x4d, 0x58, 0x38, 0x79, 0x46, 0x75, 0x6e, 0x58, 0x6e, 0x63, 0x30, 0x31, 0x68, 0x44, 0x78, +0x75, 0x43, 0x6f, 0x71, 0x70, 0x67, 0x57, 0x4c, 0x36, 0x6e, 0x66, 0x5a, 0x77, 0x44, 0x33, 0x52, +0x66, 0x52, 0x46, 0x77, 0x5a, 0x44, 0x70, 0x6f, 0x68, 0x73, 0x57, 0x58, 0x34, 0x74, 0x38, 0x51, +0x4b, 0x4e, 0x4e, 0x44, 0x30, 0x31, 0x58, 0x6c, 0x5a, 0x73, 0x30, 0x78, 0x44, 0x77, 0x31, 0x4c, +0x65, 0x5a, 0x30, 0x2f, 0x47, 0x38, 0x78, 0x37, 0x7a, 0x35, 0x2f, 0x66, 0x76, 0x4d, 0x51, 0x75, +0x68, 0x73, 0x36, 0x47, 0x6b, 0x46, 0x7a, 0x2f, 0x63, 0x54, 0x43, 0x49, 0x70, 0x53, 0x53, 0x59, +0x44, 0x45, 0x6b, 0x6c, 0x4a, 0x52, 0x7a, 0x4c, 0x67, 0x33, 0x35, 0x66, 0x33, 0x53, 0x7a, 0x4d, +0x68, 0x4b, 0x55, 0x55, 0x51, 0x42, 0x43, 0x53, 0x54, 0x53, 0x62, 0x61, 0x64, 0x4f, 0x4c, 0x45, +0x48, 0x4c, 0x48, 0x6e, 0x33, 0x68, 0x76, 0x39, 0x41, 0x49, 0x6b, 0x68, 0x44, 0x30, 0x51, 0x50, +0x64, 0x43, 0x78, 0x53, 0x39, 0x4f, 0x7a, 0x53, 0x51, 0x71, 0x49, 0x2b, 0x75, 0x65, 0x6d, 0x77, +0x38, 0x64, 0x63, 0x38, 0x39, 0x7a, 0x58, 0x2b, 0x47, 0x6a, 0x57, 0x50, 0x57, 0x78, 0x77, 0x46, +0x43, 0x64, 0x69, 0x47, 0x56, 0x34, 0x76, 0x4e, 0x58, 0x6a, 0x2b, 0x57, 0x4e, 0x2f, 0x53, 0x64, +0x67, 0x70, 0x4f, 0x54, 0x41, 0x39, 0x31, 0x35, 0x6e, 0x78, 0x33, 0x31, 0x76, 0x49, 0x79, 0x78, +0x67, 0x57, 0x6a, 0x57, 0x67, 0x6e, 0x43, 0x74, 0x76, 0x50, 0x34, 0x34, 0x33, 0x72, 0x33, 0x79, +0x41, 0x56, 0x37, 0x36, 0x65, 0x6b, 0x69, 0x31, 0x62, 0x70, 0x77, 0x42, 0x4c, 0x51, 0x58, 0x2b, +0x49, 0x5a, 0x56, 0x61, 0x57, 0x6f, 0x44, 0x38, 0x47, 0x76, 0x51, 0x58, 0x6f, 0x57, 0x74, 0x43, +0x66, 0x5a, 0x73, 0x75, 0x66, 0x76, 0x78, 0x6b, 0x6f, 0x63, 0x65, 0x37, 0x6f, 0x30, 0x57, 0x69, +0x67, 0x34, 0x38, 0x73, 0x76, 0x4e, 0x77, 0x6b, 0x6c, 0x76, 0x76, 0x62, 0x35, 0x34, 0x44, 0x65, +0x31, 0x33, 0x35, 0x44, 0x66, 0x43, 0x67, 0x55, 0x32, 0x57, 0x64, 0x4e, 0x5a, 0x39, 0x73, 0x75, +0x46, 0x66, 0x32, 0x39, 0x75, 0x39, 0x31, 0x74, 0x61, 0x73, 0x72, 0x2f, 0x76, 0x66, 0x6a, 0x7a, +0x7a, 0x4a, 0x58, 0x74, 0x37, 0x77, 0x4c, 0x43, 0x52, 0x61, 0x6d, 0x74, 0x72, 0x36, 0x62, 0x37, +0x5a, 0x79, 0x7a, 0x5a, 0x2f, 0x66, 0x62, 0x69, 0x76, 0x47, 0x54, 0x79, 0x34, 0x52, 0x78, 0x4a, +0x42, 0x32, 0x45, 0x69, 0x51, 0x4c, 0x54, 0x6f, 0x36, 0x34, 0x7a, 0x7a, 0x38, 0x2f, 0x32, 0x4e, +0x37, 0x75, 0x5a, 0x5a, 0x31, 0x4f, 0x4b, 0x62, 0x42, 0x4d, 0x4d, 0x59, 0x4f, 0x7a, 0x51, 0x6d, +0x6f, 0x2f, 0x79, 0x73, 0x39, 0x6f, 0x4b, 0x67, 0x4e, 0x6a, 0x31, 0x67, 0x59, 0x66, 0x37, 0x68, +0x4a, 0x62, 0x66, 0x39, 0x62, 0x39, 0x54, 0x61, 0x53, 0x39, 0x54, 0x4b, 0x57, 0x56, 0x6b, 0x35, +0x62, 0x77, 0x6e, 0x6f, 0x79, 0x55, 0x71, 0x49, 0x7a, 0x76, 0x39, 0x65, 0x62, 0x48, 0x6d, 0x51, +0x69, 0x67, 0x65, 0x4e, 0x51, 0x73, 0x76, 0x68, 0x54, 0x41, 0x4c, 0x36, 0x34, 0x76, 0x77, 0x79, +0x41, 0x48, 0x63, 0x37, 0x61, 0x41, 0x4e, 0x71, 0x6a, 0x4b, 0x31, 0x44, 0x70, 0x51, 0x53, 0x65, +0x54, 0x32, 0x54, 0x6b, 0x70, 0x30, 0x33, 0x6b, 0x62, 0x52, 0x70, 0x4b, 0x36, 0x38, 0x69, 0x75, +0x6d, 0x46, 0x4f, 0x2f, 0x44, 0x5a, 0x5a, 0x4f, 0x65, 0x34, 0x34, 0x48, 0x79, 0x65, 0x5a, 0x53, +0x57, 0x46, 0x58, 0x4c, 0x43, 0x6b, 0x75, 0x46, 0x63, 0x47, 0x50, 0x75, 0x57, 0x75, 0x2b, 0x34, +0x2f, 0x69, 0x74, 0x69, 0x5a, 0x48, 0x77, 0x48, 0x4e, 0x5a, 0x41, 0x39, 0x4b, 0x36, 0x57, 0x50, +0x73, 0x7a, 0x43, 0x51, 0x71, 0x6d, 0x66, 0x48, 0x73, 0x43, 0x63, 0x32, 0x4b, 0x2b, 0x31, 0x72, +0x4a, 0x6a, 0x32, 0x66, 0x33, 0x58, 0x31, 0x74, 0x43, 0x73, 0x2b, 0x57, 0x78, 0x5a, 0x55, 0x52, +0x73, 0x75, 0x30, 0x6b, 0x4e, 0x2b, 0x61, 0x41, 0x57, 0x6c, 0x76, 0x66, 0x6f, 0x41, 0x42, 0x31, +0x45, 0x78, 0x6c, 0x79, 0x76, 0x45, 0x30, 0x4c, 0x6d, 0x33, 0x39, 0x30, 0x7a, 0x79, 0x54, 0x53, +0x51, 0x2b, 0x42, 0x4c, 0x77, 0x79, 0x57, 0x4c, 0x2f, 0x44, 0x63, 0x39, 0x64, 0x2f, 0x56, 0x4b, +0x63, 0x44, 0x35, 0x52, 0x6a, 0x62, 0x32, 0x6d, 0x41, 0x43, 0x30, 0x61, 0x79, 0x4d, 0x44, 0x36, +0x50, 0x64, 0x59, 0x74, 0x58, 0x57, 0x56, 0x78, 0x2b, 0x65, 0x4a, 0x50, 0x4e, 0x74, 0x62, 0x33, +0x7a, 0x59, 0x4b, 0x35, 0x2f, 0x49, 0x56, 0x74, 0x6e, 0x4e, 0x6a, 0x65, 0x42, 0x64, 0x5a, 0x64, +0x4a, 0x48, 0x32, 0x69, 0x39, 0x2f, 0x41, 0x59, 0x2b, 0x79, 0x42, 0x2f, 0x4b, 0x6c, 0x57, 0x39, +0x75, 0x34, 0x4d, 0x37, 0x57, 0x71, 0x63, 0x53, 0x31, 0x35, 0x6b, 0x4a, 0x39, 0x41, 0x4a, 0x66, +0x56, 0x4c, 0x57, 0x65, 0x66, 0x48, 0x51, 0x5a, 0x77, 0x30, 0x4d, 0x50, 0x4e, 0x30, 0x4e, 0x6b, +0x61, 0x50, 0x63, 0x52, 0x42, 0x70, 0x2b, 0x33, 0x48, 0x39, 0x45, 0x65, 0x6e, 0x59, 0x65, 0x6b, +0x77, 0x41, 0x78, 0x68, 0x34, 0x48, 0x72, 0x52, 0x6c, 0x61, 0x45, 0x44, 0x49, 0x5a, 0x47, 0x78, +0x5a, 0x54, 0x58, 0x74, 0x35, 0x69, 0x63, 0x7a, 0x64, 0x31, 0x51, 0x62, 0x38, 0x4c, 0x56, 0x42, +0x65, 0x48, 0x79, 0x67, 0x72, 0x73, 0x38, 0x4b, 0x58, 0x44, 0x55, 0x69, 0x41, 0x63, 0x44, 0x59, +0x4f, 0x2f, 0x36, 0x2f, 0x37, 0x76, 0x6e, 0x54, 0x70, 0x55, 0x71, 0x41, 0x58, 0x4b, 0x47, 0x4e, +0x4c, 0x43, 0x79, 0x61, 0x5a, 0x68, 0x49, 0x6f, 0x4b, 0x54, 0x45, 0x37, 0x4f, 0x4a, 0x71, 0x39, +0x76, 0x62, 0x47, 0x78, 0x45, 0x41, 0x6f, 0x4d, 0x7a, 0x57, 0x48, 0x47, 0x6a, 0x4d, 0x6b, 0x6a, +0x53, 0x70, 0x65, 0x53, 0x36, 0x4c, 0x4c, 0x67, 0x77, 0x73, 0x79, 0x2b, 0x7a, 0x57, 0x4d, 0x4e, +0x6e, 0x30, 0x7a, 0x59, 0x42, 0x5a, 0x53, 0x35, 0x55, 0x31, 0x6b, 0x70, 0x41, 0x34, 0x6e, 0x6d, +0x53, 0x57, 0x45, 0x78, 0x53, 0x6b, 0x69, 0x38, 0x34, 0x38, 0x5a, 0x69, 0x65, 0x55, 0x4e, 0x53, +0x67, 0x4f, 0x4d, 0x59, 0x64, 0x73, 0x54, 0x74, 0x78, 0x62, 0x34, 0x76, 0x6c, 0x65, 0x46, 0x45, +0x6f, 0x4e, 0x4e, 0x71, 0x34, 0x44, 0x43, 0x35, 0x6a, 0x30, 0x33, 0x65, 0x56, 0x4b, 0x7a, 0x34, +0x70, 0x73, 0x5a, 0x2f, 0x66, 0x76, 0x76, 0x46, 0x2b, 0x66, 0x50, 0x72, 0x7a, 0x6a, 0x2f, 0x46, +0x4e, 0x4e, 0x44, 0x50, 0x6c, 0x66, 0x34, 0x66, 0x43, 0x50, 0x6d, 0x53, 0x66, 0x66, 0x35, 0x38, +0x64, 0x79, 0x68, 0x67, 0x35, 0x63, 0x69, 0x54, 0x47, 0x47, 0x50, 0x62, 0x62, 0x38, 0x55, 0x63, +0x77, 0x68, 0x70, 0x64, 0x75, 0x48, 0x55, 0x45, 0x59, 0x36, 0x62, 0x51, 0x6e, 0x78, 0x6e, 0x6d, +0x2f, 0x6e, 0x5a, 0x50, 0x49, 0x77, 0x4e, 0x4c, 0x6c, 0x6a, 0x65, 0x53, 0x4e, 0x2f, 0x41, 0x48, +0x7a, 0x56, 0x54, 0x6b, 0x58, 0x58, 0x50, 0x55, 0x63, 0x79, 0x31, 0x36, 0x62, 0x41, 0x61, 0x30, +0x74, 0x72, 0x4e, 0x74, 0x36, 0x53, 0x79, 0x70, 0x47, 0x44, 0x2b, 0x57, 0x71, 0x35, 0x31, 0x5a, +0x79, 0x37, 0x72, 0x6c, 0x62, 0x45, 0x41, 0x51, 0x71, 0x63, 0x6c, 0x44, 0x61, 0x6f, 0x79, 0x33, +0x68, 0x4e, 0x57, 0x33, 0x61, 0x2b, 0x61, 0x67, 0x4f, 0x75, 0x50, 0x6c, 0x45, 0x32, 0x34, 0x78, +0x4b, 0x47, 0x34, 0x54, 0x30, 0x36, 0x46, 0x74, 0x56, 0x54, 0x73, 0x7a, 0x50, 0x37, 0x76, 0x39, +0x53, 0x59, 0x54, 0x6a, 0x72, 0x67, 0x70, 0x41, 0x30, 0x31, 0x50, 0x70, 0x48, 0x6e, 0x72, 0x72, +0x53, 0x30, 0x6f, 0x45, 0x2f, 0x38, 0x48, 0x67, 0x49, 0x54, 0x45, 0x6b, 0x54, 0x79, 0x39, 0x71, +0x6a, 0x63, 0x59, 0x41, 0x73, 0x62, 0x48, 0x45, 0x4c, 0x35, 0x31, 0x77, 0x4e, 0x7a, 0x36, 0x2b, +0x2b, 0x6f, 0x71, 0x44, 0x58, 0x2f, 0x69, 0x73, 0x61, 0x70, 0x54, 0x44, 0x35, 0x47, 0x64, 0x69, +0x43, 0x4b, 0x4c, 0x53, 0x59, 0x66, 0x56, 0x7a, 0x7a, 0x78, 0x6a, 0x51, 0x65, 0x2f, 0x6e, 0x77, +0x46, 0x47, 0x34, 0x36, 0x39, 0x6a, 0x4f, 0x4c, 0x39, 0x7a, 0x6d, 0x50, 0x51, 0x34, 0x53, 0x4e, +0x5a, 0x6e, 0x78, 0x53, 0x38, 0x73, 0x76, 0x67, 0x74, 0x47, 0x6a, 0x74, 0x58, 0x6f, 0x6d, 0x51, +0x79, 0x36, 0x69, 0x74, 0x70, 0x65, 0x6d, 0x6e, 0x2f, 0x42, 0x36, 0x59, 0x68, 0x53, 0x62, 0x4d, +0x43, 0x64, 0x35, 0x63, 0x2f, 0x6f, 0x32, 0x51, 0x32, 0x49, 0x72, 0x61, 0x62, 0x2f, 0x71, 0x79, +0x59, 0x4e, 0x6f, 0x30, 0x62, 0x66, 0x79, 0x6a, 0x6b, 0x38, 0x53, 0x75, 0x48, 0x63, 0x50, 0x4c, +0x4a, 0x34, 0x30, 0x6a, 0x4f, 0x48, 0x6f, 0x42, 0x4a, 0x64, 0x6e, 0x48, 0x6f, 0x77, 0x43, 0x47, +0x55, 0x56, 0x5a, 0x66, 0x78, 0x37, 0x71, 0x49, 0x6b, 0x6c, 0x39, 0x55, 0x32, 0x6f, 0x71, 0x53, +0x6d, 0x4b, 0x78, 0x43, 0x63, 0x63, 0x4e, 0x67, 0x32, 0x78, 0x4f, 0x4d, 0x65, 0x4a, 0x30, 0x30, +0x59, 0x77, 0x2f, 0x51, 0x50, 0x46, 0x2f, 0x4c, 0x30, 0x48, 0x66, 0x2b, 0x41, 0x44, 0x51, 0x48, +0x58, 0x33, 0x62, 0x5a, 0x6e, 0x65, 0x50, 0x73, 0x49, 0x78, 0x71, 0x35, 0x63, 0x53, 0x4e, 0x48, +0x53, 0x73, 0x32, 0x55, 0x73, 0x71, 0x61, 0x4b, 0x30, 0x62, 0x4d, 0x4d, 0x4c, 0x64, 0x7a, 0x37, +0x74, 0x42, 0x6f, 0x44, 0x66, 0x41, 0x75, 0x57, 0x4e, 0x46, 0x44, 0x35, 0x44, 0x2b, 0x62, 0x56, +0x47, 0x64, 0x58, 0x58, 0x68, 0x33, 0x58, 0x4d, 0x72, 0x63, 0x75, 0x4a, 0x5a, 0x78, 0x4b, 0x70, +0x72, 0x65, 0x69, 0x68, 0x76, 0x46, 0x70, 0x51, 0x30, 0x76, 0x4c, 0x36, 0x6a, 0x41, 0x35, 0x35, +0x38, 0x45, 0x76, 0x50, 0x31, 0x31, 0x39, 0x44, 0x56, 0x68, 0x61, 0x6d, 0x6f, 0x77, 0x4a, 0x78, +0x77, 0x41, 0x6d, 0x61, 0x58, 0x58, 0x58, 0x71, 0x39, 0x50, 0x6b, 0x33, 0x4c, 0x5a, 0x41, 0x68, +0x57, 0x72, 0x6b, 0x72, 0x58, 0x50, 0x78, 0x50, 0x70, 0x71, 0x69, 0x70, 0x70, 0x61, 0x69, 0x51, +0x58, 0x78, 0x33, 0x62, 0x78, 0x34, 0x4e, 0x78, 0x75, 0x72, 0x4b, 0x78, 0x5a, 0x37, 0x36, 0x2b, +0x79, 0x4b, 0x2f, 0x51, 0x59, 0x59, 0x30, 0x74, 0x7a, 0x4c, 0x57, 0x6a, 0x74, 0x42, 0x6b, 0x55, +0x4e, 0x59, 0x48, 0x48, 0x6a, 0x4e, 0x78, 0x51, 0x4f, 0x32, 0x71, 0x37, 0x62, 0x34, 0x47, 0x65, +0x69, 0x41, 0x61, 0x48, 0x48, 0x76, 0x34, 0x7a, 0x6e, 0x50, 0x2b, 0x75, 0x6e, 0x63, 0x65, 0x78, +0x43, 0x6e, 0x4b, 0x4a, 0x59, 0x4b, 0x64, 0x2b, 0x32, 0x72, 0x72, 0x54, 0x52, 0x44, 0x47, 0x30, +0x72, 0x2f, 0x53, 0x70, 0x6c, 0x6a, 0x79, 0x45, 0x4d, 0x4e, 0x6f, 0x4c, 0x43, 0x75, 0x76, 0x7a, +0x77, 0x68, 0x70, 0x49, 0x47, 0x53, 0x4d, 0x44, 0x33, 0x54, 0x7a, 0x66, 0x51, 0x30, 0x4e, 0x41, +0x51, 0x33, 0x66, 0x50, 0x56, 0x4f, 0x37, 0x62, 0x43, 0x47, 0x4d, 0x4f, 0x6e, 0x73, 0x31, 0x76, +0x51, 0x68, 0x67, 0x67, 0x65, 0x62, 0x4a, 0x46, 0x6e, 0x36, 0x62, 0x38, 0x4c, 0x38, 0x6e, 0x30, +0x2b, 0x66, 0x72, 0x73, 0x56, 0x55, 0x33, 0x38, 0x44, 0x71, 0x2f, 0x37, 0x72, 0x55, 0x66, 0x4c, +0x73, 0x30, 0x35, 0x51, 0x6c, 0x6b, 0x71, 0x69, 0x4f, 0x67, 0x4a, 0x7a, 0x50, 0x43, 0x32, 0x68, +0x4d, 0x47, 0x76, 0x36, 0x65, 0x31, 0x38, 0x4a, 0x52, 0x53, 0x2f, 0x65, 0x6b, 0x4c, 0x57, 0x55, +0x51, 0x51, 0x59, 0x42, 0x51, 0x49, 0x41, 0x4a, 0x4a, 0x4b, 0x70, 0x57, 0x6b, 0x6f, 0x63, 0x47, +0x56, 0x55, 0x33, 0x4d, 0x53, 0x74, 0x48, 0x71, 0x6a, 0x39, 0x58, 0x38, 0x6b, 0x70, 0x62, 0x31, +0x48, 0x72, 0x4e, 0x75, 0x67, 0x4c, 0x62, 0x56, 0x68, 0x30, 0x56, 0x70, 0x37, 0x62, 0x36, 0x45, +0x4d, 0x39, 0x65, 0x57, 0x75, 0x4e, 0x71, 0x4c, 0x62, 0x6d, 0x74, 0x59, 0x37, 0x52, 0x56, 0x64, +0x45, 0x2f, 0x49, 0x4a, 0x48, 0x62, 0x48, 0x69, 0x57, 0x48, 0x4e, 0x2f, 0x77, 0x65, 0x50, 0x77, +0x34, 0x41, 0x75, 0x57, 0x6c, 0x2b, 0x53, 0x53, 0x6c, 0x6f, 0x62, 0x62, 0x53, 0x2b, 0x35, 0x2f, +0x36, 0x72, 0x7a, 0x75, 0x4f, 0x77, 0x50, 0x4d, 0x61, 0x30, 0x42, 0x4a, 0x47, 0x41, 0x57, 0x72, +0x74, 0x47, 0x6a, 0x36, 0x39, 0x66, 0x53, 0x59, 0x66, 0x6a, 0x34, 0x38, 0x7a, 0x2f, 0x75, 0x67, +0x36, 0x4c, 0x74, 0x35, 0x32, 0x41, 0x6d, 0x73, 0x54, 0x65, 0x61, 0x7a, 0x73, 0x54, 0x48, 0x44, +0x76, 0x33, 0x4d, 0x64, 0x59, 0x31, 0x62, 0x34, 0x4d, 0x49, 0x62, 0x6f, 0x49, 0x76, 0x43, 0x44, +0x69, 0x5a, 0x77, 0x6a, 0x37, 0x33, 0x33, 0x66, 0x33, 0x31, 0x30, 0x37, 0x2b, 0x4d, 0x6c, 0x6d, +0x42, 0x69, 0x33, 0x66, 0x62, 0x48, 0x56, 0x4e, 0x55, 0x53, 0x4e, 0x74, 0x4c, 0x4c, 0x36, 0x58, +0x4a, 0x57, 0x5a, 0x33, 0x2b, 0x2b, 0x41, 0x30, 0x4e, 0x41, 0x46, 0x7a, 0x2f, 0x37, 0x6d, 0x54, +0x6b, 0x2b, 0x4a, 0x75, 0x49, 0x4e, 0x36, 0x38, 0x6c, 0x72, 0x36, 0x30, 0x4e, 0x6e, 0x55, 0x71, +0x52, 0x55, 0x31, 0x78, 0x45, 0x75, 0x2f, 0x62, 0x59, 0x70, 0x69, 0x76, 0x67, 0x6a, 0x66, 0x77, +0x39, 0x61, 0x5a, 0x55, 0x65, 0x51, 0x54, 0x4c, 0x67, 0x71, 0x66, 0x2f, 0x4d, 0x34, 0x59, 0x44, +0x64, 0x42, 0x2f, 0x4f, 0x50, 0x78, 0x7a, 0x35, 0x6e, 0x55, 0x45, 0x4d, 0x35, 0x59, 0x43, 0x32, +0x37, 0x51, 0x47, 0x68, 0x57, 0x4e, 0x71, 0x55, 0x63, 0x6d, 0x49, 0x67, 0x4d, 0x52, 0x54, 0x64, +0x5a, 0x54, 0x6d, 0x32, 0x62, 0x46, 0x4b, 0x59, 0x51, 0x67, 0x61, 0x61, 0x68, 0x58, 0x77, 0x47, +0x51, 0x64, 0x49, 0x78, 0x41, 0x6a, 0x6c, 0x55, 0x32, 0x53, 0x2f, 0x6e, 0x44, 0x45, 0x6b, 0x58, +0x64, 0x57, 0x47, 0x55, 0x6a, 0x54, 0x6a, 0x4b, 0x78, 0x61, 0x56, 0x5a, 0x53, 0x75, 0x62, 0x6f, +0x52, 0x63, 0x39, 0x74, 0x31, 0x4a, 0x44, 0x64, 0x73, 0x49, 0x4f, 0x66, 0x4b, 0x43, 0x2b, 0x48, +0x36, 0x32, 0x2f, 0x46, 0x71, 0x36, 0x33, 0x70, 0x34, 0x6b, 0x6a, 0x4f, 0x5a, 0x55, 0x44, 0x45, +0x47, 0x6e, 0x6e, 0x67, 0x43, 0x38, 0x39, 0x46, 0x48, 0x36, 0x66, 0x75, 0x33, 0x74, 0x57, 0x46, +0x75, 0x2f, 0x44, 0x76, 0x6d, 0x31, 0x6c, 0x73, 0x77, 0x57, 0x32, 0x33, 0x56, 0x34, 0x33, 0x71, +0x74, 0x4e, 0x53, 0x4e, 0x57, 0x72, 0x36, 0x61, 0x79, 0x75, 0x6a, 0x70, 0x61, 0x30, 0x34, 0x63, +0x7a, 0x6e, 0x76, 0x31, 0x65, 0x35, 0x72, 0x6d, 0x4f, 0x79, 0x45, 0x79, 0x30, 0x55, 0x38, 0x44, +0x55, 0x76, 0x4f, 0x39, 0x68, 0x31, 0x31, 0x31, 0x37, 0x76, 0x6a, 0x2f, 0x4b, 0x43, 0x55, 0x6f, +0x32, 0x6c, 0x44, 0x6c, 0x51, 0x61, 0x59, 0x49, 0x47, 0x6f, 0x51, 0x51, 0x45, 0x55, 0x4c, 0x6a, +0x64, 0x47, 0x4d, 0x79, 0x4e, 0x31, 0x30, 0x4e, 0x72, 0x49, 0x37, 0x52, 0x4a, 0x57, 0x2b, 0x4e, +0x64, 0x69, 0x6f, 0x69, 0x6b, 0x4d, 0x34, 0x4b, 0x44, 0x79, 0x69, 0x42, 0x64, 0x78, 0x52, 0x69, +0x4a, 0x56, 0x31, 0x74, 0x50, 0x2f, 0x6e, 0x32, 0x76, 0x49, 0x47, 0x38, 0x2b, 0x42, 0x6f, 0x38, +0x38, 0x39, 0x71, 0x6c, 0x38, 0x6a, 0x47, 0x4e, 0x48, 0x68, 0x5a, 0x45, 0x4d, 0x2b, 0x38, 0x78, +0x2b, 0x34, 0x6b, 0x4f, 0x4d, 0x30, 0x61, 0x69, 0x43, 0x63, 0x57, 0x52, 0x53, 0x6d, 0x6f, 0x63, +0x44, 0x79, 0x50, 0x71, 0x64, 0x31, 0x7a, 0x73, 0x71, 0x2f, 0x4a, 0x36, 0x44, 0x7a, 0x37, 0x63, +0x4c, 0x75, 0x69, 0x4a, 0x65, 0x2b, 0x7a, 0x52, 0x54, 0x62, 0x77, 0x67, 0x46, 0x4e, 0x6c, 0x53, +0x55, 0x78, 0x62, 0x6e, 0x6d, 0x76, 0x6e, 0x6b, 0x73, 0x37, 0x68, 0x7a, 0x48, 0x72, 0x59, 0x63, +0x64, 0x53, 0x55, 0x6e, 0x62, 0x51, 0x6a, 0x70, 0x6d, 0x7a, 0x4d, 0x51, 0x66, 0x55, 0x55, 0x6e, +0x4a, 0x48, 0x71, 0x4e, 0x59, 0x4d, 0x33, 0x30, 0x6d, 0x55, 0x33, 0x55, 0x6c, 0x79, 0x51, 0x58, +0x74, 0x42, 0x45, 0x48, 0x41, 0x77, 0x51, 0x65, 0x50, 0x35, 0x74, 0x52, 0x54, 0x64, 0x36, 0x47, +0x6f, 0x4b, 0x4a, 0x38, 0x66, 0x66, 0x32, 0x7a, 0x6b, 0x74, 0x64, 0x66, 0x6d, 0x4d, 0x48, 0x30, +0x36, 0x31, 0x6d, 0x53, 0x50, 0x65, 0x50, 0x52, 0x74, 0x46, 0x43, 0x54, 0x7a, 0x4f, 0x54, 0x50, +0x33, 0x51, 0x4b, 0x5a, 0x72, 0x54, 0x6b, 0x69, 0x46, 0x58, 0x51, 0x61, 0x41, 0x5a, 0x54, 0x6c, +0x32, 0x79, 0x6d, 0x38, 0x70, 0x30, 0x47, 0x47, 0x50, 0x78, 0x49, 0x30, 0x73, 0x48, 0x6c, 0x2f, +0x47, 0x39, 0x72, 0x55, 0x48, 0x4d, 0x66, 0x47, 0x75, 0x4f, 0x37, 0x6d, 0x76, 0x39, 0x70, 0x4a, +0x30, 0x32, 0x57, 0x78, 0x48, 0x4b, 0x68, 0x50, 0x4a, 0x6e, 0x7a, 0x61, 0x57, 0x70, 0x7a, 0x48, +0x73, 0x50, 0x39, 0x4e, 0x37, 0x2f, 0x32, 0x57, 0x48, 0x6f, 0x6b, 0x58, 0x6f, 0x42, 0x73, 0x48, +0x58, 0x68, 0x6a, 0x32, 0x6c, 0x59, 0x74, 0x47, 0x62, 0x41, 0x61, 0x2f, 0x4f, 0x2b, 0x35, 0x45, +0x52, 0x4a, 0x38, 0x78, 0x6a, 0x37, 0x4b, 0x67, 0x63, 0x71, 0x76, 0x4d, 0x48, 0x38, 0x75, 0x43, +0x65, 0x45, 0x31, 0x6e, 0x64, 0x36, 0x66, 0x48, 0x63, 0x67, 0x75, 0x6c, 0x38, 0x32, 0x6a, 0x53, +0x48, 0x6c, 0x57, 0x32, 0x4c, 0x45, 0x43, 0x4a, 0x41, 0x35, 0x49, 0x75, 0x30, 0x54, 0x65, 0x2f, +0x75, 0x48, 0x30, 0x35, 0x41, 0x76, 0x75, 0x39, 0x62, 0x57, 0x54, 0x76, 0x74, 0x56, 0x4d, 0x7a, +0x73, 0x32, 0x65, 0x52, 0x58, 0x56, 0x74, 0x4c, 0x56, 0x74, 0x4d, 0x61, 0x46, 0x38, 0x64, 0x4b, +0x55, 0x58, 0x68, 0x4c, 0x34, 0x5a, 0x4e, 0x53, 0x68, 0x48, 0x4c, 0x66, 0x31, 0x61, 0x50, 0x4c, +0x58, 0x72, 0x53, 0x53, 0x35, 0x59, 0x44, 0x46, 0x65, 0x4c, 0x45, 0x37, 0x68, 0x73, 0x4d, 0x46, +0x30, 0x72, 0x47, 0x70, 0x6d, 0x55, 0x53, 0x4b, 0x50, 0x35, 0x42, 0x72, 0x44, 0x34, 0x65, 0x4f, +0x48, 0x38, 0x64, 0x4c, 0x30, 0x48, 0x2f, 0x68, 0x70, 0x79, 0x54, 0x70, 0x6d, 0x2f, 0x39, 0x44, +0x49, 0x6c, 0x57, 0x66, 0x75, 0x77, 0x66, 0x74, 0x66, 0x4c, 0x67, 0x55, 0x53, 0x33, 0x48, 0x7a, +0x33, 0x64, 0x68, 0x77, 0x30, 0x76, 0x70, 0x5a, 0x45, 0x30, 0x6d, 0x49, 0x46, 0x6c, 0x44, 0x59, +0x59, 0x5a, 0x64, 0x41, 0x5a, 0x6a, 0x4e, 0x4a, 0x4b, 0x47, 0x35, 0x51, 0x77, 0x31, 0x69, 0x70, +0x31, 0x6b, 0x61, 0x43, 0x69, 0x67, 0x6a, 0x69, 0x79, 0x59, 0x79, 0x2f, 0x69, 0x57, 0x76, 0x55, +0x4f, 0x78, 0x65, 0x7a, 0x6f, 0x45, 0x6a, 0x7a, 0x2f, 0x62, 0x30, 0x76, 0x51, 0x63, 0x50, 0x7a, +0x78, 0x41, 0x55, 0x58, 0x35, 0x33, 0x52, 0x72, 0x51, 0x45, 0x39, 0x42, 0x47, 0x7a, 0x31, 0x6e, +0x63, 0x51, 0x4d, 0x66, 0x47, 0x6a, 0x5a, 0x69, 0x4e, 0x47, 0x2f, 0x6d, 0x77, 0x74, 0x49, 0x72, +0x64, 0x6d, 0x31, 0x63, 0x52, 0x61, 0x32, 0x2b, 0x6a, 0x75, 0x47, 0x2b, 0x2f, 0x58, 0x68, 0x55, +0x34, 0x32, 0x68, 0x6f, 0x62, 0x72, 0x66, 0x4b, 0x4c, 0x44, 0x4b, 0x55, 0x4a, 0x4c, 0x59, 0x2f, +0x6e, 0x6e, 0x73, 0x4e, 0x63, 0x66, 0x33, 0x32, 0x76, 0x31, 0x34, 0x2b, 0x36, 0x74, 0x6f, 0x62, +0x72, 0x6a, 0x2f, 0x5a, 0x59, 0x75, 0x39, 0x46, 0x33, 0x4d, 0x77, 0x64, 0x5a, 0x78, 0x55, 0x64, +0x43, 0x73, 0x6b, 0x38, 0x68, 0x2f, 0x51, 0x78, 0x47, 0x49, 0x6b, 0x50, 0x66, 0x4d, 0x6f, 0x39, +0x37, 0x72, 0x68, 0x69, 0x45, 0x41, 0x6a, 0x79, 0x6c, 0x48, 0x41, 0x5a, 0x42, 0x4f, 0x6c, 0x62, +0x64, 0x6e, 0x6a, 0x4f, 0x48, 0x31, 0x74, 0x30, 0x47, 0x41, 0x47, 0x30, 0x48, 0x41, 0x4a, 0x6b, +0x4c, 0x2f, 0x68, 0x41, 0x66, 0x62, 0x34, 0x64, 0x38, 0x31, 0x4f, 0x4e, 0x74, 0x73, 0x46, 0x36, +0x36, 0x35, 0x55, 0x4f, 0x61, 0x2f, 0x4d, 0x50, 0x67, 0x79, 0x45, 0x41, 0x63, 0x49, 0x36, 0x32, +0x57, 0x36, 0x66, 0x72, 0x73, 0x31, 0x72, 0x48, 0x6f, 0x73, 0x62, 0x7a, 0x4e, 0x49, 0x78, 0x6e, +0x45, 0x4b, 0x63, 0x35, 0x4e, 0x57, 0x77, 0x37, 0x2f, 0x6e, 0x44, 0x75, 0x58, 0x51, 0x41, 0x5a, +0x63, 0x73, 0x4f, 0x73, 0x2b, 0x47, 0x50, 0x77, 0x73, 0x53, 0x38, 0x4c, 0x44, 0x49, 0x39, 0x2f, +0x50, 0x5a, 0x39, 0x41, 0x78, 0x43, 0x7a, 0x6c, 0x67, 0x35, 0x2f, 0x5a, 0x6f, 0x35, 0x74, 0x2f, +0x6e, 0x6e, 0x48, 0x6c, 0x6f, 0x62, 0x58, 0x6a, 0x6a, 0x37, 0x70, 0x48, 0x70, 0x77, 0x53, 0x2b, +0x30, 0x50, 0x48, 0x52, 0x59, 0x31, 0x38, 0x48, 0x57, 0x4d, 0x39, 0x68, 0x6a, 0x78, 0x49, 0x34, +0x38, 0x2b, 0x74, 0x35, 0x77, 0x61, 0x71, 0x6f, 0x39, 0x4a, 0x72, 0x2b, 0x65, 0x7a, 0x33, 0x45, +0x56, 0x44, 0x65, 0x52, 0x30, 0x4a, 0x62, 0x68, 0x33, 0x2f, 0x53, 0x35, 0x63, 0x64, 0x33, 0x77, +0x70, 0x33, 0x7a, 0x7a, 0x35, 0x50, 0x56, 0x31, 0x43, 0x45, 0x67, 0x51, 0x42, 0x4a, 0x35, 0x2b, +0x38, 0x43, 0x37, 0x47, 0x34, 0x34, 0x62, 0x4c, 0x4c, 0x6e, 0x2b, 0x58, 0x4b, 0x79, 0x33, 0x2f, +0x50, 0x77, 0x51, 0x64, 0x76, 0x79, 0x2f, 0x58, 0x58, 0x41, 0x31, 0x4a, 0x48, 0x30, 0x59, 0x34, +0x77, 0x43, 0x74, 0x4a, 0x72, 0x2b, 0x46, 0x44, 0x62, 0x65, 0x68, 0x41, 0x6d, 0x43, 0x6f, 0x38, +0x53, 0x45, 0x5a, 0x71, 0x6f, 0x4d, 0x47, 0x72, 0x69, 0x36, 0x4d, 0x36, 0x6c, 0x4d, 0x75, 0x7a, +0x55, 0x33, 0x4d, 0x5a, 0x37, 0x75, 0x70, 0x42, 0x6c, 0x4c, 0x62, 0x4d, 0x59, 0x6e, 0x62, 0x76, +0x43, 0x77, 0x62, 0x42, 0x4a, 0x44, 0x77, 0x41, 0x79, 0x76, 0x62, 0x5a, 0x4f, 0x4b, 0x73, 0x56, +0x56, 0x55, 0x6e, 0x4b, 0x2b, 0x6c, 0x41, 0x77, 0x53, 0x4e, 0x72, 0x44, 0x33, 0x53, 0x31, 0x42, +0x69, 0x45, 0x4e, 0x46, 0x76, 0x68, 0x50, 0x30, 0x2f, 0x52, 0x45, 0x72, 0x36, 0x2f, 0x53, 0x79, +0x5a, 0x63, 0x59, 0x31, 0x67, 0x30, 0x75, 0x42, 0x4f, 0x4c, 0x72, 0x35, 0x71, 0x48, 0x57, 0x56, +0x39, 0x50, 0x71, 0x64, 0x2f, 0x55, 0x51, 0x47, 0x58, 0x6a, 0x54, 0x36, 0x48, 0x43, 0x2b, 0x51, +0x34, 0x56, 0x6e, 0x52, 0x34, 0x50, 0x44, 0x62, 0x2f, 0x65, 0x56, 0x5a, 0x32, 0x4e, 0x46, 0x73, +0x2f, 0x41, 0x37, 0x68, 0x43, 0x49, 0x4e, 0x62, 0x42, 0x36, 0x6e, 0x6b, 0x65, 0x42, 0x5a, 0x4d, +0x6e, 0x59, 0x31, 0x70, 0x61, 0x4d, 0x45, 0x75, 0x57, 0x59, 0x76, 0x49, 0x4c, 0x69, 0x45, 0x32, +0x5a, 0x51, 0x74, 0x48, 0x71, 0x31, 0x58, 0x53, 0x65, 0x63, 0x77, 0x36, 0x42, 0x71, 0x32, 0x59, +0x64, 0x73, 0x6a, 0x4b, 0x33, 0x48, 0x6e, 0x55, 0x71, 0x56, 0x46, 0x62, 0x79, 0x53, 0x6c, 0x4f, +0x63, 0x4c, 0x59, 0x73, 0x37, 0x38, 0x61, 0x58, 0x69, 0x76, 0x59, 0x71, 0x64, 0x47, 0x46, 0x65, +0x2b, 0x67, 0x6f, 0x30, 0x2f, 0x62, 0x57, 0x44, 0x66, 0x34, 0x51, 0x4e, 0x70, 0x36, 0x46, 0x76, +0x43, 0x52, 0x61, 0x66, 0x75, 0x77, 0x71, 0x53, 0x37, 0x33, 0x75, 0x50, 0x59, 0x67, 0x30, 0x65, +0x53, 0x45, 0x2f, 0x66, 0x59, 0x66, 0x37, 0x66, 0x42, 0x33, 0x45, 0x75, 0x53, 0x50, 0x30, 0x32, +0x6f, 0x6f, 0x32, 0x2f, 0x66, 0x64, 0x44, 0x5a, 0x6e, 0x6f, 0x6b, 0x76, 0x7a, 0x7a, 0x47, 0x73, +0x72, 0x4f, 0x66, 0x30, 0x50, 0x2f, 0x51, 0x6e, 0x7a, 0x51, 0x44, 0x43, 0x47, 0x66, 0x7a, 0x79, +0x39, 0x6a, 0x4e, 0x4f, 0x4f, 0x72, 0x4b, 0x4d, 0x6f, 0x33, 0x34, 0x38, 0x6d, 0x6b, 0x4e, 0x4c, +0x7a, 0x68, 0x6f, 0x51, 0x47, 0x58, 0x45, 0x38, 0x6f, 0x35, 0x71, 0x74, 0x54, 0x41, 0x36, 0x61, +0x39, 0x4b, 0x6b, 0x67, 0x6c, 0x42, 0x5a, 0x34, 0x4a, 0x4f, 0x4f, 0x33, 0x55, 0x33, 0x71, 0x47, +0x59, 0x6d, 0x58, 0x48, 0x49, 0x55, 0x44, 0x45, 0x4c, 0x6e, 0x2f, 0x34, 0x58, 0x6f, 0x6d, 0x55, +0x39, 0x2b, 0x36, 0x39, 0x64, 0x6a, 0x52, 0x59, 0x53, 0x62, 0x39, 0x49, 0x6c, 0x6d, 0x47, 0x64, +0x66, 0x73, 0x56, 0x54, 0x56, 0x34, 0x66, 0x66, 0x63, 0x45, 0x71, 0x44, 0x34, 0x30, 0x6b, 0x76, +0x68, 0x71, 0x4b, 0x4d, 0x73, 0x2f, 0x66, 0x45, 0x52, 0x52, 0x39, 0x68, 0x31, 0x6c, 0x41, 0x6f, +0x4c, 0x49, 0x4b, 0x62, 0x5a, 0x64, 0x38, 0x7a, 0x44, 0x44, 0x36, 0x66, 0x50, 0x70, 0x59, 0x54, +0x79, 0x63, 0x73, 0x71, 0x75, 0x76, 0x4a, 0x4b, 0x6d, 0x37, 0x5a, 0x70, 0x70, 0x32, 0x51, 0x44, +0x4e, 0x47, 0x30, 0x4c, 0x67, 0x44, 0x64, 0x46, 0x73, 0x46, 0x39, 0x47, 0x51, 0x5a, 0x35, 0x7a, +0x4c, 0x73, 0x4c, 0x5a, 0x36, 0x79, 0x6f, 0x4e, 0x31, 0x62, 0x67, 0x43, 0x53, 0x36, 0x53, 0x4b, +0x4d, 0x36, 0x51, 0x47, 0x67, 0x4a, 0x78, 0x51, 0x31, 0x30, 0x77, 0x51, 0x50, 0x65, 0x66, 0x48, +0x70, 0x41, 0x47, 0x2b, 0x58, 0x4f, 0x4b, 0x62, 0x45, 0x34, 0x42, 0x32, 0x65, 0x69, 0x33, 0x34, +0x67, 0x41, 0x5a, 0x35, 0x49, 0x7a, 0x2f, 0x36, 0x52, 0x42, 0x53, 0x43, 0x69, 0x47, 0x4b, 0x35, +0x78, 0x46, 0x6f, 0x4c, 0x47, 0x2b, 0x65, 0x57, 0x55, 0x4c, 0x51, 0x4c, 0x79, 0x77, 0x4e, 0x65, +0x47, 0x53, 0x33, 0x64, 0x50, 0x74, 0x2b, 0x55, 0x32, 0x33, 0x76, 0x5a, 0x49, 0x65, 0x73, 0x2f, +0x4b, 0x43, 0x39, 0x74, 0x50, 0x42, 0x74, 0x6b, 0x4b, 0x46, 0x79, 0x49, 0x43, 0x44, 0x7a, 0x68, +0x76, 0x6e, 0x6a, 0x50, 0x33, 0x63, 0x61, 0x4f, 0x2b, 0x32, 0x35, 0x30, 0x46, 0x56, 0x46, 0x77, +0x51, 0x35, 0x39, 0x75, 0x50, 0x46, 0x6e, 0x46, 0x33, 0x36, 0x58, 0x4e, 0x63, 0x76, 0x6d, 0x34, +0x43, 0x69, 0x35, 0x64, 0x4a, 0x33, 0x69, 0x7a, 0x76, 0x77, 0x6b, 0x6a, 0x4a, 0x4e, 0x78, 0x2f, +0x64, 0x77, 0x56, 0x47, 0x44, 0x74, 0x2b, 0x66, 0x4b, 0x6b, 0x54, 0x6d, 0x49, 0x5a, 0x42, 0x49, +0x68, 0x59, 0x76, 0x54, 0x70, 0x6b, 0x38, 0x2f, 0x7a, 0x6e, 0x33, 0x37, 0x43, 0x78, 0x71, 0x47, +0x66, 0x38, 0x74, 0x72, 0x72, 0x48, 0x6b, 0x66, 0x39, 0x77, 0x66, 0x45, 0x49, 0x53, 0x4b, 0x76, +0x41, 0x79, 0x71, 0x33, 0x50, 0x68, 0x64, 0x78, 0x30, 0x45, 0x70, 0x47, 0x51, 0x61, 0x52, 0x2b, +0x41, 0x6b, 0x46, 0x37, 0x6b, 0x4b, 0x56, 0x58, 0x4b, 0x72, 0x66, 0x47, 0x31, 0x56, 0x57, 0x79, +0x70, 0x4e, 0x44, 0x46, 0x50, 0x73, 0x6c, 0x65, 0x2f, 0x77, 0x7a, 0x44, 0x61, 0x34, 0x4f, 0x75, +0x33, 0x58, 0x59, 0x7a, 0x63, 0x7a, 0x36, 0x43, 0x56, 0x39, 0x79, 0x49, 0x4c, 0x34, 0x45, 0x47, +0x70, 0x61, 0x42, 0x61, 0x43, 0x32, 0x36, 0x54, 0x6b, 0x6e, 0x30, 0x4c, 0x79, 0x30, 0x68, 0x4a, +0x42, 0x49, 0x74, 0x2b, 0x53, 0x75, 0x53, 0x6f, 0x74, 0x55, 0x4e, 0x70, 0x53, 0x71, 0x57, 0x6b, +0x64, 0x6f, 0x42, 0x79, 0x74, 0x57, 0x6e, 0x6d, 0x65, 0x35, 0x4d, 0x6f, 0x4e, 0x31, 0x72, 0x32, +0x5a, 0x32, 0x66, 0x2f, 0x35, 0x51, 0x6e, 0x4b, 0x51, 0x46, 0x48, 0x7a, 0x30, 0x62, 0x63, 0x44, +0x44, 0x44, 0x77, 0x6b, 0x75, 0x75, 0x6b, 0x51, 0x51, 0x38, 0x7a, 0x6f, 0x77, 0x5a, 0x6a, 0x49, +0x35, 0x66, 0x73, 0x44, 0x67, 0x6b, 0x72, 0x35, 0x63, 0x76, 0x2f, 0x32, 0x6a, 0x64, 0x4d, 0x6f, +0x69, 0x58, 0x76, 0x7a, 0x34, 0x52, 0x58, 0x67, 0x50, 0x57, 0x77, 0x58, 0x49, 0x68, 0x62, 0x71, +0x31, 0x55, 0x4a, 0x6a, 0x35, 0x38, 0x7a, 0x48, 0x37, 0x37, 0x49, 0x4f, 0x5a, 0x39, 0x6c, 0x39, +0x4d, 0x51, 0x59, 0x47, 0x46, 0x42, 0x62, 0x2f, 0x7a, 0x44, 0x6a, 0x71, 0x52, 0x69, 0x41, 0x71, +0x44, 0x68, 0x50, 0x33, 0x66, 0x2f, 0x4f, 0x34, 0x4d, 0x58, 0x69, 0x6f, 0x2b, 0x67, 0x4d, 0x39, +0x57, 0x43, 0x64, 0x62, 0x70, 0x50, 0x4c, 0x52, 0x55, 0x66, 0x50, 0x54, 0x66, 0x4f, 0x63, 0x79, +0x70, 0x4b, 0x32, 0x5a, 0x6b, 0x54, 0x50, 0x48, 0x79, 0x47, 0x33, 0x4d, 0x35, 0x2b, 0x61, 0x67, +0x78, 0x76, 0x50, 0x37, 0x42, 0x7a, 0x37, 0x5a, 0x4d, 0x2b, 0x68, 0x64, 0x4c, 0x38, 0x57, 0x4d, +0x65, 0x62, 0x33, 0x32, 0x38, 0x69, 0x4d, 0x77, 0x74, 0x62, 0x4f, 0x4f, 0x38, 0x58, 0x44, 0x68, +0x69, 0x58, 0x38, 0x74, 0x78, 0x2b, 0x50, 0x4b, 0x37, 0x61, 0x35, 0x44, 0x43, 0x63, 0x50, 0x53, +0x42, 0x4e, 0x5a, 0x78, 0x34, 0x63, 0x43, 0x30, 0x46, 0x75, 0x56, 0x34, 0x50, 0x2b, 0x62, 0x46, +0x4c, 0x67, 0x46, 0x36, 0x67, 0x6d, 0x4d, 0x66, 0x2b, 0x49, 0x65, 0x44, 0x7a, 0x54, 0x77, 0x58, +0x4a, 0x5a, 0x4d, 0x41, 0x70, 0x4a, 0x2f, 0x77, 0x53, 0x6c, 0x44, 0x63, 0x39, 0x30, 0x32, 0x41, +0x67, 0x63, 0x66, 0x53, 0x4a, 0x64, 0x45, 0x79, 0x2b, 0x6d, 0x4a, 0x38, 0x36, 0x41, 0x34, 0x59, +0x68, 0x79, 0x62, 0x6e, 0x35, 0x37, 0x31, 0x52, 0x6b, 0x4b, 0x4c, 0x38, 0x78, 0x61, 0x56, 0x5a, +0x55, 0x2f, 0x76, 0x55, 0x76, 0x69, 0x35, 0x6e, 0x57, 0x47, 0x76, 0x4f, 0x50, 0x75, 0x36, 0x41, +0x33, 0x38, 0x2f, 0x48, 0x39, 0x39, 0x7a, 0x45, 0x58, 0x58, 0x4a, 0x41, 0x46, 0x4c, 0x50, 0x4b, +0x47, 0x44, 0x45, 0x47, 0x33, 0x74, 0x46, 0x42, 0x51, 0x42, 0x38, 0x58, 0x46, 0x68, 0x68, 0x49, +0x52, 0x7a, 0x76, 0x6a, 0x4f, 0x41, 0x70, 0x44, 0x70, 0x32, 0x56, 0x37, 0x4b, 0x4e, 0x43, 0x68, +0x48, 0x4f, 0x73, 0x64, 0x49, 0x6e, 0x31, 0x49, 0x44, 0x4d, 0x57, 0x31, 0x4e, 0x36, 0x4a, 0x41, +0x75, 0x53, 0x67, 0x52, 0x32, 0x41, 0x4e, 0x43, 0x39, 0x51, 0x31, 0x41, 0x6a, 0x43, 0x38, 0x43, +0x6c, 0x71, 0x53, 0x4a, 0x42, 0x2b, 0x2b, 0x41, 0x74, 0x36, 0x6f, 0x4a, 0x2b, 0x41, 0x57, 0x5a, +0x4a, 0x46, 0x36, 0x69, 0x55, 0x62, 0x55, 0x73, 0x68, 0x73, 0x73, 0x31, 0x2f, 0x59, 0x57, 0x64, +0x2b, 0x75, 0x38, 0x52, 0x79, 0x67, 0x77, 0x48, 0x57, 0x45, 0x39, 0x33, 0x6c, 0x6e, 0x6e, 0x33, +0x69, 0x72, 0x6d, 0x6e, 0x7a, 0x65, 0x65, 0x57, 0x61, 0x4e, 0x65, 0x54, 0x48, 0x69, 0x77, 0x68, +0x55, 0x69, 0x6d, 0x57, 0x72, 0x47, 0x6d, 0x6e, 0x6f, 0x56, 0x39, 0x74, 0x72, 0x2b, 0x36, 0x33, +0x36, 0x37, 0x31, 0x5a, 0x55, 0x56, 0x5a, 0x55, 0x52, 0x49, 0x68, 0x6e, 0x66, 0x76, 0x57, 0x38, +0x6b, 0x34, 0x66, 0x49, 0x6e, 0x4f, 0x78, 0x7a, 0x71, 0x5a, 0x6e, 0x2b, 0x58, 0x4d, 0x65, 0x6e, +0x37, 0x50, 0x6f, 0x73, 0x58, 0x35, 0x37, 0x50, 0x64, 0x64, 0x6d, 0x75, 0x35, 0x63, 0x4f, 0x38, +0x43, 0x70, 0x47, 0x78, 0x6d, 0x52, 0x6d, 0x4d, 0x4f, 0x55, 0x76, 0x67, 0x49, 0x34, 0x64, 0x4d, +0x35, 0x62, 0x78, 0x37, 0x6e, 0x7a, 0x39, 0x49, 0x4f, 0x57, 0x74, 0x2f, 0x46, 0x75, 0x75, 0x59, +0x32, 0x64, 0x71, 0x6c, 0x5a, 0x53, 0x35, 0x30, 0x61, 0x52, 0x6e, 0x56, 0x70, 0x44, 0x67, 0x73, +0x58, 0x4e, 0x71, 0x55, 0x48, 0x67, 0x4b, 0x78, 0x55, 0x35, 0x39, 0x34, 0x48, 0x41, 0x4b, 0x33, +0x74, 0x45, 0x73, 0x43, 0x45, 0x53, 0x77, 0x42, 0x74, 0x45, 0x37, 0x65, 0x30, 0x57, 0x77, 0x4b, +0x6b, 0x2b, 0x38, 0x6f, 0x4f, 0x34, 0x42, 0x33, 0x74, 0x68, 0x6a, 0x76, 0x75, 0x72, 0x57, 0x54, +0x45, 0x77, 0x41, 0x2f, 0x34, 0x58, 0x59, 0x64, 0x42, 0x35, 0x47, 0x45, 0x54, 0x73, 0x30, 0x54, +0x61, 0x45, 0x52, 0x67, 0x4f, 0x41, 0x47, 0x63, 0x72, 0x79, 0x59, 0x56, 0x53, 0x63, 0x6f, 0x48, +0x72, 0x76, 0x32, 0x64, 0x2b, 0x45, 0x72, 0x54, 0x6d, 0x42, 0x70, 0x5a, 0x6c, 0x32, 0x50, 0x6c, +0x73, 0x49, 0x6d, 0x34, 0x39, 0x31, 0x33, 0x39, 0x44, 0x53, 0x67, 0x55, 0x74, 0x6a, 0x7a, 0x6e, +0x35, 0x7a, 0x65, 0x68, 0x2f, 0x49, 0x53, 0x51, 0x33, 0x43, 0x4d, 0x48, 0x49, 0x51, 0x77, 0x4c, +0x32, 0x4f, 0x31, 0x59, 0x51, 0x38, 0x77, 0x4a, 0x73, 0x70, 0x65, 0x6a, 0x4c, 0x43, 0x46, 0x51, +0x6c, 0x6a, 0x5a, 0x31, 0x78, 0x48, 0x76, 0x76, 0x70, 0x48, 0x79, 0x7a, 0x74, 0x57, 0x41, 0x75, +0x66, 0x68, 0x42, 0x61, 0x41, 0x6e, 0x66, 0x31, 0x44, 0x56, 0x75, 0x53, 0x4e, 0x39, 0x39, 0x39, +0x50, 0x43, 0x56, 0x69, 0x32, 0x5a, 0x36, 0x30, 0x78, 0x68, 0x51, 0x57, 0x30, 0x54, 0x35, 0x32, +0x4b, 0x61, 0x47, 0x39, 0x50, 0x2b, 0x77, 0x44, 0x63, 0x45, 0x75, 0x43, 0x66, 0x37, 0x32, 0x7a, +0x67, 0x38, 0x6f, 0x4e, 0x38, 0x59, 0x6b, 0x45, 0x58, 0x6e, 0x36, 0x6b, 0x79, 0x41, 0x71, 0x47, +0x49, 0x79, 0x78, 0x51, 0x2f, 0x4c, 0x55, 0x7a, 0x77, 0x72, 0x64, 0x42, 0x67, 0x34, 0x4e, 0x36, +0x6e, 0x76, 0x69, 0x4b, 0x51, 0x45, 0x6a, 0x41, 0x63, 0x76, 0x50, 0x64, 0x51, 0x48, 0x6e, 0x31, +0x78, 0x4e, 0x6c, 0x58, 0x6c, 0x68, 0x55, 0x41, 0x51, 0x34, 0x51, 0x42, 0x43, 0x2f, 0x55, 0x73, +0x46, 0x6d, 0x6b, 0x64, 0x65, 0x58, 0x73, 0x46, 0x6c, 0x45, 0x77, 0x64, 0x78, 0x35, 0x4c, 0x35, +0x70, 0x33, 0x39, 0x74, 0x6a, 0x72, 0x36, 0x7a, 0x69, 0x6e, 0x44, 0x2f, 0x57, 0x6b, 0x35, 0x2f, +0x6e, 0x52, 0x2f, 0x49, 0x6a, 0x70, 0x53, 0x51, 0x65, 0x2b, 0x79, 0x75, 0x63, 0x4d, 0x30, 0x47, +0x77, 0x5a, 0x47, 0x50, 0x67, 0x53, 0x6e, 0x6b, 0x37, 0x51, 0x64, 0x63, 0x42, 0x59, 0x72, 0x78, +0x64, 0x36, 0x34, 0x37, 0x39, 0x62, 0x33, 0x59, 0x6a, 0x53, 0x69, 0x33, 0x5a, 0x6f, 0x6f, 0x39, +0x6b, 0x35, 0x6e, 0x58, 0x51, 0x39, 0x45, 0x47, 0x49, 0x70, 0x58, 0x65, 0x57, 0x41, 0x46, 0x41, +0x34, 0x66, 0x45, 0x76, 0x38, 0x68, 0x35, 0x39, 0x6c, 0x78, 0x50, 0x73, 0x6e, 0x55, 0x37, 0x62, +0x6e, 0x59, 0x36, 0x69, 0x38, 0x76, 0x41, 0x78, 0x54, 0x30, 0x48, 0x31, 0x50, 0x61, 0x2b, 0x75, +0x56, 0x42, 0x38, 0x73, 0x6c, 0x74, 0x32, 0x77, 0x5a, 0x66, 0x50, 0x49, 0x70, 0x5a, 0x72, 0x66, +0x64, 0x73, 0x6f, 0x56, 0x48, 0x43, 0x4d, 0x78, 0x54, 0x54, 0x32, 0x55, 0x70, 0x66, 0x32, 0x69, +0x75, 0x53, 0x2b, 0x43, 0x48, 0x32, 0x35, 0x5a, 0x54, 0x33, 0x37, 0x65, 0x65, 0x4e, 0x4d, 0x5a, +0x37, 0x45, 0x37, 0x75, 0x32, 0x6a, 0x4b, 0x76, 0x68, 0x47, 0x74, 0x76, 0x33, 0x66, 0x59, 0x37, +0x61, 0x35, 0x69, 0x66, 0x30, 0x4f, 0x48, 0x66, 0x2f, 0x77, 0x45, 0x47, 0x52, 0x67, 0x2b, 0x36, +0x4b, 0x37, 0x35, 0x59, 0x41, 0x4a, 0x76, 0x76, 0x39, 0x6c, 0x62, 0x62, 0x78, 0x64, 0x4c, 0x38, +0x54, 0x65, 0x44, 0x65, 0x4a, 0x57, 0x64, 0x6b, 0x43, 0x52, 0x74, 0x68, 0x5a, 0x7a, 0x5a, 0x6f, +0x68, 0x47, 0x55, 0x63, 0x4e, 0x51, 0x75, 0x4d, 0x70, 0x44, 0x64, 0x4b, 0x67, 0x64, 0x52, 0x72, +0x4a, 0x70, 0x61, 0x51, 0x6d, 0x7a, 0x2f, 0x63, 0x6f, 0x4b, 0x39, 0x57, 0x55, 0x6f, 0x39, 0x44, +0x43, 0x6d, 0x6d, 0x78, 0x31, 0x46, 0x52, 0x58, 0x45, 0x48, 0x47, 0x71, 0x76, 0x70, 0x72, 0x4c, +0x53, 0x57, 0x67, 0x34, 0x36, 0x58, 0x51, 0x4e, 0x65, 0x2b, 0x7a, 0x35, 0x42, 0x52, 0x78, 0x75, +0x76, 0x7a, 0x56, 0x58, 0x73, 0x73, 0x6b, 0x32, 0x4d, 0x52, 0x45, 0x70, 0x48, 0x4a, 0x72, 0x35, +0x56, 0x64, 0x4b, 0x49, 0x5a, 0x50, 0x2f, 0x30, 0x35, 0x30, 0x58, 0x6c, 0x68, 0x66, 0x6f, 0x78, +0x50, 0x33, 0x75, 0x34, 0x41, 0x72, 0x45, 0x63, 0x2f, 0x43, 0x42, 0x7a, 0x70, 0x53, 0x47, 0x44, +0x4c, 0x55, 0x56, 0x6e, 0x46, 0x31, 0x77, 0x67, 0x68, 0x43, 0x51, 0x4c, 0x42, 0x51, 0x77, 0x39, +0x2b, 0x78, 0x48, 0x6e, 0x6e, 0x6a, 0x71, 0x64, 0x2b, 0x55, 0x42, 0x46, 0x7a, 0x35, 0x7a, 0x62, +0x79, 0x6e, 0x35, 0x65, 0x2f, 0x64, 0x67, 0x4f, 0x41, 0x52, 0x68, 0x72, 0x50, 0x57, 0x56, 0x6a, +0x57, 0x52, 0x4e, 0x2b, 0x63, 0x42, 0x57, 0x43, 0x4d, 0x69, 0x63, 0x7a, 0x39, 0x45, 0x45, 0x67, +0x57, 0x77, 0x71, 0x61, 0x74, 0x46, 0x57, 0x31, 0x2f, 0x70, 0x37, 0x4d, 0x7a, 0x52, 0x64, 0x33, +0x41, 0x44, 0x7a, 0x68, 0x73, 0x31, 0x34, 0x66, 0x34, 0x37, 0x50, 0x4e, 0x64, 0x43, 0x55, 0x71, +0x74, 0x45, 0x7a, 0x43, 0x30, 0x45, 0x70, 0x51, 0x79, 0x55, 0x54, 0x67, 0x74, 0x56, 0x77, 0x6a, +0x75, 0x7a, 0x2b, 0x67, 0x2f, 0x71, 0x51, 0x57, 0x70, 0x6a, 0x4b, 0x56, 0x61, 0x46, 0x71, 0x56, +0x36, 0x5a, 0x76, 0x2f, 0x46, 0x53, 0x63, 0x74, 0x66, 0x45, 0x4c, 0x42, 0x59, 0x53, 0x71, 0x59, +0x55, 0x42, 0x50, 0x78, 0x2b, 0x6b, 0x6d, 0x43, 0x76, 0x58, 0x58, 0x79, 0x4d, 0x47, 0x59, 0x48, +0x51, 0x45, 0x32, 0x6e, 0x73, 0x6a, 0x50, 0x48, 0x55, 0x2f, 0x44, 0x64, 0x34, 0x66, 0x39, 0x55, +0x73, 0x46, 0x72, 0x54, 0x2b, 0x69, 0x41, 0x77, 0x36, 0x32, 0x4b, 0x4a, 0x69, 0x53, 0x4c, 0x6f, +0x77, 0x53, 0x34, 0x52, 0x79, 0x74, 0x61, 0x7a, 0x49, 0x75, 0x57, 0x56, 0x6c, 0x6d, 0x47, 0x32, +0x33, 0x78, 0x62, 0x53, 0x31, 0x59, 0x7a, 0x37, 0x39, 0x42, 0x48, 0x50, 0x6b, 0x6b, 0x65, 0x51, +0x55, 0x46, 0x78, 0x4f, 0x73, 0x58, 0x78, 0x39, 0x5a, 0x47, 0x71, 0x48, 0x73, 0x67, 0x77, 0x33, +0x5a, 0x43, 0x61, 0x6b, 0x35, 0x63, 0x75, 0x39, 0x68, 0x44, 0x42, 0x74, 0x55, 0x77, 0x58, 0x58, +0x33, 0x66, 0x6f, 0x42, 0x55, 0x47, 0x72, 0x52, 0x46, 0x67, 0x32, 0x70, 0x74, 0x67, 0x57, 0x32, +0x70, 0x6c, 0x4f, 0x53, 0x4f, 0x52, 0x7a, 0x37, 0x44, 0x39, 0x77, 0x77, 0x56, 0x70, 0x62, 0x59, +0x30, 0x32, 0x57, 0x4e, 0x54, 0x56, 0x33, 0x4c, 0x77, 0x76, 0x6b, 0x56, 0x30, 0x4a, 0x69, 0x51, +0x68, 0x32, 0x63, 0x75, 0x4f, 0x6f, 0x30, 0x72, 0x35, 0x34, 0x4f, 0x76, 0x31, 0x45, 0x66, 0x4a, +0x54, 0x4b, 0x38, 0x4d, 0x32, 0x77, 0x77, 0x72, 0x35, 0x61, 0x47, 0x59, 0x4c, 0x59, 0x64, 0x35, +0x49, 0x55, 0x57, 0x47, 0x63, 0x6d, 0x36, 0x66, 0x38, 0x54, 0x42, 0x79, 0x4a, 0x5a, 0x64, 0x6c, +0x52, 0x61, 0x66, 0x4b, 0x46, 0x79, 0x4e, 0x54, 0x56, 0x49, 0x75, 0x4d, 0x6f, 0x45, 0x43, 0x71, +0x44, 0x6c, 0x56, 0x5a, 0x62, 0x55, 0x73, 0x71, 0x79, 0x62, 0x51, 0x66, 0x41, 0x4e, 0x62, 0x64, +0x67, 0x31, 0x71, 0x79, 0x4b, 0x46, 0x4e, 0x50, 0x72, 0x36, 0x69, 0x4b, 0x2f, 0x73, 0x34, 0x50, +0x55, 0x67, 0x51, 0x70, 0x2f, 0x38, 0x75, 0x6e, 0x45, 0x64, 0x44, 0x45, 0x6d, 0x48, 0x6f, 0x39, +0x4d, 0x58, 0x37, 0x53, 0x43, 0x32, 0x6e, 0x70, 0x71, 0x37, 0x6e, 0x38, 0x43, 0x44, 0x63, 0x53, +0x6b, 0x78, 0x4b, 0x52, 0x53, 0x63, 0x4d, 0x38, 0x39, 0x56, 0x73, 0x69, 0x33, 0x33, 0x78, 0x34, +0x54, 0x69, 0x31, 0x6d, 0x75, 0x2f, 0x43, 0x6c, 0x54, 0x4d, 0x4a, 0x39, 0x39, 0x31, 0x68, 0x4e, +0x4b, 0x37, 0x44, 0x44, 0x65, 0x67, 0x32, 0x38, 0x62, 0x62, 0x46, 0x6c, 0x56, 0x32, 0x78, 0x62, +0x33, 0x36, 0x69, 0x31, 0x50, 0x48, 0x37, 0x4f, 0x66, 0x66, 0x32, 0x6a, 0x5a, 0x55, 0x4f, 0x62, +0x38, 0x66, 0x51, 0x36, 0x70, 0x38, 0x50, 0x34, 0x69, 0x44, 0x55, 0x58, 0x75, 0x62, 0x63, 0x30, +0x59, 0x4c, 0x67, 0x47, 0x36, 0x76, 0x33, 0x2f, 0x72, 0x2f, 0x45, 0x38, 0x70, 0x33, 0x32, 0x4c, +0x6e, 0x39, 0x4d, 0x43, 0x32, 0x71, 0x51, 0x45, 0x6f, 0x63, 0x2f, 0x59, 0x47, 0x38, 0x44, 0x77, +0x32, 0x48, 0x50, 0x30, 0x73, 0x66, 0x4b, 0x50, 0x78, 0x55, 0x77, 0x47, 0x2f, 0x75, 0x2b, 0x38, +0x4d, 0x56, 0x72, 0x61, 0x33, 0x6f, 0x61, 0x53, 0x4b, 0x71, 0x75, 0x69, 0x45, 0x77, 0x4a, 0x30, +0x6c, 0x71, 0x56, 0x52, 0x47, 0x76, 0x58, 0x6d, 0x42, 0x56, 0x70, 0x71, 0x38, 0x77, 0x59, 0x50, +0x35, 0x37, 0x4b, 0x4f, 0x50, 0x2b, 0x50, 0x43, 0x76, 0x58, 0x7a, 0x43, 0x6b, 0x66, 0x77, 0x6d, +0x74, 0x48, 0x55, 0x47, 0x61, 0x73, 0x44, 0x57, 0x73, 0x7a, 0x65, 0x66, 0x4f, 0x77, 0x32, 0x79, +0x7a, 0x4d, 0x41, 0x31, 0x59, 0x61, 0x55, 0x4e, 0x46, 0x53, 0x51, 0x36, 0x33, 0x54, 0x70, 0x73, +0x50, 0x57, 0x43, 0x53, 0x66, 0x68, 0x53, 0x4a, 0x4c, 0x70, 0x2f, 0x43, 0x4b, 0x49, 0x41, 0x6a, +0x50, 0x4a, 0x55, 0x4c, 0x41, 0x6b, 0x30, 0x39, 0x39, 0x79, 0x74, 0x4e, 0x50, 0x66, 0x34, 0x30, +0x51, 0x6b, 0x6b, 0x53, 0x69, 0x6b, 0x36, 0x46, 0x44, 0x2b, 0x39, 0x6b, 0x42, 0x49, 0x4e, 0x42, +0x49, 0x47, 0x58, 0x4e, 0x4c, 0x4c, 0x65, 0x77, 0x36, 0x76, 0x37, 0x66, 0x33, 0x78, 0x6c, 0x6f, +0x41, 0x6d, 0x44, 0x42, 0x6e, 0x49, 0x6d, 0x32, 0x2b, 0x32, 0x69, 0x56, 0x34, 0x65, 0x67, 0x42, +0x52, 0x30, 0x6e, 0x42, 0x7a, 0x2f, 0x37, 0x75, 0x35, 0x5a, 0x4f, 0x6b, 0x35, 0x78, 0x50, 0x37, +0x50, 0x34, 0x34, 0x57, 0x36, 0x69, 0x36, 0x4f, 0x6c, 0x6e, 0x4e, 0x51, 0x47, 0x46, 0x31, 0x30, +0x44, 0x4e, 0x77, 0x42, 0x30, 0x37, 0x37, 0x39, 0x41, 0x42, 0x51, 0x53, 0x2b, 0x36, 0x33, 0x65, +0x64, 0x49, 0x62, 0x2b, 0x79, 0x57, 0x2f, 0x38, 0x35, 0x42, 0x66, 0x61, 0x6c, 0x35, 0x48, 0x30, +0x68, 0x2b, 0x4f, 0x38, 0x41, 0x78, 0x61, 0x54, 0x62, 0x42, 0x6c, 0x42, 0x52, 0x50, 0x4a, 0x47, +0x31, 0x69, 0x55, 0x4b, 0x57, 0x74, 0x43, 0x65, 0x34, 0x59, 0x65, 0x59, 0x55, 0x66, 0x6d, 0x37, +0x35, 0x6e, 0x69, 0x44, 0x56, 0x67, 0x53, 0x42, 0x41, 0x49, 0x70, 0x41, 0x78, 0x68, 0x55, 0x51, +0x35, 0x34, 0x41, 0x39, 0x75, 0x39, 0x6b, 0x39, 0x48, 0x6e, 0x46, 0x4a, 0x4e, 0x54, 0x58, 0x68, +0x58, 0x58, 0x45, 0x46, 0x79, 0x32, 0x54, 0x4b, 0x43, 0x39, 0x6e, 0x5a, 0x4b, 0x50, 0x2f, 0x6d, +0x45, 0x6a, 0x68, 0x55, 0x72, 0x33, 0x43, 0x51, 0x6a, 0x30, 0x46, 0x4c, 0x68, 0x68, 0x36, 0x7a, +0x4d, 0x32, 0x48, 0x52, 0x76, 0x59, 0x77, 0x77, 0x37, 0x62, 0x31, 0x64, 0x50, 0x63, 0x55, 0x45, +0x4f, 0x45, 0x77, 0x34, 0x59, 0x77, 0x64, 0x4f, 0x76, 0x7a, 0x4c, 0x45, 0x5a, 0x67, 0x69, 0x37, +0x73, 0x6d, 0x67, 0x77, 0x45, 0x2f, 0x57, 0x74, 0x4c, 0x2b, 0x63, 0x4d, 0x42, 0x49, 0x37, 0x6a, +0x78, 0x67, 0x59, 0x2b, 0x69, 0x41, 0x66, 0x54, 0x71, 0x38, 0x7a, 0x39, 0x68, 0x78, 0x54, 0x57, +0x46, 0x4c, 0x46, 0x37, 0x5a, 0x61, 0x51, 0x64, 0x73, 0x71, 0x57, 0x77, 0x4a, 0x73, 0x38, 0x42, +0x42, 0x79, 0x63, 0x4d, 0x30, 0x62, 0x6d, 0x6b, 0x51, 0x77, 0x6a, 0x46, 0x67, 0x53, 0x38, 0x50, +0x51, 0x41, 0x55, 0x58, 0x4d, 0x65, 0x65, 0x55, 0x56, 0x34, 0x67, 0x51, 0x67, 0x74, 0x4b, 0x52, +0x66, 0x30, 0x61, 0x39, 0x6b, 0x4a, 0x63, 0x31, 0x6b, 0x68, 0x64, 0x57, 0x67, 0x31, 0x77, 0x6e, +0x38, 0x48, 0x37, 0x2b, 0x33, 0x5a, 0x6d, 0x30, 0x47, 0x6c, 0x4c, 0x64, 0x72, 0x51, 0x6a, 0x36, +0x78, 0x6e, 0x48, 0x35, 0x34, 0x69, 0x66, 0x56, 0x34, 0x51, 0x53, 0x76, 0x4f, 0x67, 0x32, 0x4f, +0x56, 0x58, 0x79, 0x70, 0x6f, 0x58, 0x4a, 0x30, 0x47, 0x45, 0x32, 0x56, 0x43, 0x67, 0x65, 0x39, +0x2f, 0x41, 0x47, 0x71, 0x71, 0x49, 0x54, 0x63, 0x58, 0x62, 0x2f, 0x6c, 0x79, 0x61, 0x47, 0x32, +0x46, 0x67, 0x51, 0x50, 0x54, 0x4b, 0x4c, 0x5a, 0x75, 0x55, 0x47, 0x43, 0x6b, 0x59, 0x31, 0x58, +0x39, 0x2f, 0x2f, 0x4c, 0x38, 0x51, 0x53, 0x2f, 0x33, 0x6c, 0x77, 0x70, 0x38, 0x36, 0x79, 0x54, +0x79, 0x50, 0x4a, 0x75, 0x34, 0x42, 0x49, 0x4b, 0x59, 0x4c, 0x78, 0x6e, 0x53, 0x70, 0x2b, 0x66, +0x37, 0x56, 0x39, 0x66, 0x75, 0x7a, 0x6f, 0x33, 0x79, 0x43, 0x6f, 0x53, 0x52, 0x4b, 0x49, 0x53, +0x4c, 0x2b, 0x34, 0x65, 0x78, 0x34, 0x2f, 0x53, 0x75, 0x6a, 0x45, 0x49, 0x6a, 0x4c, 0x52, 0x35, +0x41, 0x61, 0x7a, 0x53, 0x53, 0x46, 0x34, 0x61, 0x38, 0x42, 0x52, 0x2b, 0x63, 0x54, 0x4d, 0x6e, +0x71, 0x52, 0x63, 0x52, 0x72, 0x61, 0x74, 0x43, 0x56, 0x6c, 0x63, 0x52, 0x6b, 0x47, 0x4d, 0x61, +0x55, 0x62, 0x6b, 0x30, 0x70, 0x38, 0x46, 0x57, 0x36, 0x39, 0x4a, 0x66, 0x52, 0x32, 0x68, 0x36, +0x56, 0x77, 0x67, 0x65, 0x75, 0x4f, 0x33, 0x73, 0x72, 0x71, 0x69, 0x76, 0x79, 0x4d, 0x4b, 0x62, +0x51, 0x39, 0x6f, 0x64, 0x78, 0x48, 0x6d, 0x42, 0x6a, 0x63, 0x77, 0x4b, 0x79, 0x4b, 0x2b, 0x71, +0x47, 0x6a, 0x6c, 0x71, 0x4e, 0x4e, 0x76, 0x44, 0x45, 0x35, 0x4f, 0x45, 0x63, 0x4d, 0x79, 0x48, +0x68, 0x57, 0x47, 0x33, 0x37, 0x57, 0x41, 0x47, 0x52, 0x49, 0x66, 0x32, 0x59, 0x33, 0x65, 0x32, +0x35, 0x4a, 0x4a, 0x50, 0x50, 0x58, 0x36, 0x6b, 0x53, 0x53, 0x79, 0x67, 0x43, 0x6b, 0x4e, 0x41, +0x49, 0x37, 0x56, 0x4e, 0x54, 0x43, 0x6b, 0x49, 0x5a, 0x6b, 0x6b, 0x47, 0x36, 0x70, 0x6b, 0x73, +0x6d, 0x6c, 0x44, 0x6a, 0x6d, 0x77, 0x63, 0x41, 0x71, 0x77, 0x48, 0x68, 0x32, 0x51, 0x44, 0x4a, +0x45, 0x53, 0x77, 0x43, 0x70, 0x44, 0x46, 0x58, 0x6c, 0x75, 0x4f, 0x57, 0x5a, 0x47, 0x39, 0x2b, +0x6c, 0x7a, 0x78, 0x50, 0x6c, 0x44, 0x79, 0x43, 0x6b, 0x6f, 0x61, 0x2f, 0x45, 0x45, 0x61, 0x74, +0x59, 0x65, 0x4c, 0x57, 0x46, 0x4d, 0x39, 0x4f, 0x37, 0x2f, 0x45, 0x68, 0x46, 0x58, 0x5a, 0x47, +0x67, 0x4d, 0x45, 0x64, 0x45, 0x73, 0x33, 0x32, 0x76, 0x2f, 0x57, 0x38, 0x55, 0x2b, 0x44, 0x41, +0x50, 0x57, 0x46, 0x4e, 0x65, 0x79, 0x55, 0x2b, 0x48, 0x39, 0x6d, 0x58, 0x53, 0x36, 0x55, 0x66, +0x54, 0x6c, 0x41, 0x69, 0x34, 0x2f, 0x63, 0x75, 0x58, 0x57, 0x4c, 0x42, 0x78, 0x45, 0x55, 0x47, +0x77, 0x45, 0x59, 0x31, 0x6b, 0x59, 0x47, 0x6c, 0x74, 0x56, 0x44, 0x53, 0x31, 0x75, 0x2f, 0x78, +0x49, 0x73, 0x48, 0x36, 0x75, 0x66, 0x76, 0x30, 0x63, 0x56, 0x6b, 0x5a, 0x68, 0x70, 0x43, 0x41, +0x70, 0x42, 0x4c, 0x71, 0x36, 0x6d, 0x6c, 0x68, 0x35, 0x4f, 0x52, 0x31, 0x72, 0x31, 0x78, 0x49, +0x66, 0x4d, 0x4d, 0x44, 0x32, 0x70, 0x37, 0x4c, 0x4b, 0x48, 0x39, 0x4c, 0x4b, 0x68, 0x32, 0x5a, +0x38, 0x52, 0x5a, 0x38, 0x43, 0x33, 0x76, 0x70, 0x6b, 0x45, 0x61, 0x4f, 0x48, 0x56, 0x2f, 0x50, +0x68, 0x6c, 0x30, 0x74, 0x70, 0x71, 0x43, 0x30, 0x6c, 0x6c, 0x56, 0x49, 0x6f, 0x59, 0x78, 0x57, +0x32, 0x4b, 0x78, 0x6c, 0x77, 0x38, 0x63, 0x53, 0x64, 0x47, 0x62, 0x6c, 0x46, 0x44, 0x61, 0x6c, +0x41, 0x38, 0x64, 0x4a, 0x62, 0x50, 0x78, 0x41, 0x69, 0x52, 0x57, 0x4e, 0x78, 0x47, 0x4e, 0x79, +0x2f, 0x49, 0x4b, 0x50, 0x75, 0x67, 0x6b, 0x6e, 0x6e, 0x56, 0x63, 0x67, 0x4d, 0x53, 0x48, 0x55, +0x49, 0x73, 0x5a, 0x62, 0x68, 0x55, 0x68, 0x41, 0x38, 0x54, 0x72, 0x4e, 0x4c, 0x2f, 0x78, 0x36, +0x6b, 0x69, 0x39, 0x32, 0x52, 0x70, 0x35, 0x6c, 0x2f, 0x5a, 0x32, 0x41, 0x52, 0x4f, 0x35, 0x66, +0x31, 0x52, 0x44, 0x77, 0x35, 0x76, 0x61, 0x51, 0x5a, 0x69, 0x39, 0x54, 0x71, 0x44, 0x52, 0x55, +0x56, 0x62, 0x72, 0x38, 0x56, 0x43, 0x72, 0x7a, 0x46, 0x6d, 0x66, 0x54, 0x6b, 0x79, 0x76, 0x77, +0x6c, 0x55, 0x74, 0x4d, 0x4d, 0x4b, 0x46, 0x62, 0x6e, 0x6f, 0x6c, 0x35, 0x2b, 0x2b, 0x33, 0x76, +0x51, 0x4e, 0x57, 0x6b, 0x55, 0x6f, 0x4e, 0x62, 0x51, 0x6d, 0x49, 0x41, 0x64, 0x4a, 0x2f, 0x53, +0x38, 0x6e, 0x68, 0x6b, 0x5a, 0x66, 0x2f, 0x63, 0x47, 0x2f, 0x65, 0x6f, 0x4f, 0x41, 0x38, 0x73, +0x38, 0x39, 0x34, 0x46, 0x48, 0x46, 0x6a, 0x48, 0x7a, 0x79, 0x53, 0x31, 0x6f, 0x7a, 0x66, 0x68, +0x36, 0x39, 0x38, 0x66, 0x73, 0x2f, 0x6a, 0x50, 0x68, 0x65, 0x52, 0x77, 0x34, 0x72, 0x65, 0x39, +0x2f, 0x30, 0x2b, 0x69, 0x2b, 0x56, 0x50, 0x65, 0x72, 0x75, 0x2f, 0x39, 0x53, 0x35, 0x73, 0x33, +0x44, 0x34, 0x7a, 0x4e, 0x59, 0x4c, 0x47, 0x4f, 0x49, 0x37, 0x6b, 0x74, 0x43, 0x42, 0x74, 0x76, +0x4e, 0x4c, 0x32, 0x37, 0x37, 0x64, 0x38, 0x49, 0x47, 0x62, 0x5a, 0x47, 0x46, 0x43, 0x62, 0x74, +0x2f, 0x2f, 0x63, 0x5a, 0x61, 0x69, 0x76, 0x50, 0x4a, 0x59, 0x74, 0x64, 0x74, 0x62, 0x70, 0x50, +0x73, 0x50, 0x36, 0x36, 0x47, 0x37, 0x6a, 0x33, 0x59, 0x7a, 0x68, 0x61, 0x39, 0x39, 0x6e, 0x6c, +0x76, 0x54, 0x5a, 0x72, 0x35, 0x31, 0x4f, 0x48, 0x66, 0x2f, 0x58, 0x76, 0x35, 0x58, 0x75, 0x58, +0x75, 0x51, 0x46, 0x6a, 0x70, 0x76, 0x54, 0x63, 0x5a, 0x30, 0x46, 0x6a, 0x45, 0x58, 0x77, 0x56, +0x55, 0x7a, 0x34, 0x4e, 0x31, 0x53, 0x57, 0x41, 0x4b, 0x4d, 0x41, 0x73, 0x72, 0x74, 0x4a, 0x6b, +0x33, 0x32, 0x39, 0x54, 0x31, 0x30, 0x74, 0x35, 0x6a, 0x32, 0x64, 0x64, 0x70, 0x59, 0x50, 0x61, +0x6d, 0x75, 0x72, 0x31, 0x37, 0x39, 0x34, 0x64, 0x37, 0x4c, 0x72, 0x41, 0x6e, 0x68, 0x37, 0x6e, +0x2f, 0x7a, 0x57, 0x53, 0x39, 0x33, 0x52, 0x52, 0x46, 0x63, 0x4d, 0x43, 0x77, 0x38, 0x58, 0x39, +0x6c, 0x77, 0x66, 0x76, 0x58, 0x5a, 0x7a, 0x7a, 0x6b, 0x46, 0x56, 0x67, 0x6d, 0x33, 0x39, 0x34, +0x45, 0x76, 0x54, 0x66, 0x34, 0x65, 0x4f, 0x59, 0x54, 0x35, 0x66, 0x39, 0x32, 0x4b, 0x48, 0x44, +0x74, 0x6c, 0x70, 0x39, 0x48, 0x75, 0x67, 0x44, 0x59, 0x66, 0x47, 0x5a, 0x4a, 0x4e, 0x32, 0x79, +0x38, 0x37, 0x49, 0x62, 0x78, 0x54, 0x6a, 0x66, 0x4a, 0x54, 0x49, 0x36, 0x6d, 0x2b, 0x39, 0x61, +0x62, 0x72, 0x6e, 0x52, 0x58, 0x68, 0x76, 0x43, 0x58, 0x42, 0x73, 0x36, 0x61, 0x31, 0x65, 0x50, +0x36, 0x71, 0x62, 0x4e, 0x57, 0x38, 0x4f, 0x72, 0x73, 0x6c, 0x65, 0x54, 0x32, 0x73, 0x55, 0x69, +0x78, 0x6f, 0x4c, 0x4d, 0x50, 0x2b, 0x77, 0x32, 0x59, 0x79, 0x30, 0x6d, 0x6a, 0x58, 0x72, 0x61, +0x4b, 0x59, 0x67, 0x4c, 0x51, 0x37, 0x57, 0x6a, 0x6a, 0x55, 0x33, 0x6c, 0x36, 0x45, 0x37, 0x53, +0x6c, 0x37, 0x56, 0x47, 0x64, 0x59, 0x56, 0x70, 0x6d, 0x79, 0x73, 0x47, 0x6d, 0x4f, 0x6e, 0x6a, +0x58, 0x65, 0x37, 0x42, 0x39, 0x6c, 0x2f, 0x48, 0x41, 0x71, 0x30, 0x35, 0x66, 0x68, 0x55, 0x39, +0x6d, 0x42, 0x57, 0x4b, 0x4e, 0x6c, 0x6b, 0x6d, 0x71, 0x39, 0x68, 0x6c, 0x6d, 0x42, 0x35, 0x54, +0x41, 0x37, 0x66, 0x6b, 0x67, 0x5a, 0x7a, 0x58, 0x31, 0x65, 0x50, 0x35, 0x4e, 0x77, 0x61, 0x68, +0x44, 0x33, 0x45, 0x53, 0x6d, 0x59, 0x70, 0x55, 0x66, 0x65, 0x4b, 0x41, 0x74, 0x41, 0x6b, 0x70, +0x32, 0x76, 0x71, 0x4c, 0x4b, 0x65, 0x4d, 0x62, 0x4d, 0x38, 0x38, 0x7a, 0x50, 0x4b, 0x43, 0x6c, +0x68, 0x68, 0x32, 0x63, 0x62, 0x73, 0x2b, 0x39, 0x4e, 0x39, 0x68, 0x63, 0x6a, 0x43, 0x47, 0x31, +0x34, 0x4c, 0x73, 0x6d, 0x43, 0x31, 0x61, 0x35, 0x64, 0x66, 0x43, 0x64, 0x76, 0x4a, 0x67, 0x64, +0x77, 0x30, 0x58, 0x32, 0x4e, 0x50, 0x44, 0x6e, 0x6f, 0x45, 0x33, 0x4a, 0x39, 0x7a, 0x58, 0x48, +0x66, 0x62, 0x38, 0x73, 0x4e, 0x4f, 0x37, 0x66, 0x79, 0x62, 0x6d, 0x73, 0x64, 0x48, 0x38, 0x34, +0x50, 0x38, 0x78, 0x6b, 0x36, 0x67, 0x41, 0x43, 0x32, 0x65, 0x67, 0x70, 0x2b, 0x50, 0x4a, 0x46, +0x51, 0x4b, 0x41, 0x32, 0x50, 0x39, 0x37, 0x78, 0x2f, 0x74, 0x37, 0x38, 0x33, 0x74, 0x31, 0x64, +0x6d, 0x74, 0x6e, 0x39, 0x47, 0x48, 0x2f, 0x51, 0x59, 0x53, 0x62, 0x76, 0x72, 0x68, 0x49, 0x4e, +0x53, 0x4d, 0x2b, 0x75, 0x68, 0x72, 0x50, 0x75, 0x70, 0x57, 0x61, 0x65, 0x7a, 0x4f, 0x42, 0x5a, +0x6a, 0x69, 0x46, 0x4c, 0x45, 0x42, 0x6b, 0x31, 0x4a, 0x35, 0x31, 0x55, 0x6b, 0x33, 0x56, 0x46, +0x31, 0x2b, 0x35, 0x46, 0x37, 0x2f, 0x74, 0x6d, 0x7a, 0x2f, 0x30, 0x39, 0x64, 0x31, 0x53, 0x74, +0x73, 0x76, 0x57, 0x37, 0x59, 0x73, 0x42, 0x37, 0x50, 0x58, 0x39, 0x34, 0x77, 0x46, 0x41, 0x59, +0x4f, 0x68, 0x6c, 0x64, 0x65, 0x78, 0x46, 0x51, 0x34, 0x35, 0x6c, 0x36, 0x6c, 0x30, 0x43, 0x61, +0x42, 0x31, 0x4e, 0x38, 0x6a, 0x74, 0x63, 0x62, 0x54, 0x77, 0x39, 0x45, 0x79, 0x31, 0x79, 0x56, +0x36, 0x4b, 0x66, 0x53, 0x47, 0x4e, 0x74, 0x52, 0x70, 0x5a, 0x32, 0x43, 0x57, 0x4c, 0x61, 0x50, +0x68, 0x74, 0x63, 0x55, 0x30, 0x64, 0x73, 0x43, 0x52, 0x50, 0x38, 0x47, 0x58, 0x61, 0x37, 0x73, +0x31, 0x57, 0x6d, 0x2f, 0x76, 0x6e, 0x67, 0x52, 0x71, 0x59, 0x4d, 0x36, 0x32, 0x30, 0x4c, 0x2b, +0x77, 0x4e, 0x79, 0x67, 0x77, 0x67, 0x4f, 0x39, 0x62, 0x5a, 0x35, 0x47, 0x53, 0x47, 0x4b, 0x58, +0x78, 0x52, 0x64, 0x41, 0x37, 0x46, 0x50, 0x69, 0x46, 0x46, 0x39, 0x44, 0x41, 0x6c, 0x4b, 0x73, +0x48, 0x57, 0x38, 0x46, 0x54, 0x49, 0x64, 0x72, 0x4d, 0x49, 0x70, 0x4b, 0x30, 0x7a, 0x6a, 0x41, +0x39, 0x5a, 0x4c, 0x70, 0x75, 0x66, 0x45, 0x69, 0x78, 0x64, 0x63, 0x2f, 0x66, 0x76, 0x67, 0x53, +0x67, 0x49, 0x65, 0x50, 0x2b, 0x49, 0x61, 0x56, 0x52, 0x43, 0x4f, 0x58, 0x46, 0x4f, 0x55, 0x77, +0x79, 0x37, 0x78, 0x74, 0x43, 0x65, 0x6d, 0x63, 0x35, 0x4b, 0x4f, 0x2b, 0x59, 0x4d, 0x57, 0x4f, +0x79, 0x4f, 0x76, 0x48, 0x6c, 0x70, 0x54, 0x48, 0x57, 0x64, 0x62, 0x53, 0x54, 0x57, 0x32, 0x54, +0x35, 0x35, 0x49, 0x4e, 0x6b, 0x50, 0x35, 0x4c, 0x35, 0x33, 0x7a, 0x4e, 0x6d, 0x36, 0x44, 0x72, +0x6f, 0x30, 0x4b, 0x43, 0x37, 0x55, 0x4b, 0x4b, 0x64, 0x31, 0x6e, 0x5a, 0x6f, 0x62, 0x34, 0x47, +0x4b, 0x75, 0x32, 0x36, 0x4f, 0x37, 0x6f, 0x38, 0x4f, 0x53, 0x7a, 0x7a, 0x62, 0x55, 0x43, 0x52, +0x61, 0x32, 0x6d, 0x49, 0x54, 0x55, 0x57, 0x45, 0x4a, 0x34, 0x59, 0x70, 0x4e, 0x53, 0x42, 0x59, +0x38, 0x2f, 0x42, 0x52, 0x30, 0x77, 0x4b, 0x54, 0x39, 0x48, 0x61, 0x75, 0x74, 0x74, 0x6c, 0x44, +0x65, 0x76, 0x74, 0x56, 0x39, 0x38, 0x54, 0x79, 0x66, 0x4c, 0x43, 0x69, 0x30, 0x6c, 0x70, 0x67, +0x72, 0x54, 0x69, 0x53, 0x71, 0x56, 0x71, 0x73, 0x45, 0x48, 0x65, 0x64, 0x50, 0x59, 0x38, 0x44, +0x4a, 0x4d, 0x4f, 0x57, 0x43, 0x47, 0x69, 0x74, 0x38, 0x7a, 0x6b, 0x78, 0x50, 0x77, 0x32, 0x46, +0x44, 0x72, 0x6a, 0x67, 0x69, 0x2b, 0x4b, 0x79, 0x53, 0x72, 0x6c, 0x79, 0x34, 0x4e, 0x4e, 0x78, +0x2b, 0x35, 0x6b, 0x38, 0x73, 0x77, 0x79, 0x71, 0x77, 0x79, 0x65, 0x6a, 0x33, 0x63, 0x45, 0x54, +0x58, 0x32, 0x4c, 0x6b, 0x38, 0x48, 0x42, 0x51, 0x45, 0x61, 0x65, 0x56, 0x58, 0x67, 0x48, 0x59, +0x44, 0x42, 0x38, 0x4e, 0x63, 0x2b, 0x36, 0x50, 0x78, 0x6a, 0x4c, 0x5a, 0x41, 0x47, 0x68, 0x52, +0x6f, 0x69, 0x57, 0x63, 0x6b, 0x4d, 0x65, 0x31, 0x59, 0x63, 0x58, 0x55, 0x59, 0x49, 0x62, 0x47, +0x52, 0x6f, 0x6f, 0x35, 0x50, 0x70, 0x6e, 0x48, 0x6a, 0x56, 0x38, 0x55, 0x38, 0x2f, 0x4d, 0x44, +0x4f, 0x6e, 0x48, 0x56, 0x31, 0x4e, 0x57, 0x4c, 0x6c, 0x49, 0x58, 0x51, 0x74, 0x58, 0x63, 0x36, +0x47, 0x59, 0x55, 0x50, 0x4a, 0x4b, 0x79, 0x75, 0x69, 0x62, 0x6e, 0x6f, 0x6a, 0x56, 0x77, 0x38, +0x6f, 0x70, 0x62, 0x61, 0x36, 0x6b, 0x46, 0x58, 0x4e, 0x71, 0x31, 0x67, 0x61, 0x2f, 0x49, 0x66, +0x79, 0x77, 0x6a, 0x76, 0x5a, 0x32, 0x43, 0x6f, 0x59, 0x58, 0x72, 0x59, 0x76, 0x61, 0x78, 0x6f, +0x37, 0x34, 0x65, 0x6a, 0x48, 0x66, 0x78, 0x75, 0x72, 0x64, 0x50, 0x66, 0x32, 0x52, 0x31, 0x74, +0x75, 0x51, 0x65, 0x32, 0x67, 0x31, 0x37, 0x6f, 0x62, 0x6c, 0x4e, 0x70, 0x42, 0x65, 0x6f, 0x55, +0x53, 0x54, 0x48, 0x76, 0x51, 0x79, 0x73, 0x2b, 0x74, 0x56, 0x2b, 0x37, 0x75, 0x72, 0x72, 0x66, +0x78, 0x38, 0x61, 0x71, 0x72, 0x72, 0x67, 0x51, 0x38, 0x4a, 0x6c, 0x2b, 0x33, 0x56, 0x30, 0x5a, +0x34, 0x30, 0x73, 0x6d, 0x79, 0x56, 0x6c, 0x47, 0x4b, 0x38, 0x68, 0x4e, 0x58, 0x50, 0x4e, 0x4e, +0x72, 0x2f, 0x2f, 0x66, 0x72, 0x31, 0x77, 0x2f, 0x54, 0x47, 0x78, 0x54, 0x2b, 0x78, 0x42, 0x4e, +0x37, 0x50, 0x76, 0x2b, 0x4d, 0x64, 0x2b, 0x42, 0x33, 0x68, 0x32, 0x4b, 0x71, 0x79, 0x74, 0x43, +0x50, 0x50, 0x49, 0x6b, 0x2b, 0x2b, 0x54, 0x69, 0x4d, 0x4d, 0x51, 0x52, 0x64, 0x6d, 0x76, 0x58, +0x50, 0x48, 0x59, 0x45, 0x66, 0x42, 0x42, 0x51, 0x64, 0x4f, 0x77, 0x2f, 0x69, 0x4d, 0x61, 0x52, +0x53, 0x36, 0x42, 0x64, 0x65, 0x52, 0x6c, 0x31, 0x34, 0x4c, 0x71, 0x70, 0x2b, 0x43, 0x4f, 0x71, +0x4a, 0x52, 0x7a, 0x6e, 0x6d, 0x76, 0x50, 0x45, 0x38, 0x39, 0x63, 0x77, 0x6b, 0x76, 0x74, 0x67, +0x53, 0x76, 0x6d, 0x7a, 0x52, 0x76, 0x4e, 0x32, 0x71, 0x61, 0x5a, 0x50, 0x57, 0x52, 0x35, 0x45, +0x46, 0x4a, 0x52, 0x65, 0x43, 0x41, 0x6c, 0x39, 0x79, 0x57, 0x42, 0x2f, 0x42, 0x2b, 0x45, 0x70, +0x4a, 0x6f, 0x6c, 0x55, 0x77, 0x62, 0x4d, 0x79, 0x30, 0x54, 0x55, 0x4f, 0x42, 0x4c, 0x7a, 0x76, +0x36, 0x44, 0x75, 0x52, 0x41, 0x67, 0x31, 0x78, 0x6f, 0x6b, 0x49, 0x4d, 0x30, 0x39, 0x31, 0x34, +0x78, 0x63, 0x5a, 0x4e, 0x51, 0x59, 0x47, 0x4e, 0x67, 0x62, 0x58, 0x4e, 0x67, 0x68, 0x54, 0x61, +0x44, 0x56, 0x38, 0x38, 0x71, 0x75, 0x33, 0x62, 0x68, 0x4e, 0x2b, 0x32, 0x63, 0x46, 0x50, 0x61, +0x38, 0x62, 0x33, 0x55, 0x4f, 0x36, 0x66, 0x6e, 0x64, 0x49, 0x44, 0x4b, 0x67, 0x76, 0x4d, 0x5a, +0x42, 0x65, 0x64, 0x6b, 0x4d, 0x6c, 0x44, 0x65, 0x6e, 0x47, 0x78, 0x51, 0x35, 0x63, 0x30, 0x74, +0x4a, 0x52, 0x58, 0x74, 0x58, 0x41, 0x4f, 0x30, 0x47, 0x6a, 0x41, 0x64, 0x64, 0x69, 0x71, 0x52, +0x49, 0x67, 0x57, 0x6d, 0x33, 0x43, 0x69, 0x36, 0x37, 0x32, 0x4e, 0x67, 0x42, 0x48, 0x61, 0x6b, +0x53, 0x69, 0x46, 0x6b, 0x6c, 0x6b, 0x47, 0x74, 0x57, 0x4f, 0x78, 0x68, 0x70, 0x78, 0x6e, 0x70, +0x62, 0x75, 0x72, 0x52, 0x4c, 0x45, 0x51, 0x34, 0x38, 0x61, 0x56, 0x36, 0x44, 0x57, 0x4a, 0x33, +0x6c, 0x58, 0x48, 0x65, 0x42, 0x56, 0x4d, 0x74, 0x71, 0x71, 0x32, 0x33, 0x46, 0x6c, 0x77, 0x37, +0x5a, 0x51, 0x55, 0x6c, 0x4f, 0x53, 0x62, 0x59, 0x54, 0x72, 0x4b, 0x73, 0x64, 0x30, 0x37, 0x54, +0x41, 0x4f, 0x68, 0x57, 0x46, 0x77, 0x4b, 0x75, 0x30, 0x7a, 0x37, 0x2f, 0x38, 0x4b, 0x61, 0x69, +0x70, 0x36, 0x52, 0x33, 0x4e, 0x74, 0x31, 0x6c, 0x48, 0x6f, 0x75, 0x64, 0x78, 0x37, 0x41, 0x34, +0x61, 0x66, 0x2b, 0x38, 0x53, 0x56, 0x48, 0x73, 0x37, 0x47, 0x6f, 0x67, 0x42, 0x48, 0x56, 0x75, +0x50, 0x52, 0x49, 0x37, 0x37, 0x48, 0x62, 0x6e, 0x46, 0x72, 0x63, 0x6a, 0x76, 0x58, 0x38, 0x42, +0x37, 0x76, 0x52, 0x4f, 0x4e, 0x52, 0x37, 0x4a, 0x50, 0x4b, 0x66, 0x48, 0x32, 0x64, 0x6a, 0x75, +0x4c, 0x75, 0x49, 0x48, 0x41, 0x4b, 0x79, 0x6b, 0x42, 0x32, 0x6d, 0x33, 0x2f, 0x69, 0x31, 0x56, +0x67, 0x62, 0x4c, 0x61, 0x63, 0x4d, 0x51, 0x35, 0x4e, 0x70, 0x31, 0x30, 0x55, 0x4a, 0x44, 0x6f, +0x47, 0x62, 0x68, 0x64, 0x34, 0x65, 0x52, 0x5a, 0x4b, 0x2b, 0x33, 0x44, 0x74, 0x5a, 0x38, 0x52, +0x2b, 0x71, 0x43, 0x63, 0x33, 0x30, 0x55, 0x36, 0x38, 0x73, 0x35, 0x4f, 0x43, 0x56, 0x49, 0x43, +0x33, 0x59, 0x51, 0x55, 0x70, 0x5a, 0x63, 0x68, 0x64, 0x56, 0x73, 0x36, 0x4c, 0x33, 0x78, 0x51, +0x35, 0x35, 0x56, 0x48, 0x55, 0x37, 0x37, 0x57, 0x53, 0x68, 0x58, 0x49, 0x70, 0x4d, 0x75, 0x57, +0x78, 0x74, 0x6d, 0x73, 0x2b, 0x6b, 0x34, 0x35, 0x65, 0x7a, 0x54, 0x47, 0x62, 0x6b, 0x4c, 0x39, +0x66, 0x44, 0x55, 0x57, 0x50, 0x67, 0x34, 0x66, 0x48, 0x79, 0x73, 0x35, 0x56, 0x61, 0x4b, 0x4f, +0x79, 0x46, 0x46, 0x34, 0x61, 0x52, 0x61, 0x41, 0x45, 0x55, 0x6e, 0x55, 0x50, 0x42, 0x77, 0x59, +0x30, 0x6c, 0x41, 0x78, 0x49, 0x6d, 0x36, 0x30, 0x59, 0x56, 0x71, 0x39, 0x50, 0x75, 0x6e, 0x4a, +0x6c, 0x49, 0x4a, 0x63, 0x76, 0x42, 0x77, 0x77, 0x72, 0x6d, 0x6a, 0x6f, 0x7a, 0x69, 0x6f, 0x6f, +0x71, 0x56, 0x32, 0x7a, 0x55, 0x45, 0x70, 0x50, 0x55, 0x56, 0x52, 0x5a, 0x59, 0x2b, 0x65, 0x32, +0x6c, 0x2f, 0x7a, 0x66, 0x5a, 0x66, 0x77, 0x73, 0x57, 0x39, 0x48, 0x7a, 0x2b, 0x6f, 0x59, 0x4d, +0x77, 0x43, 0x2b, 0x61, 0x69, 0x4c, 0x37, 0x6b, 0x43, 0x66, 0x66, 0x6f, 0x70, 0x36, 0x48, 0x2b, +0x2f, 0x67, 0x4a, 0x6e, 0x36, 0x49, 0x69, 0x61, 0x65, 0x53, 0x2b, 0x76, 0x2f, 0x72, 0x53, 0x50, +0x65, 0x41, 0x51, 0x55, 0x6e, 0x35, 0x74, 0x75, 0x4b, 0x53, 0x79, 0x65, 0x63, 0x67, 0x70, 0x72, +0x78, 0x46, 0x6d, 0x72, 0x69, 0x47, 0x61, 0x6a, 0x4a, 0x6c, 0x32, 0x4f, 0x4d, 0x34, 0x63, 0x56, +0x50, 0x59, 0x63, 0x2b, 0x70, 0x68, 0x76, 0x33, 0x47, 0x72, 0x6d, 0x4b, 0x6e, 0x4c, 0x52, 0x55, +0x44, 0x66, 0x4d, 0x58, 0x6a, 0x61, 0x77, 0x54, 0x66, 0x74, 0x44, 0x73, 0x6f, 0x75, 0x62, 0x59, +0x73, 0x32, 0x74, 0x73, 0x57, 0x43, 0x73, 0x36, 0x74, 0x43, 0x75, 0x68, 0x66, 0x45, 0x6a, 0x44, +0x7a, 0x43, 0x38, 0x45, 0x7a, 0x37, 0x7a, 0x61, 0x77, 0x50, 0x68, 0x4c, 0x66, 0x62, 0x6c, 0x42, +0x59, 0x6f, 0x52, 0x53, 0x33, 0x50, 0x58, 0x55, 0x75, 0x35, 0x75, 0x39, 0x2f, 0x78, 0x7a, 0x78, +0x36, 0x4d, 0x65, 0x62, 0x32, 0x32, 0x78, 0x41, 0x69, 0x52, 0x61, 0x77, 0x33, 0x4b, 0x4c, 0x44, +0x47, 0x51, 0x51, 0x35, 0x78, 0x78, 0x42, 0x51, 0x5a, 0x4b, 0x4c, 0x78, 0x65, 0x48, 0x42, 0x4c, +0x68, 0x41, 0x43, 0x43, 0x6c, 0x69, 0x51, 0x61, 0x41, 0x45, 0x4d, 0x71, 0x5a, 0x71, 0x66, 0x79, +0x5a, 0x55, 0x47, 0x51, 0x74, 0x41, 0x71, 0x66, 0x38, 0x49, 0x6c, 0x31, 0x6e, 0x58, 0x6f, 0x69, +0x49, 0x55, 0x71, 0x72, 0x37, 0x4a, 0x70, 0x51, 0x6d, 0x32, 0x65, 0x57, 0x7a, 0x55, 0x31, 0x57, +0x4b, 0x48, 0x4d, 0x2f, 0x77, 0x36, 0x63, 0x39, 0x78, 0x67, 0x69, 0x41, 0x41, 0x62, 0x55, 0x76, +0x31, 0x64, 0x4b, 0x55, 0x67, 0x6d, 0x59, 0x4a, 0x55, 0x41, 0x4c, 0x6b, 0x4b, 0x6a, 0x4d, 0x4f, +0x68, 0x52, 0x71, 0x58, 0x41, 0x70, 0x59, 0x51, 0x51, 0x75, 0x43, 0x4d, 0x64, 0x54, 0x35, 0x34, +0x49, 0x48, 0x43, 0x65, 0x37, 0x2f, 0x64, 0x78, 0x7a, 0x59, 0x55, 0x67, 0x30, 0x4c, 0x6f, 0x6c, +0x46, 0x52, 0x51, 0x37, 0x49, 0x54, 0x53, 0x71, 0x75, 0x64, 0x45, 0x51, 0x54, 0x78, 0x6d, 0x49, +0x42, 0x77, 0x71, 0x58, 0x54, 0x70, 0x70, 0x54, 0x2f, 0x72, 0x6d, 0x65, 0x73, 0x45, 0x2b, 0x2b, +0x69, 0x34, 0x33, 0x73, 0x42, 0x41, 0x6f, 0x45, 0x4c, 0x66, 0x61, 0x5a, 0x6e, 0x66, 0x51, 0x32, +0x59, 0x31, 0x6f, 0x32, 0x6b, 0x2b, 0x74, 0x61, 0x77, 0x77, 0x63, 0x38, 0x68, 0x66, 0x76, 0x46, +0x74, 0x44, 0x48, 0x6a, 0x39, 0x58, 0x46, 0x59, 0x4f, 0x33, 0x35, 0x71, 0x4e, 0x5a, 0x30, 0x36, +0x6b, 0x34, 0x6f, 0x59, 0x62, 0x38, 0x46, 0x74, 0x62, 0x73, 0x35, 0x59, 0x33, 0x75, 0x6d, 0x5a, +0x48, 0x76, 0x49, 0x4b, 0x52, 0x45, 0x4b, 0x39, 0x78, 0x65, 0x41, 0x45, 0x46, 0x52, 0x72, 0x46, +0x77, 0x58, 0x51, 0x58, 0x66, 0x4c, 0x42, 0x79, 0x41, 0x30, 0x6f, 0x71, 0x78, 0x67, 0x78, 0x59, +0x77, 0x72, 0x47, 0x71, 0x56, 0x6e, 0x66, 0x6d, 0x31, 0x52, 0x42, 0x75, 0x4a, 0x46, 0x36, 0x39, +0x47, 0x31, 0x30, 0x33, 0x6e, 0x74, 0x51, 0x31, 0x56, 0x48, 0x44, 0x70, 0x73, 0x4b, 0x79, 0x69, +0x4d, 0x6f, 0x78, 0x63, 0x75, 0x52, 0x69, 0x78, 0x64, 0x54, 0x73, 0x48, 0x6f, 0x30, 0x63, 0x69, +0x55, 0x52, 0x30, 0x76, 0x6a, 0x65, 0x76, 0x62, 0x64, 0x75, 0x78, 0x38, 0x4e, 0x39, 0x53, 0x56, +0x4d, 0x58, 0x7a, 0x6f, 0x4a, 0x59, 0x52, 0x4b, 0x41, 0x4a, 0x45, 0x34, 0x65, 0x66, 0x66, 0x49, +0x71, 0x65, 0x66, 0x4c, 0x70, 0x45, 0x32, 0x44, 0x4b, 0x59, 0x73, 0x78, 0x57, 0x49, 0x36, 0x47, +0x36, 0x72, 0x77, 0x33, 0x52, 0x79, 0x67, 0x41, 0x69, 0x49, 0x4a, 0x68, 0x4a, 0x67, 0x36, 0x6d, +0x55, 0x73, 0x70, 0x61, 0x58, 0x31, 0x70, 0x59, 0x57, 0x75, 0x37, 0x6f, 0x61, 0x50, 0x58, 0x30, +0x36, 0x30, 0x34, 0x2b, 0x66, 0x54, 0x6b, 0x56, 0x75, 0x42, 0x57, 0x57, 0x35, 0x5a, 0x61, 0x7a, +0x73, 0x58, 0x45, 0x6c, 0x64, 0x59, 0x52, 0x33, 0x4c, 0x32, 0x70, 0x66, 0x52, 0x76, 0x36, 0x69, +0x42, 0x4a, 0x65, 0x31, 0x4c, 0x36, 0x46, 0x39, 0x59, 0x7a, 0x39, 0x4c, 0x4f, 0x35, 0x54, 0x51, +0x55, 0x31, 0x4c, 0x4f, 0x34, 0x62, 0x54, 0x45, 0x44, 0x69, 0x67, 0x61, 0x77, 0x59, 0x4f, 0x4d, +0x43, 0x52, 0x70, 0x61, 0x50, 0x70, 0x4f, 0x4f, 0x59, 0x44, 0x6a, 0x36, 0x38, 0x54, 0x61, 0x50, +0x44, 0x35, 0x4a, 0x6b, 0x77, 0x67, 0x69, 0x46, 0x74, 0x48, 0x77, 0x61, 0x68, 0x2f, 0x43, 0x6f, +0x56, 0x46, 0x52, 0x73, 0x4e, 0x70, 0x44, 0x58, 0x44, 0x62, 0x57, 0x6d, 0x7a, 0x6f, 0x4e, 0x66, +0x2b, 0x33, 0x2b, 0x54, 0x67, 0x6e, 0x51, 0x45, 0x46, 0x44, 0x76, 0x58, 0x48, 0x61, 0x4d, 0x76, +0x57, 0x72, 0x47, 0x2b, 0x39, 0x45, 0x66, 0x32, 0x48, 0x50, 0x36, 0x41, 0x50, 0x50, 0x68, 0x78, +0x64, 0x56, 0x6f, 0x33, 0x33, 0x36, 0x6d, 0x76, 0x6b, 0x48, 0x48, 0x49, 0x63, 0x70, 0x69, 0x75, +0x46, 0x2b, 0x58, 0x67, 0x32, 0x2b, 0x70, 0x67, 0x6a, 0x55, 0x58, 0x6c, 0x35, 0x71, 0x4b, 0x6d, +0x76, 0x6f, 0x6b, 0x61, 0x50, 0x73, 0x6e, 0x77, 0x51, 0x54, 0x67, 0x35, 0x57, 0x4e, 0x78, 0x74, +0x75, 0x65, 0x30, 0x4a, 0x78, 0x30, 0x47, 0x36, 0x4b, 0x49, 0x38, 0x63, 0x4c, 0x72, 0x68, 0x69, +0x67, 0x65, 0x48, 0x6c, 0x4e, 0x77, 0x44, 0x50, 0x72, 0x4a, 0x4a, 0x34, 0x57, 0x6e, 0x46, 0x77, +0x56, 0x63, 0x47, 0x7a, 0x66, 0x41, 0x4a, 0x30, 0x51, 0x50, 0x50, 0x78, 0x45, 0x77, 0x43, 0x50, +0x2f, 0x45, 0x66, 0x54, 0x74, 0x5a, 0x35, 0x38, 0x7a, 0x72, 0x70, 0x57, 0x4b, 0x76, 0x4c, 0x58, +0x57, 0x51, 0x34, 0x77, 0x64, 0x61, 0x65, 0x66, 0x50, 0x78, 0x31, 0x78, 0x30, 0x45, 0x65, 0x62, +0x32, 0x32, 0x7a, 0x48, 0x6e, 0x6e, 0x49, 0x4e, 0x2b, 0x39, 0x31, 0x33, 0x38, 0x65, 0x44, 0x77, +0x74, 0x67, 0x4a, 0x34, 0x48, 0x62, 0x57, 0x32, 0x6f, 0x33, 0x5a, 0x59, 0x36, 0x5a, 0x46, 0x65, +0x6d, 0x70, 0x7a, 0x46, 0x62, 0x2b, 0x63, 0x4e, 0x64, 0x75, 0x70, 0x43, 0x45, 0x63, 0x43, 0x53, +0x63, 0x6f, 0x4e, 0x6d, 0x75, 0x74, 0x2f, 0x74, 0x76, 0x4c, 0x70, 0x36, 0x66, 0x4d, 0x51, 0x50, +0x75, 0x31, 0x39, 0x62, 0x47, 0x36, 0x74, 0x57, 0x72, 0x65, 0x77, 0x77, 0x41, 0x47, 0x30, 0x55, +0x63, 0x35, 0x57, 0x75, 0x4f, 0x79, 0x66, 0x75, 0x43, 0x49, 0x6a, 0x2f, 0x46, 0x52, 0x2f, 0x45, +0x47, 0x4e, 0x73, 0x68, 0x63, 0x51, 0x45, 0x58, 0x6d, 0x74, 0x62, 0x5a, 0x63, 0x49, 0x48, 0x61, +0x35, 0x6d, 0x4f, 0x68, 0x45, 0x64, 0x62, 0x52, 0x5a, 0x73, 0x7a, 0x4f, 0x61, 0x36, 0x57, 0x56, +0x45, 0x67, 0x42, 0x6b, 0x68, 0x2b, 0x45, 0x52, 0x59, 0x59, 0x31, 0x33, 0x67, 0x46, 0x5a, 0x64, +0x45, 0x41, 0x35, 0x42, 0x43, 0x5a, 0x57, 0x54, 0x74, 0x79, 0x55, 0x30, 0x38, 0x73, 0x37, 0x62, +0x74, 0x36, 0x6d, 0x5a, 0x51, 0x6e, 0x4b, 0x44, 0x30, 0x42, 0x71, 0x56, 0x2b, 0x2f, 0x48, 0x58, +0x44, 0x54, 0x79, 0x73, 0x4d, 0x66, 0x58, 0x49, 0x4d, 0x74, 0x62, 0x37, 0x68, 0x67, 0x6e, 0x73, +0x4d, 0x77, 0x2f, 0x73, 0x62, 0x7a, 0x70, 0x36, 0x51, 0x50, 0x51, 0x42, 0x49, 0x46, 0x30, 0x73, +0x4f, 0x6c, 0x56, 0x38, 0x43, 0x75, 0x61, 0x74, 0x57, 0x45, 0x62, 0x2f, 0x6d, 0x43, 0x6e, 0x4b, +0x41, 0x39, 0x6a, 0x57, 0x4e, 0x4c, 0x4c, 0x31, 0x38, 0x41, 0x63, 0x6d, 0x69, 0x45, 0x69, 0x70, +0x66, 0x2b, 0x51, 0x2b, 0x30, 0x74, 0x55, 0x58, 0x4c, 0x59, 0x34, 0x57, 0x6c, 0x68, 0x74, 0x41, +0x6a, 0x76, 0x73, 0x44, 0x33, 0x76, 0x48, 0x53, 0x45, 0x77, 0x44, 0x34, 0x4a, 0x58, 0x38, 0x35, +0x61, 0x54, 0x43, 0x72, 0x56, 0x79, 0x65, 0x67, 0x52, 0x6c, 0x58, 0x79, 0x79, 0x63, 0x42, 0x42, +0x44, 0x74, 0x78, 0x6d, 0x53, 0x68, 0x53, 0x6e, 0x77, 0x50, 0x51, 0x2b, 0x35, 0x77, 0x39, 0x6d, +0x30, 0x4c, 0x6c, 0x35, 0x49, 0x55, 0x6d, 0x67, 0x2b, 0x2f, 0x6d, 0x49, 0x39, 0x51, 0x32, 0x53, +0x4b, 0x65, 0x48, 0x34, 0x31, 0x63, 0x31, 0x65, 0x55, 0x4d, 0x4b, 0x61, 0x6b, 0x68, 0x59, 0x31, +0x64, 0x69, 0x6d, 0x2b, 0x6d, 0x4c, 0x33, 0x56, 0x63, 0x68, 0x45, 0x66, 0x53, 0x62, 0x38, 0x38, +0x58, 0x32, 0x57, 0x4e, 0x4f, 0x46, 0x78, 0x39, 0x75, 0x47, 0x7a, 0x44, 0x37, 0x37, 0x57, 0x31, +0x35, 0x39, 0x4e, 0x35, 0x72, 0x4f, 0x56, 0x46, 0x39, 0x67, 0x65, 0x64, 0x35, 0x43, 0x44, 0x54, +0x76, 0x72, 0x48, 0x69, 0x48, 0x33, 0x39, 0x55, 0x66, 0x67, 0x4d, 0x52, 0x69, 0x4e, 0x72, 0x35, +0x65, 0x2b, 0x78, 0x57, 0x2b, 0x35, 0x7a, 0x47, 0x32, 0x59, 0x6e, 0x75, 0x53, 0x4a, 0x73, 0x41, +0x7a, 0x68, 0x71, 0x6d, 0x4c, 0x58, 0x75, 0x61, 0x59, 0x77, 0x63, 0x63, 0x51, 0x38, 0x7a, 0x77, +0x34, 0x36, 0x79, 0x77, 0x4f, 0x71, 0x4b, 0x6d, 0x4a, 0x35, 0x47, 0x64, 0x6f, 0x36, 0x56, 0x41, +0x77, 0x4d, 0x4b, 0x78, 0x30, 0x47, 0x4b, 0x59, 0x72, 0x78, 0x66, 0x43, 0x76, 0x6c, 0x6d, 0x50, +0x30, 0x61, 0x72, 0x62, 0x61, 0x66, 0x57, 0x39, 0x4d, 0x66, 0x69, 0x34, 0x6a, 0x2b, 0x31, 0x69, +0x51, 0x31, 0x4b, 0x69, 0x79, 0x55, 0x58, 0x69, 0x65, 0x78, 0x2f, 0x50, 0x37, 0x50, 0x55, 0x2f, +0x4e, 0x38, 0x54, 0x57, 0x39, 0x79, 0x4c, 0x38, 0x64, 0x41, 0x4a, 0x36, 0x38, 0x66, 0x4c, 0x66, +0x4e, 0x79, 0x74, 0x38, 0x2f, 0x7a, 0x68, 0x68, 0x4a, 0x76, 0x79, 0x65, 0x65, 0x2f, 0x5a, 0x58, +0x39, 0x33, 0x33, 0x4d, 0x41, 0x43, 0x50, 0x74, 0x66, 0x68, 0x34, 0x50, 0x41, 0x32, 0x47, 0x31, +0x51, 0x71, 0x78, 0x61, 0x69, 0x7a, 0x2f, 0x30, 0x4c, 0x2b, 0x72, 0x6a, 0x6a, 0x71, 0x44, 0x37, +0x38, 0x55, 0x4a, 0x52, 0x66, 0x68, 0x4c, 0x37, 0x39, 0x4a, 0x4f, 0x51, 0x52, 0x68, 0x36, 0x4e, +0x75, 0x76, 0x34, 0x6d, 0x77, 0x72, 0x71, 0x44, 0x4f, 0x73, 0x44, 0x53, 0x55, 0x55, 0x69, 0x52, +0x54, 0x6b, 0x68, 0x66, 0x66, 0x6b, 0x63, 0x7a, 0x38, 0x58, 0x6e, 0x4c, 0x53, 0x49, 0x59, 0x49, +0x6a, 0x42, 0x67, 0x75, 0x32, 0x79, 0x68, 0x45, 0x6f, 0x4a, 0x52, 0x68, 0x52, 0x47, 0x44, 0x44, +0x76, 0x2b, 0x34, 0x43, 0x37, 0x6e, 0x68, 0x5a, 0x38, 0x50, 0x63, 0x38, 0x57, 0x4b, 0x36, 0x31, +0x77, 0x39, 0x34, 0x39, 0x6e, 0x43, 0x6c, 0x2b, 0x57, 0x36, 0x66, 0x4b, 0x58, 0x76, 0x32, 0x44, +0x75, 0x75, 0x41, 0x4e, 0x7a, 0x7a, 0x6a, 0x6d, 0x59, 0x4b, 0x56, 0x4f, 0x36, 0x68, 0x5a, 0x50, +0x53, 0x55, 0x4d, 0x4b, 0x69, 0x6a, 0x6a, 0x58, 0x6b, 0x79, 0x57, 0x6f, 0x4b, 0x52, 0x44, 0x4a, +0x69, 0x62, 0x77, 0x6c, 0x44, 0x44, 0x30, 0x70, 0x71, 0x34, 0x6b, 0x4b, 0x54, 0x45, 0x31, 0x6f, +0x41, 0x51, 0x72, 0x73, 0x77, 0x6b, 0x36, 0x5a, 0x51, 0x46, 0x41, 0x4a, 0x4c, 0x32, 0x65, 0x54, +0x39, 0x66, 0x32, 0x47, 0x6e, 0x57, 0x7a, 0x5a, 0x68, 0x35, 0x74, 0x5a, 0x6c, 0x38, 0x74, 0x69, +0x79, 0x38, 0x6a, 0x73, 0x53, 0x66, 0x68, 0x33, 0x74, 0x4a, 0x6f, 0x63, 0x78, 0x46, 0x58, 0x50, +0x52, 0x78, 0x4c, 0x75, 0x35, 0x4f, 0x2b, 0x31, 0x57, 0x64, 0x76, 0x36, 0x66, 0x79, 0x64, 0x39, +0x6a, 0x48, 0x47, 0x72, 0x6a, 0x52, 0x6a, 0x76, 0x4c, 0x75, 0x4c, 0x4a, 0x68, 0x78, 0x71, 0x31, +0x44, 0x6a, 0x62, 0x5a, 0x48, 0x6e, 0x51, 0x46, 0x4e, 0x31, 0x6b, 0x6f, 0x52, 0x4b, 0x79, 0x75, +0x6e, 0x5a, 0x76, 0x5a, 0x4d, 0x6b, 0x4f, 0x75, 0x52, 0x72, 0x6c, 0x4a, 0x52, 0x57, 0x46, 0x68, +0x7a, 0x73, 0x78, 0x61, 0x41, 0x43, 0x62, 0x45, 0x4d, 0x4d, 0x73, 0x74, 0x35, 0x6d, 0x76, 0x6e, +0x2b, 0x45, 0x33, 0x59, 0x33, 0x33, 0x50, 0x69, 0x30, 0x34, 0x62, 0x77, 0x54, 0x44, 0x45, 0x46, +0x67, 0x2b, 0x50, 0x7a, 0x2f, 0x73, 0x58, 0x62, 0x65, 0x59, 0x56, 0x5a, 0x56, 0x31, 0x39, 0x2f, +0x2f, 0x6e, 0x48, 0x76, 0x76, 0x39, 0x46, 0x34, 0x59, 0x6d, 0x49, 0x47, 0x68, 0x44, 0x45, 0x67, +0x54, 0x46, 0x42, 0x47, 0x77, 0x6f, 0x49, 0x6b, 0x4e, 0x57, 0x39, 0x54, 0x59, 0x59, 0x6b, 0x2f, +0x41, 0x46, 0x6f, 0x32, 0x78, 0x67, 0x43, 0x55, 0x57, 0x59, 0x75, 0x38, 0x6c, 0x6c, 0x6d, 0x67, +0x73, 0x69, 0x56, 0x46, 0x73, 0x73, 0x55, 0x57, 0x4e, 0x71, 0x4d, 0x47, 0x43, 0x67, 0x4b, 0x49, +0x6f, 0x4b, 0x4e, 0x68, 0x51, 0x65, 0x6d, 0x65, 0x47, 0x4e, 0x73, 0x44, 0x30, 0x75, 0x66, 0x66, +0x73, 0x39, 0x76, 0x36, 0x78, 0x39, 0x37, 0x6c, 0x74, 0x37, 0x71, 0x44, 0x2b, 0x38, 0x70, 0x37, +0x6e, 0x75, 0x64, 0x7a, 0x43, 0x4f, 0x58, 0x50, 0x32, 0x32, 0x58, 0x75, 0x76, 0x74, 0x64, 0x64, +0x65, 0x36, 0x37, 0x75, 0x2b, 0x36, 0x30, 0x6e, 0x44, 0x57, 0x59, 0x64, 0x6d, 0x66, 0x76, 0x37, +0x6b, 0x76, 0x58, 0x2f, 0x38, 0x56, 0x51, 0x37, 0x79, 0x67, 0x65, 0x74, 0x52, 0x72, 0x2f, 0x30, +0x48, 0x37, 0x78, 0x64, 0x6a, 0x79, 0x46, 0x37, 0x31, 0x43, 0x74, 0x37, 0x63, 0x54, 0x37, 0x6f, +0x34, 0x42, 0x55, 0x50, 0x42, 0x2f, 0x56, 0x33, 0x53, 0x56, 0x4c, 0x43, 0x69, 0x67, 0x4b, 0x47, +0x39, 0x50, 0x63, 0x61, 0x51, 0x33, 0x76, 0x6d, 0x38, 0x50, 0x33, 0x73, 0x46, 0x4f, 0x65, 0x57, +0x57, 0x55, 0x64, 0x67, 0x45, 0x46, 0x4e, 0x58, 0x42, 0x41, 0x71, 0x41, 0x31, 0x66, 0x5a, 0x70, +0x57, 0x73, 0x73, 0x50, 0x55, 0x4d, 0x58, 0x52, 0x73, 0x46, 0x65, 0x77, 0x6f, 0x5a, 0x74, 0x32, +0x33, 0x36, 0x36, 0x6b, 0x6f, 0x79, 0x55, 0x4c, 0x57, 0x44, 0x43, 0x43, 0x2f, 0x73, 0x49, 0x4d, +0x4a, 0x68, 0x31, 0x62, 0x54, 0x72, 0x30, 0x38, 0x52, 0x62, 0x36, 0x2b, 0x35, 0x69, 0x6c, 0x48, +0x46, 0x6c, 0x32, 0x42, 0x69, 0x74, 0x7a, 0x4b, 0x51, 0x53, 0x32, 0x6b, 0x35, 0x38, 0x45, 0x32, +0x65, 0x47, 0x4a, 0x55, 0x6f, 0x61, 0x2f, 0x62, 0x2b, 0x2b, 0x6e, 0x64, 0x5a, 0x32, 0x72, 0x53, +0x4d, 0x74, 0x6c, 0x67, 0x4c, 0x56, 0x66, 0x6d, 0x39, 0x71, 0x63, 0x6f, 0x74, 0x35, 0x2f, 0x50, +0x4e, 0x6e, 0x78, 0x45, 0x4a, 0x68, 0x63, 0x6e, 0x78, 0x63, 0x6d, 0x6d, 0x4e, 0x74, 0x66, 0x4c, +0x74, 0x39, 0x6d, 0x39, 0x5a, 0x32, 0x62, 0x49, 0x43, 0x6f, 0x77, 0x32, 0x6e, 0x44, 0x7a, 0x71, +0x74, 0x69, 0x2f, 0x4a, 0x4d, 0x6d, 0x54, 0x38, 0x76, 0x2f, 0x51, 0x75, 0x54, 0x6b, 0x34, 0x50, +0x70, 0x31, 0x51, 0x76, 0x7a, 0x37, 0x44, 0x54, 0x4d, 0x2b, 0x65, 0x64, 0x6e, 0x37, 0x4c, 0x2f, +0x56, 0x34, 0x54, 0x43, 0x56, 0x31, 0x31, 0x79, 0x4e, 0x33, 0x4c, 0x41, 0x68, 0x34, 0x57, 0x4d, +0x53, 0x67, 0x73, 0x5a, 0x6a, 0x6a, 0x33, 0x47, 0x66, 0x6e, 0x65, 0x55, 0x70, 0x67, 0x6f, 0x6f, +0x38, 0x45, 0x69, 0x31, 0x39, 0x73, 0x76, 0x72, 0x31, 0x35, 0x39, 0x73, 0x50, 0x5a, 0x38, 0x47, +0x74, 0x2f, 0x50, 0x54, 0x78, 0x54, 0x31, 0x59, 0x41, 0x62, 0x76, 0x79, 0x54, 0x6e, 0x59, 0x52, +0x4b, 0x4b, 0x56, 0x76, 0x56, 0x36, 0x63, 0x46, 0x37, 0x55, 0x52, 0x56, 0x56, 0x38, 0x4d, 0x43, +0x64, 0x65, 0x49, 0x43, 0x38, 0x59, 0x44, 0x4c, 0x71, 0x32, 0x73, 0x6d, 0x4f, 0x2b, 0x31, 0x4c, +0x47, 0x7a, 0x77, 0x30, 0x4f, 0x47, 0x36, 0x71, 0x31, 0x58, 0x49, 0x58, 0x66, 0x72, 0x35, 0x52, +0x63, 0x2f, 0x7a, 0x66, 0x42, 0x50, 0x5a, 0x66, 0x36, 0x44, 0x4f, 0x35, 0x6e, 0x74, 0x32, 0x39, +0x72, 0x56, 0x76, 0x6c, 0x63, 0x63, 0x71, 0x65, 0x67, 0x73, 0x63, 0x6d, 0x50, 0x56, 0x79, 0x73, +0x4f, 0x48, 0x4d, 0x71, 0x52, 0x46, 0x49, 0x46, 0x7a, 0x55, 0x46, 0x35, 0x6a, 0x6a, 0x42, 0x58, +0x2b, 0x50, 0x2f, 0x77, 0x42, 0x38, 0x2f, 0x44, 0x44, 0x6d, 0x48, 0x50, 0x4f, 0x77, 0x58, 0x7a, +0x36, 0x61, 0x61, 0x6f, 0x47, 0x4e, 0x42, 0x5a, 0x6c, 0x31, 0x4c, 0x4c, 0x74, 0x42, 0x46, 0x68, +0x33, 0x47, 0x57, 0x62, 0x44, 0x57, 0x6d, 0x75, 0x2b, 0x2b, 0x59, 0x47, 0x6a, 0x7a, 0x45, 0x2f, +0x4b, 0x4a, 0x47, 0x79, 0x6d, 0x33, 0x50, 0x77, 0x41, 0x41, 0x43, 0x41, 0x41, 0x53, 0x55, 0x52, +0x42, 0x56, 0x45, 0x7a, 0x41, 0x59, 0x59, 0x50, 0x76, 0x6f, 0x62, 0x35, 0x31, 0x58, 0x4d, 0x73, +0x43, 0x34, 0x4c, 0x62, 0x4d, 0x39, 0x2f, 0x38, 0x78, 0x43, 0x38, 0x43, 0x59, 0x62, 0x68, 0x56, +0x41, 0x65, 0x61, 0x53, 0x54, 0x54, 0x6c, 0x6e, 0x46, 0x36, 0x79, 0x30, 0x44, 0x45, 0x47, 0x54, +0x54, 0x34, 0x73, 0x4f, 0x77, 0x38, 0x4d, 0x72, 0x4d, 0x35, 0x7a, 0x37, 0x34, 0x65, 0x47, 0x4c, +0x53, 0x2f, 0x49, 0x7a, 0x37, 0x68, 0x30, 0x49, 0x68, 0x65, 0x6b, 0x30, 0x34, 0x47, 0x70, 0x36, +0x73, 0x74, 0x63, 0x34, 0x57, 0x4c, 0x66, 0x47, 0x31, 0x4c, 0x62, 0x47, 0x64, 0x38, 0x52, 0x71, +0x74, 0x72, 0x66, 0x6e, 0x76, 0x74, 0x67, 0x42, 0x65, 0x51, 0x49, 0x6d, 0x56, 0x42, 0x75, 0x58, +0x45, 0x77, 0x4d, 0x75, 0x7a, 0x4c, 0x65, 0x6a, 0x6c, 0x50, 0x2f, 0x38, 0x78, 0x4c, 0x4e, 0x6c, +0x70, 0x59, 0x62, 0x4c, 0x2f, 0x2f, 0x4b, 0x2f, 0x68, 0x30, 0x74, 0x2b, 0x6b, 0x50, 0x6e, 0x39, +0x67, 0x41, 0x53, 0x51, 0x4c, 0x74, 0x67, 0x46, 0x4d, 0x67, 0x63, 0x65, 0x4f, 0x45, 0x65, 0x56, +0x6b, 0x48, 0x58, 0x59, 0x50, 0x50, 0x58, 0x61, 0x75, 0x70, 0x54, 0x32, 0x53, 0x63, 0x50, 0x77, +0x6c, 0x52, 0x77, 0x51, 0x53, 0x68, 0x33, 0x4d, 0x54, 0x65, 0x6f, 0x6e, 0x6e, 0x33, 0x32, 0x4e, +0x67, 0x47, 0x58, 0x4d, 0x57, 0x4e, 0x43, 0x43, 0x7a, 0x38, 0x39, 0x6c, 0x33, 0x55, 0x46, 0x41, +0x69, 0x4c, 0x66, 0x32, 0x6c, 0x2b, 0x64, 0x58, 0x4e, 0x57, 0x37, 0x6d, 0x37, 0x5a, 0x42, 0x50, +0x31, 0x6d, 0x31, 0x72, 0x6a, 0x56, 0x70, 0x2b, 0x63, 0x76, 0x79, 0x51, 0x4f, 0x53, 0x68, 0x48, +0x66, 0x4e, 0x4c, 0x6b, 0x4a, 0x65, 0x67, 0x71, 0x6e, 0x35, 0x64, 0x37, 0x4c, 0x67, 0x4b, 0x73, +0x55, 0x53, 0x36, 0x2f, 0x36, 0x4b, 0x33, 0x2f, 0x74, 0x63, 0x7a, 0x45, 0x33, 0x54, 0x72, 0x75, +0x42, 0x38, 0x79, 0x61, 0x39, 0x6a, 0x7a, 0x47, 0x47, 0x6f, 0x2f, 0x6f, 0x63, 0x69, 0x61, 0x39, +0x38, 0x39, 0x71, 0x2f, 0x65, 0x44, 0x36, 0x55, 0x55, 0x52, 0x64, 0x6d, 0x46, 0x6a, 0x4b, 0x6b, +0x61, 0x6a, 0x54, 0x48, 0x51, 0x76, 0x39, 0x69, 0x6d, 0x4f, 0x34, 0x2b, 0x75, 0x33, 0x4a, 0x4e, +0x2f, 0x72, 0x58, 0x69, 0x52, 0x55, 0x77, 0x66, 0x38, 0x78, 0x71, 0x49, 0x68, 0x30, 0x38, 0x46, +0x58, 0x79, 0x65, 0x4e, 0x33, 0x31, 0x6c, 0x6d, 0x59, 0x42, 0x78, 0x2f, 0x45, 0x72, 0x46, 0x31, +0x72, 0x46, 0x37, 0x4e, 0x75, 0x35, 0x6b, 0x2b, 0x64, 0x45, 0x36, 0x54, 0x6b, 0x36, 0x78, 0x75, +0x50, 0x2f, 0x52, 0x58, 0x6c, 0x62, 0x37, 0x37, 0x31, 0x6f, 0x2b, 0x4d, 0x2f, 0x61, 0x75, 0x66, +0x4f, 0x6e, 0x7a, 0x37, 0x2b, 0x61, 0x51, 0x72, 0x41, 0x45, 0x79, 0x4a, 0x46, 0x41, 0x53, 0x68, +0x6e, 0x42, 0x53, 0x69, 0x6c, 0x55, 0x46, 0x64, 0x50, 0x52, 0x66, 0x33, 0x7a, 0x57, 0x66, 0x52, +0x6c, 0x56, 0x36, 0x49, 0x38, 0x55, 0x41, 0x38, 0x2f, 0x68, 0x6d, 0x70, 0x72, 0x51, 0x74, 0x31, +0x34, 0x6e, 0x54, 0x30, 0x6e, 0x4b, 0x55, 0x6f, 0x45, 0x59, 0x45, 0x76, 0x65, 0x53, 0x58, 0x7a, +0x68, 0x55, 0x31, 0x73, 0x6c, 0x4f, 0x65, 0x63, 0x34, 0x51, 0x62, 0x39, 0x71, 0x6e, 0x35, 0x56, +0x4e, 0x41, 0x71, 0x56, 0x38, 0x42, 0x74, 0x55, 0x49, 0x62, 0x72, 0x2f, 0x59, 0x35, 0x39, 0x36, +0x6e, 0x42, 0x56, 0x38, 0x76, 0x38, 0x2b, 0x4f, 0x56, 0x69, 0x77, 0x45, 0x69, 0x34, 0x54, 0x50, +0x6d, 0x63, 0x65, 0x66, 0x45, 0x4f, 0x75, 0x71, 0x62, 0x59, 0x67, 0x36, 0x50, 0x62, 0x54, 0x32, +0x63, 0x72, 0x52, 0x76, 0x71, 0x2b, 0x5a, 0x66, 0x76, 0x59, 0x38, 0x34, 0x35, 0x68, 0x32, 0x4f, +0x4f, 0x76, 0x70, 0x48, 0x73, 0x70, 0x39, 0x5a, 0x62, 0x5a, 0x34, 0x6a, 0x7a, 0x37, 0x4e, 0x65, +0x57, 0x35, 0x66, 0x44, 0x53, 0x52, 0x58, 0x50, 0x59, 0x41, 0x68, 0x52, 0x71, 0x67, 0x5a, 0x4a, +0x32, 0x7a, 0x34, 0x35, 0x79, 0x65, 0x2b, 0x55, 0x67, 0x2f, 0x56, 0x56, 0x61, 0x34, 0x64, 0x65, +0x42, 0x45, 0x6c, 0x41, 0x57, 0x35, 0x42, 0x4c, 0x52, 0x6b, 0x67, 0x61, 0x67, 0x39, 0x73, 0x51, +0x77, 0x46, 0x35, 0x31, 0x33, 0x45, 0x57, 0x74, 0x32, 0x72, 0x48, 0x47, 0x49, 0x52, 0x49, 0x66, +0x68, 0x54, 0x6b, 0x71, 0x37, 0x54, 0x61, 0x2b, 0x56, 0x4c, 0x70, 0x56, 0x6b, 0x59, 0x48, 0x6b, +0x64, 0x43, 0x79, 0x63, 0x76, 0x59, 0x6c, 0x46, 0x61, 0x47, 0x46, 0x41, 0x70, 0x52, 0x5a, 0x59, +0x52, 0x72, 0x47, 0x2b, 0x73, 0x5a, 0x6e, 0x31, 0x59, 0x41, 0x52, 0x33, 0x51, 0x55, 0x73, 0x64, +0x2b, 0x2f, 0x65, 0x6c, 0x69, 0x2f, 0x68, 0x73, 0x33, 0x41, 0x4a, 0x37, 0x6e, 0x2f, 0x54, 0x7a, +0x72, 0x77, 0x35, 0x30, 0x6e, 0x48, 0x62, 0x32, 0x57, 0x43, 0x46, 0x43, 0x43, 0x72, 0x76, 0x33, +0x61, 0x36, 0x4d, 0x7a, 0x58, 0x43, 0x68, 0x2b, 0x44, 0x41, 0x43, 0x55, 0x74, 0x58, 0x7a, 0x77, +0x4a, 0x54, 0x72, 0x6e, 0x6b, 0x76, 0x33, 0x76, 0x65, 0x63, 0x66, 0x62, 0x37, 0x33, 0x55, 0x38, +0x61, 0x38, 0x72, 0x4d, 0x4d, 0x6a, 0x31, 0x39, 0x68, 0x45, 0x76, 0x76, 0x54, 0x70, 0x50, 0x4f, +0x73, 0x31, 0x37, 0x74, 0x72, 0x71, 0x45, 0x39, 0x74, 0x4d, 0x4a, 0x52, 0x66, 0x4d, 0x59, 0x75, +0x64, 0x74, 0x30, 0x36, 0x68, 0x36, 0x66, 0x4b, 0x72, 0x79, 0x66, 0x4b, 0x6a, 0x58, 0x59, 0x52, +0x66, 0x59, 0x37, 0x63, 0x41, 0x34, 0x54, 0x2b, 0x46, 0x75, 0x65, 0x76, 0x34, 0x75, 0x36, 0x68, +0x76, 0x72, 0x72, 0x63, 0x6d, 0x72, 0x45, 0x72, 0x55, 0x66, 0x70, 0x54, 0x6c, 0x31, 0x6c, 0x76, +0x2b, 0x31, 0x56, 0x72, 0x4a, 0x2f, 0x61, 0x76, 0x63, 0x43, 0x75, 0x64, 0x57, 0x75, 0x54, 0x34, +0x6c, 0x66, 0x58, 0x6a, 0x78, 0x35, 0x68, 0x65, 0x35, 0x34, 0x4c, 0x49, 0x50, 0x4f, 0x50, 0x62, +0x6f, 0x2f, 0x71, 0x78, 0x65, 0x32, 0x30, 0x78, 0x75, 0x62, 0x70, 0x6a, 0x2b, 0x74, 0x63, 0x56, +0x38, 0x73, 0x57, 0x67, 0x7a, 0x6c, 0x54, 0x33, 0x79, 0x36, 0x4e, 0x4d, 0x7a, 0x6e, 0x33, 0x6c, +0x66, 0x62, 0x4b, 0x4a, 0x2f, 0x33, 0x79, 0x4c, 0x57, 0x72, 0x57, 0x2b, 0x6c, 0x5a, 0x50, 0x63, +0x52, 0x72, 0x50, 0x6e, 0x54, 0x35, 0x77, 0x78, 0x36, 0x4b, 0x4a, 0x66, 0x66, 0x4e, 0x51, 0x78, +0x6c, 0x2f, 0x33, 0x33, 0x2b, 0x7a, 0x4f, 0x6a, 0x52, 0x6f, 0x35, 0x6b, 0x79, 0x5a, 0x51, 0x71, +0x4e, 0x32, 0x78, 0x72, 0x78, 0x6a, 0x4d, 0x63, 0x4b, 0x73, 0x64, 0x7a, 0x32, 0x6f, 0x37, 0x43, +0x49, 0x52, 0x79, 0x45, 0x46, 0x4d, 0x2b, 0x52, 0x2f, 0x55, 0x56, 0x49, 0x68, 0x70, 0x4d, 0x44, +0x54, 0x48, 0x6c, 0x50, 0x45, 0x46, 0x48, 0x72, 0x32, 0x37, 0x4d, 0x6b, 0x64, 0x64, 0x39, 0x79, +0x42, 0x75, 0x50, 0x31, 0x32, 0x76, 0x45, 0x6d, 0x54, 0x4d, 0x45, 0x75, 0x57, 0x57, 0x44, 0x44, +0x51, 0x78, 0x6f, 0x32, 0x59, 0x36, 0x6d, 0x72, 0x4d, 0x68, 0x67, 0x32, 0x59, 0x43, 0x59, 0x64, +0x6a, 0x31, 0x71, 0x7a, 0x47, 0x4c, 0x46, 0x2b, 0x4f, 0x57, 0x62, 0x6b, 0x53, 0x30, 0x36, 0x38, +0x66, 0x5a, 0x76, 0x56, 0x71, 0x71, 0x4b, 0x33, 0x46, 0x62, 0x4e, 0x2b, 0x4f, 0x58, 0x50, 0x77, +0x74, 0x34, 0x55, 0x63, 0x4c, 0x75, 0x65, 0x37, 0x57, 0x67, 0x39, 0x69, 0x77, 0x74, 0x52, 0x30, +0x68, 0x46, 0x63, 0x39, 0x65, 0x4d, 0x39, 0x37, 0x36, 0x65, 0x59, 0x7a, 0x68, 0x6d, 0x4f, 0x74, +0x6d, 0x57, 0x53, 0x57, 0x57, 0x76, 0x49, 0x33, 0x56, 0x31, 0x6f, 0x4c, 0x74, 0x31, 0x37, 0x4f, +0x41, 0x39, 0x2f, 0x37, 0x79, 0x4b, 0x45, 0x7a, 0x74, 0x4f, 0x76, 0x36, 0x37, 0x56, 0x41, 0x42, +0x70, 0x55, 0x48, 0x61, 0x54, 0x4a, 0x4e, 0x44, 0x71, 0x71, 0x38, 0x57, 0x6f, 0x45, 0x30, 0x39, +0x42, 0x37, 0x57, 0x68, 0x41, 0x50, 0x2f, 0x70, 0x33, 0x31, 0x4c, 0x46, 0x48, 0x57, 0x6f, 0x55, +0x77, 0x61, 0x42, 0x44, 0x71, 0x34, 0x6a, 0x2b, 0x69, 0x33, 0x35, 0x71, 0x42, 0x65, 0x76, 0x49, +0x78, 0x39, 0x4c, 0x44, 0x64, 0x30, 0x45, 0x6b, 0x57, 0x6d, 0x31, 0x33, 0x52, 0x66, 0x59, 0x34, +0x5a, 0x4c, 0x2f, 0x6e, 0x74, 0x30, 0x54, 0x34, 0x35, 0x52, 0x59, 0x4c, 0x58, 0x36, 0x6e, 0x30, +0x65, 0x33, 0x53, 0x54, 0x77, 0x74, 0x65, 0x44, 0x38, 0x53, 0x70, 0x2f, 0x54, 0x52, 0x77, 0x75, +0x65, 0x71, 0x2f, 0x4f, 0x35, 0x2f, 0x31, 0x6e, 0x42, 0x34, 0x36, 0x2f, 0x5a, 0x75, 0x70, 0x6b, +0x41, 0x45, 0x58, 0x79, 0x4a, 0x31, 0x46, 0x62, 0x6f, 0x6b, 0x78, 0x56, 0x41, 0x75, 0x47, 0x6f, +0x33, 0x7a, 0x6a, 0x6a, 0x76, 0x58, 0x77, 0x69, 0x6c, 0x79, 0x58, 0x4b, 0x2f, 0x43, 0x61, 0x6d, +0x52, 0x78, 0x6e, 0x6e, 0x34, 0x6b, 0x35, 0x49, 0x35, 0x45, 0x75, 0x47, 0x5a, 0x4a, 0x47, 0x2b, +0x74, 0x53, 0x4b, 0x7a, 0x34, 0x77, 0x66, 0x34, 0x35, 0x55, 0x41, 0x53, 0x57, 0x4c, 0x63, 0x55, +0x68, 0x6f, 0x61, 0x4a, 0x32, 0x4c, 0x79, 0x75, 0x55, 0x51, 0x4d, 0x67, 0x6b, 0x4b, 0x4b, 0x2f, +0x73, 0x42, 0x73, 0x71, 0x72, 0x42, 0x46, 0x4a, 0x5a, 0x68, 0x70, 0x32, 0x55, 0x4e, 0x63, 0x77, +0x59, 0x4f, 0x6a, 0x73, 0x37, 0x30, 0x56, 0x72, 0x6a, 0x2b, 0x7a, 0x47, 0x67, 0x6a, 0x52, 0x78, +0x48, 0x72, 0x42, 0x69, 0x6a, 0x42, 0x53, 0x6b, 0x46, 0x6e, 0x54, 0x46, 0x51, 0x55, 0x56, 0x73, +0x73, 0x78, 0x72, 0x65, 0x4f, 0x5a, 0x72, 0x54, 0x57, 0x68, 0x4d, 0x50, 0x68, 0x6e, 0x36, 0x30, +0x41, 0x34, 0x6f, 0x63, 0x6b, 0x41, 0x61, 0x56, 0x32, 0x72, 0x38, 0x7a, 0x58, 0x61, 0x61, 0x73, +0x41, 0x73, 0x58, 0x58, 0x6e, 0x41, 0x73, 0x42, 0x42, 0x74, 0x36, 0x79, 0x75, 0x78, 0x6e, 0x44, +0x56, 0x4f, 0x55, 0x6b, 0x72, 0x6c, 0x74, 0x66, 0x31, 0x2f, 0x6f, 0x45, 0x43, 0x53, 0x49, 0x2f, +0x35, 0x41, 0x38, 0x68, 0x35, 0x37, 0x32, 0x47, 0x71, 0x63, 0x6a, 0x46, 0x5a, 0x59, 0x61, 0x54, +0x66, 0x56, 0x66, 0x69, 0x44, 0x72, 0x55, 0x50, 0x51, 0x66, 0x71, 0x6b, 0x53, 0x69, 0x4c, 0x6e, +0x67, 0x4f, 0x61, 0x52, 0x6a, 0x76, 0x72, 0x47, 0x4b, 0x49, 0x65, 0x6d, 0x7a, 0x54, 0x69, 0x44, +0x68, 0x6e, 0x6e, 0x6a, 0x6f, 0x45, 0x32, 0x71, 0x71, 0x69, 0x39, 0x68, 0x59, 0x33, 0x2b, 0x71, +0x51, 0x67, 0x38, 0x61, 0x79, 0x42, 0x69, 0x55, 0x78, 0x42, 0x30, 0x6e, 0x6e, 0x51, 0x4b, 0x73, +0x38, 0x61, 0x79, 0x73, 0x48, 0x33, 0x4e, 0x6e, 0x4a, 0x7a, 0x72, 0x59, 0x77, 0x2f, 0x33, 0x68, +0x71, 0x4d, 0x61, 0x2b, 0x2f, 0x65, 0x43, 0x2f, 0x77, 0x44, 0x66, 0x50, 0x6d, 0x7a, 0x57, 0x50, +0x31, 0x36, 0x74, 0x58, 0x78, 0x6c, 0x63, 0x6e, 0x33, 0x45, 0x36, 0x5a, 0x71, 0x2f, 0x46, 0x30, +0x49, 0x68, 0x4f, 0x38, 0x6a, 0x70, 0x55, 0x42, 0x4b, 0x78, 0x61, 0x42, 0x42, 0x67, 0x32, 0x77, +0x66, 0x54, 0x4a, 0x31, 0x4b, 0x65, 0x4f, 0x4e, 0x47, 0x4b, 0x39, 0x6a, 0x70, 0x44, 0x4e, 0x51, +0x70, 0x55, 0x59, 0x54, 0x45, 0x64, 0x35, 0x53, 0x43, 0x67, 0x51, 0x4e, 0x68, 0x30, 0x53, 0x49, +0x6f, 0x75, 0x39, 0x76, 0x4f, 0x65, 0x53, 0x66, 0x6f, 0x78, 0x68, 0x68, 0x72, 0x36, 0x68, 0x76, +0x6a, 0x6e, 0x48, 0x34, 0x71, 0x79, 0x58, 0x6d, 0x74, 0x34, 0x67, 0x72, 0x41, 0x51, 0x70, 0x6e, +0x6c, 0x7a, 0x78, 0x68, 0x2f, 0x6b, 0x78, 0x48, 0x4b, 0x48, 0x68, 0x66, 0x2b, 0x6d, 0x32, 0x35, +0x48, 0x50, 0x58, 0x41, 0x50, 0x61, 0x72, 0x2b, 0x44, 0x30, 0x4e, 0x4d, 0x2b, 0x51, 0x75, 0x58, +0x6e, 0x78, 0x50, 0x66, 0x37, 0x36, 0x76, 0x42, 0x44, 0x30, 0x41, 0x73, 0x58, 0x6f, 0x53, 0x36, +0x36, 0x47, 0x48, 0x33, 0x4b, 0x69, 0x65, 0x68, 0x4a, 0x35, 0x36, 0x45, 0x76, 0x2b, 0x79, 0x4d, +0x68, 0x35, 0x37, 0x73, 0x6f, 0x4b, 0x35, 0x4b, 0x63, 0x65, 0x62, 0x5a, 0x67, 0x37, 0x4e, 0x36, +0x43, 0x72, 0x61, 0x32, 0x43, 0x42, 0x35, 0x62, 0x37, 0x66, 0x4c, 0x41, 0x7a, 0x6b, 0x66, 0x39, +0x77, 0x36, 0x33, 0x72, 0x42, 0x78, 0x7a, 0x73, 0x46, 0x31, 0x2f, 0x58, 0x78, 0x75, 0x66, 0x6f, +0x69, 0x77, 0x64, 0x6a, 0x68, 0x69, 0x6e, 0x2f, 0x4f, 0x55, 0x49, 0x45, 0x43, 0x73, 0x46, 0x54, +0x4c, 0x6c, 0x59, 0x56, 0x5a, 0x4c, 0x6b, 0x36, 0x76, 0x45, 0x53, 0x36, 0x63, 0x46, 0x35, 0x42, +0x4a, 0x69, 0x41, 0x42, 0x4c, 0x37, 0x6f, 0x52, 0x66, 0x6d, 0x39, 0x52, 0x73, 0x4c, 0x69, 0x4d, +0x6b, 0x58, 0x73, 0x39, 0x71, 0x50, 0x47, 0x6d, 0x68, 0x6b, 0x46, 0x70, 0x61, 0x45, 0x79, 0x65, +0x49, 0x6d, 0x58, 0x74, 0x53, 0x59, 0x4a, 0x53, 0x4e, 0x35, 0x34, 0x65, 0x43, 0x76, 0x58, 0x57, +0x77, 0x68, 0x77, 0x6d, 0x67, 0x79, 0x49, 0x58, 0x56, 0x64, 0x67, 0x4a, 0x4b, 0x35, 0x57, 0x4b, +0x32, 0x44, 0x73, 0x6f, 0x72, 0x4a, 0x63, 0x49, 0x6b, 0x39, 0x6c, 0x64, 0x4b, 0x4b, 0x68, 0x51, +0x71, 0x5a, 0x51, 0x2b, 0x6b, 0x6c, 0x4b, 0x4b, 0x35, 0x75, 0x5a, 0x6c, 0x6f, 0x4e, 0x49, 0x72, +0x57, 0x6d, 0x6c, 0x68, 0x48, 0x47, 0x34, 0x67, 0x4f, 0x6a, 0x42, 0x39, 0x32, 0x39, 0x32, 0x6a, +0x46, 0x37, 0x34, 0x7a, 0x52, 0x31, 0x41, 0x4b, 0x36, 0x44, 0x58, 0x77, 0x66, 0x4f, 0x6d, 0x4d, +0x67, 0x5a, 0x43, 0x74, 0x61, 0x36, 0x7a, 0x67, 0x44, 0x61, 0x37, 0x70, 0x77, 0x2f, 0x78, 0x67, +0x72, 0x72, 0x74, 0x59, 0x61, 0x6f, 0x6d, 0x6c, 0x51, 0x61, 0x71, 0x6b, 0x49, 0x65, 0x61, 0x47, +0x75, 0x31, 0x34, 0x63, 0x69, 0x55, 0x46, 0x56, 0x6e, 0x52, 0x56, 0x52, 0x5a, 0x42, 0x61, 0x43, +0x42, 0x41, 0x59, 0x64, 0x70, 0x62, 0x72, 0x76, 0x5a, 0x45, 0x57, 0x70, 0x49, 0x68, 0x35, 0x4f, +0x58, 0x77, 0x52, 0x78, 0x4a, 0x73, 0x41, 0x70, 0x62, 0x47, 0x4b, 0x7a, 0x39, 0x54, 0x57, 0x6d, +0x62, 0x32, 0x50, 0x50, 0x53, 0x6e, 0x7a, 0x57, 0x4c, 0x61, 0x63, 0x31, 0x6f, 0x42, 0x52, 0x69, +0x74, 0x4b, 0x58, 0x37, 0x6c, 0x56, 0x5a, 0x79, 0x76, 0x75, 0x67, 0x74, 0x4f, 0x51, 0x41, 0x4f, +0x71, 0x74, 0x64, 0x58, 0x43, 0x57, 0x62, 0x57, 0x6b, 0x73, 0x71, 0x41, 0x79, 0x33, 0x73, 0x66, +0x78, 0x64, 0x2f, 0x63, 0x4b, 0x77, 0x6c, 0x75, 0x5a, 0x6f, 0x4f, 0x43, 0x2f, 0x50, 0x58, 0x38, +0x4d, 0x4a, 0x78, 0x35, 0x54, 0x78, 0x2b, 0x5a, 0x74, 0x37, 0x65, 0x54, 0x6d, 0x68, 0x4f, 0x6c, +0x64, 0x55, 0x38, 0x67, 0x33, 0x33, 0x32, 0x32, 0x6a, 0x6f, 0x69, 0x4b, 0x50, 0x58, 0x6a, 0x31, +0x79, 0x57, 0x66, 0x6a, 0x4e, 0x56, 0x76, 0x72, 0x55, 0x46, 0x4e, 0x4b, 0x77, 0x75, 0x52, 0x55, +0x76, 0x64, 0x79, 0x38, 0x2b, 0x66, 0x76, 0x45, 0x47, 0x74, 0x75, 0x39, 0x35, 0x4e, 0x65, 0x64, +0x4d, 0x4c, 0x4f, 0x44, 0x41, 0x2f, 0x57, 0x39, 0x68, 0x79, 0x69, 0x55, 0x54, 0x48, 0x42, 0x53, +0x35, 0x32, 0x71, 0x31, 0x6b, 0x43, 0x75, 0x6b, 0x4b, 0x77, 0x41, 0x5a, 0x37, 0x31, 0x65, 0x42, +0x64, 0x53, 0x70, 0x6b, 0x51, 0x43, 0x6a, 0x66, 0x2b, 0x47, 0x67, 0x68, 0x46, 0x59, 0x31, 0x42, +0x56, 0x6c, 0x51, 0x4a, 0x46, 0x2f, 0x31, 0x46, 0x57, 0x36, 0x71, 0x43, 0x32, 0x6e, 0x75, 0x38, +0x6a, 0x6c, 0x61, 0x61, 0x71, 0x4c, 0x41, 0x2f, 0x70, 0x45, 0x68, 0x51, 0x69, 0x4e, 0x62, 0x5a, +0x61, 0x62, 0x30, 0x31, 0x6c, 0x76, 0x6c, 0x4d, 0x4f, 0x41, 0x52, 0x75, 0x78, 0x63, 0x73, 0x7a, +0x45, 0x6f, 0x49, 0x7a, 0x72, 0x7a, 0x51, 0x7a, 0x6a, 0x33, 0x2b, 0x33, 0x38, 0x71, 0x61, 0x76, +0x72, 0x41, 0x6d, 0x56, 0x58, 0x61, 0x7a, 0x62, 0x59, 0x56, 0x58, 0x2f, 0x46, 0x64, 0x36, 0x68, +0x37, 0x37, 0x6b, 0x65, 0x66, 0x64, 0x56, 0x70, 0x38, 0x72, 0x78, 0x39, 0x33, 0x2b, 0x47, 0x6d, +0x4e, 0x79, 0x6f, 0x32, 0x67, 0x6e, 0x33, 0x77, 0x55, 0x2f, 0x65, 0x2f, 0x2f, 0x6f, 0x47, 0x2b, +0x2b, 0x48, 0x6a, 0x4e, 0x72, 0x44, 0x75, 0x4c, 0x68, 0x42, 0x78, 0x6c, 0x57, 0x41, 0x6c, 0x65, +0x63, 0x4a, 0x53, 0x6b, 0x73, 0x72, 0x57, 0x5a, 0x65, 0x6f, 0x2b, 0x44, 0x46, 0x72, 0x59, 0x6f, +0x74, 0x53, 0x6c, 0x42, 0x62, 0x6c, 0x41, 0x71, 0x46, 0x58, 0x79, 0x6b, 0x6b, 0x56, 0x39, 0x52, +0x4c, 0x7a, 0x71, 0x35, 0x55, 0x48, 0x44, 0x46, 0x42, 0x4d, 0x58, 0x70, 0x50, 0x78, 0x64, 0x76, +0x76, 0x67, 0x38, 0x65, 0x45, 0x39, 0x30, 0x77, 0x43, 0x72, 0x53, 0x64, 0x54, 0x79, 0x53, 0x50, +0x6a, 0x68, 0x4a, 0x4b, 0x75, 0x38, 0x33, 0x7a, 0x74, 0x63, 0x72, 0x67, 0x54, 0x75, 0x38, 0x67, +0x4e, 0x54, 0x4d, 0x6d, 0x49, 0x6b, 0x43, 0x50, 0x74, 0x75, 0x30, 0x7a, 0x37, 0x50, 0x54, 0x6a, +0x47, 0x6a, 0x36, 0x63, 0x72, 0x33, 0x32, 0x54, 0x36, 0x35, 0x32, 0x41, 0x47, 0x5a, 0x7a, 0x69, +0x2b, 0x2b, 0x4f, 0x49, 0x4c, 0x36, 0x75, 0x72, 0x71, 0x61, 0x47, 0x31, 0x74, 0x4a, 0x52, 0x61, +0x7a, 0x6c, 0x56, 0x6a, 0x76, 0x65, 0x33, 0x38, 0x4a, 0x72, 0x37, 0x79, 0x2f, 0x6a, 0x4f, 0x77, +0x65, 0x46, 0x67, 0x2f, 0x71, 0x74, 0x31, 0x52, 0x78, 0x2b, 0x4e, 0x43, 0x50, 0x75, 0x4f, 0x32, +0x67, 0x35, 0x7a, 0x42, 0x74, 0x43, 0x57, 0x45, 0x4b, 0x52, 0x59, 0x6f, 0x59, 0x65, 0x4f, 0x53, +0x4b, 0x56, 0x4d, 0x51, 0x57, 0x32, 0x6f, 0x56, 0x32, 0x64, 0x73, 0x48, 0x50, 0x6e, 0x72, 0x54, +0x2f, 0x47, 0x76, 0x6a, 0x34, 0x51, 0x45, 0x76, 0x71, 0x47, 0x36, 0x41, 0x35, 0x6f, 0x7a, 0x44, +0x6a, 0x79, 0x68, 0x6e, 0x55, 0x35, 0x4e, 0x66, 0x45, 0x30, 0x58, 0x74, 0x61, 0x61, 0x32, 0x54, +0x6a, 0x57, 0x76, 0x72, 0x38, 0x36, 0x74, 0x51, 0x75, 0x2b, 0x32, 0x2b, 0x39, 0x59, 0x6f, 0x58, +0x74, 0x6b, 0x79, 0x52, 0x30, 0x58, 0x33, 0x65, 0x66, 0x4d, 0x37, 0x57, 0x68, 0x7a, 0x38, 0x53, +0x4a, 0x69, 0x4e, 0x5a, 0x55, 0x4a, 0x52, 0x44, 0x34, 0x41, 0x70, 0x4c, 0x4e, 0x2f, 0x69, 0x37, +0x68, 0x51, 0x69, 0x42, 0x53, 0x56, 0x4d, 0x52, 0x68, 0x52, 0x7a, 0x58, 0x38, 0x4e, 0x42, 0x68, +0x31, 0x4e, 0x31, 0x42, 0x77, 0x31, 0x6c, 0x32, 0x56, 0x64, 0x46, 0x4c, 0x79, 0x79, 0x62, 0x71, +0x62, 0x33, 0x39, 0x4c, 0x2f, 0x77, 0x50, 0x7a, 0x4d, 0x41, 0x2f, 0x73, 0x54, 0x6a, 0x33, 0x61, +0x36, 0x4f, 0x6b, 0x48, 0x4a, 0x38, 0x46, 0x75, 0x6d, 0x63, 0x77, 0x41, 0x47, 0x68, 0x6d, 0x39, +0x4d, 0x51, 0x66, 0x64, 0x74, 0x33, 0x2f, 0x6c, 0x6e, 0x46, 0x70, 0x64, 0x56, 0x4d, 0x48, 0x7a, +0x62, 0x4e, 0x6e, 0x72, 0x30, 0x75, 0x44, 0x7a, 0x44, 0x73, 0x36, 0x54, 0x4e, 0x35, 0x71, 0x73, +0x2b, 0x37, 0x44, 0x4c, 0x2b, 0x43, 0x36, 0x39, 0x62, 0x6d, 0x42, 0x68, 0x33, 0x39, 0x77, 0x37, +0x51, 0x2f, 0x35, 0x65, 0x2f, 0x37, 0x48, 0x4c, 0x2f, 0x38, 0x76, 0x36, 0x44, 0x6b, 0x54, 0x32, +0x71, 0x55, 0x45, 0x2f, 0x2f, 0x41, 0x31, 0x31, 0x52, 0x47, 0x76, 0x66, 0x77, 0x70, 0x77, 0x69, +0x2f, 0x65, 0x39, 0x65, 0x42, 0x33, 0x32, 0x4e, 0x48, 0x45, 0x2f, 0x72, 0x79, 0x61, 0x77, 0x68, +0x74, 0x33, 0x38, 0x70, 0x75, 0x54, 0x36, 0x2b, 0x69, 0x6f, 0x51, 0x56, 0x47, 0x4c, 0x34, 0x4c, +0x57, 0x6c, 0x61, 0x53, 0x4f, 0x55, 0x66, 0x71, 0x34, 0x42, 0x61, 0x44, 0x4d, 0x2f, 0x6a, 0x42, +0x6a, 0x58, 0x78, 0x68, 0x63, 0x44, 0x4e, 0x34, 0x2f, 0x77, 0x4a, 0x7a, 0x2f, 0x76, 0x77, 0x78, +0x41, 0x65, 0x33, 0x75, 0x58, 0x33, 0x33, 0x34, 0x79, 0x4d, 0x37, 0x44, 0x57, 0x39, 0x48, 0x50, +0x63, 0x61, 0x50, 0x2f, 0x58, 0x6f, 0x7a, 0x6e, 0x39, 0x33, 0x6b, 0x6e, 0x76, 0x75, 0x35, 0x6f, +0x4d, 0x67, 0x52, 0x49, 0x61, 0x57, 0x44, 0x54, 0x62, 0x4b, 0x72, 0x62, 0x67, 0x6b, 0x4b, 0x51, +0x70, 0x75, 0x58, 0x52, 0x63, 0x61, 0x66, 0x4a, 0x6e, 0x57, 0x4d, 0x58, 0x5a, 0x38, 0x66, 0x75, +0x45, 0x6b, 0x75, 0x36, 0x5a, 0x72, 0x4f, 0x53, 0x53, 0x6b, 0x61, 0x4b, 0x70, 0x56, 0x38, 0x4e, +0x39, 0x4c, 0x38, 0x4c, 0x6a, 0x65, 0x30, 0x4b, 0x42, 0x71, 0x31, 0x6d, 0x61, 0x76, 0x73, 0x4d, +0x49, 0x66, 0x67, 0x74, 0x2b, 0x44, 0x7a, 0x34, 0x48, 0x33, 0x79, 0x74, 0x6e, 0x38, 0x75, 0x4e, +0x51, 0x57, 0x44, 0x63, 0x4a, 0x76, 0x42, 0x48, 0x77, 0x56, 0x43, 0x47, 0x63, 0x66, 0x58, 0x72, +0x69, 0x39, 0x4c, 0x32, 0x75, 0x4e, 0x37, 0x51, 0x6c, 0x58, 0x53, 0x2b, 0x31, 0x6a, 0x70, 0x50, +0x4b, 0x2b, 0x6a, 0x37, 0x34, 0x72, 0x6b, 0x79, 0x61, 0x53, 0x4b, 0x59, 0x35, 0x44, 0x31, 0x37, +0x5a, 0x30, 0x50, 0x78, 0x36, 0x64, 0x70, 0x66, 0x32, 0x4a, 0x73, 0x62, 0x63, 0x2f, 0x71, 0x50, +0x52, 0x44, 0x6b, 0x36, 0x63, 0x50, 0x50, 0x35, 0x57, 0x4d, 0x49, 0x72, 0x48, 0x48, 0x39, 0x77, +0x41, 0x46, 0x48, 0x64, 0x39, 0x36, 0x70, 0x39, 0x30, 0x74, 0x46, 0x53, 0x73, 0x58, 0x56, 0x6e, +0x44, 0x33, 0x56, 0x67, 0x34, 0x66, 0x44, 0x71, 0x62, 0x66, 0x61, 0x5a, 0x2b, 0x53, 0x42, 0x4f, +0x4b, 0x64, 0x2f, 0x72, 0x66, 0x79, 0x4e, 0x4c, 0x69, 0x4f, 0x71, 0x35, 0x34, 0x61, 0x6a, 0x46, +0x58, 0x6c, 0x79, 0x34, 0x6e, 0x4e, 0x77, 0x51, 0x33, 0x4c, 0x36, 0x39, 0x6b, 0x79, 0x68, 0x6a, +0x4e, 0x41, 0x33, 0x4d, 0x2f, 0x41, 0x57, 0x70, 0x49, 0x72, 0x45, 0x67, 0x36, 0x36, 0x53, 0x62, +0x32, 0x74, 0x2f, 0x44, 0x73, 0x48, 0x61, 0x7a, 0x45, 0x59, 0x33, 0x6a, 0x45, 0x6b, 0x41, 0x39, +0x49, 0x4e, 0x4d, 0x30, 0x70, 0x39, 0x77, 0x34, 0x63, 0x54, 0x39, 0x70, 0x2b, 0x44, 0x72, 0x6c, +0x33, 0x52, 0x78, 0x2b, 0x74, 0x4a, 0x71, 0x61, 0x78, 0x49, 0x74, 0x4e, 0x31, 0x37, 0x69, 0x62, +0x2f, 0x6c, 0x76, 0x36, 0x39, 0x4a, 0x63, 0x4f, 0x31, 0x36, 0x58, 0x2b, 0x6a, 0x4f, 0x79, 0x69, +0x37, 0x42, 0x43, 0x4c, 0x6e, 0x41, 0x63, 0x64, 0x50, 0x6e, 0x63, 0x70, 0x37, 0x77, 0x50, 0x64, +0x4a, 0x34, 0x51, 0x69, 0x62, 0x2b, 0x53, 0x58, 0x6a, 0x70, 0x70, 0x63, 0x55, 0x41, 0x70, 0x48, +0x30, 0x4c, 0x6f, 0x52, 0x67, 0x75, 0x6f, 0x50, 0x69, 0x35, 0x75, 0x66, 0x6e, 0x41, 0x2b, 0x6d, +0x41, 0x46, 0x75, 0x67, 0x43, 0x68, 0x55, 0x78, 0x37, 0x62, 0x64, 0x36, 0x38, 0x47, 0x59, 0x43, +0x70, 0x55, 0x35, 0x4f, 0x67, 0x6c, 0x45, 0x6c, 0x74, 0x69, 0x4a, 0x74, 0x2b, 0x4c, 0x76, 0x77, +0x57, 0x6a, 0x63, 0x55, 0x79, 0x33, 0x6a, 0x38, 0x6e, 0x43, 0x55, 0x70, 0x4b, 0x47, 0x70, 0x51, +0x30, 0x6a, 0x75, 0x67, 0x54, 0x41, 0x65, 0x4f, 0x50, 0x69, 0x45, 0x4f, 0x4c, 0x74, 0x30, 0x36, +0x66, 0x44, 0x6a, 0x37, 0x63, 0x64, 0x50, 0x39, 0x67, 0x64, 0x37, 0x32, 0x44, 0x33, 0x32, 0x71, +0x48, 0x61, 0x4e, 0x51, 0x42, 0x6b, 0x74, 0x48, 0x6d, 0x37, 0x55, 0x75, 0x5a, 0x51, 0x44, 0x59, +0x4b, 0x6f, 0x58, 0x6e, 0x31, 0x6f, 0x55, 0x38, 0x49, 0x41, 0x5a, 0x56, 0x33, 0x2f, 0x7a, 0x6e, +0x2b, 0x30, 0x45, 0x62, 0x5a, 0x36, 0x6b, 0x4d, 0x71, 0x5a, 0x4d, 0x67, 0x2b, 0x4c, 0x52, 0x2b, +0x44, 0x70, 0x50, 0x50, 0x70, 0x6e, 0x59, 0x54, 0x62, 0x2f, 0x66, 0x67, 0x32, 0x79, 0x49, 0x67, +0x59, 0x52, 0x67, 0x68, 0x57, 0x54, 0x48, 0x75, 0x54, 0x4e, 0x2b, 0x66, 0x41, 0x4c, 0x77, 0x64, +0x4d, 0x35, 0x66, 0x41, 0x36, 0x47, 0x46, 0x36, 0x5a, 0x57, 0x4d, 0x65, 0x4e, 0x53, 0x61, 0x4a, +0x70, 0x49, 0x7a, 0x4f, 0x72, 0x62, 0x64, 0x75, 0x71, 0x4e, 0x43, 0x68, 0x73, 0x4a, 0x6c, 0x5a, +0x68, 0x4b, 0x63, 0x6e, 0x4e, 0x6c, 0x5a, 0x78, 0x61, 0x4c, 0x5a, 0x6a, 0x31, 0x6a, 0x4f, 0x53, +0x4c, 0x65, 0x73, 0x46, 0x4a, 0x4a, 0x79, 0x58, 0x36, 0x37, 0x38, 0x47, 0x7a, 0x59, 0x46, 0x42, +0x56, 0x59, 0x74, 0x41, 0x4d, 0x58, 0x70, 0x79, 0x53, 0x32, 0x78, 0x69, 0x44, 0x4e, 0x68, 0x35, +0x47, 0x68, 0x7a, 0x48, 0x47, 0x55, 0x70, 0x49, 0x6c, 0x63, 0x77, 0x7a, 0x4d, 0x57, 0x39, 0x6f, +0x47, 0x5a, 0x46, 0x4f, 0x63, 0x61, 0x38, 0x64, 0x2f, 0x36, 0x64, 0x4b, 0x6c, 0x37, 0x4e, 0x79, +0x35, 0x6b, 0x7a, 0x33, 0x32, 0x32, 0x49, 0x4f, 0x38, 0x76, 0x50, 0x79, 0x55, 0x38, 0x65, 0x2f, +0x6f, 0x36, 0x4f, 0x44, 0x7a, 0x42, 0x56, 0x39, 0x51, 0x58, 0x46, 0x4c, 0x4d, 0x71, 0x46, 0x47, +0x57, 0x52, 0x4c, 0x57, 0x68, 0x63, 0x53, 0x74, 0x59, 0x43, 0x63, 0x74, 0x38, 0x4a, 0x47, 0x76, +0x57, 0x7a, 0x45, 0x63, 0x68, 0x77, 0x46, 0x51, 0x39, 0x46, 0x55, 0x61, 0x44, 0x7a, 0x74, 0x64, +0x6f, 0x38, 0x54, 0x4e, 0x59, 0x6c, 0x66, 0x38, 0x32, 0x6e, 0x63, 0x73, 0x2f, 0x62, 0x75, 0x50, +0x64, 0x42, 0x34, 0x62, 0x78, 0x6d, 0x7a, 0x4d, 0x4f, 0x4a, 0x72, 0x70, 0x79, 0x4a, 0x62, 0x71, +0x74, 0x6e, 0x54, 0x4f, 0x72, 0x65, 0x70, 0x4a, 0x66, 0x57, 0x59, 0x35, 0x38, 0x36, 0x52, 0x4f, +0x30, 0x56, 0x34, 0x67, 0x76, 0x4a, 0x46, 0x4a, 0x35, 0x46, 0x47, 0x62, 0x48, 0x75, 0x47, 0x68, +0x43, 0x4b, 0x39, 0x65, 0x2f, 0x55, 0x6f, 0x41, 0x76, 0x42, 0x4e, 0x4f, 0x66, 0x6e, 0x41, 0x78, +0x41, 0x78, 0x57, 0x35, 0x2f, 0x34, 0x53, 0x76, 0x2b, 0x7a, 0x55, 0x78, 0x4f, 0x51, 0x68, 0x6e, +0x62, 0x66, 0x38, 0x72, 0x4e, 0x35, 0x34, 0x69, 0x4a, 0x45, 0x64, 0x4e, 0x68, 0x6f, 0x6b, 0x54, +0x69, 0x71, 0x64, 0x6a, 0x53, 0x47, 0x49, 0x51, 0x78, 0x50, 0x44, 0x6a, 0x50, 0x73, 0x69, 0x4a, +0x37, 0x61, 0x66, 0x50, 0x58, 0x55, 0x34, 0x71, 0x77, 0x6d, 0x37, 0x2f, 0x68, 0x74, 0x50, 0x6d, +0x62, 0x50, 0x49, 0x2f, 0x62, 0x33, 0x50, 0x7a, 0x76, 0x64, 0x56, 0x66, 0x71, 0x39, 0x63, 0x6e, +0x4d, 0x57, 0x58, 0x47, 0x79, 0x6b, 0x6f, 0x43, 0x46, 0x4b, 0x6b, 0x6a, 0x4a, 0x6c, 0x34, 0x4c, +0x46, 0x7a, 0x7a, 0x67, 0x6f, 0x63, 0x43, 0x57, 0x47, 0x4d, 0x7a, 0x62, 0x57, 0x4d, 0x30, 0x73, +0x70, 0x58, 0x6c, 0x53, 0x4b, 0x5a, 0x69, 0x48, 0x69, 0x41, 0x68, 0x68, 0x2f, 0x2b, 0x51, 0x4a, +0x66, 0x4a, 0x4a, 0x77, 0x7a, 0x74, 0x57, 0x6b, 0x72, 0x64, 0x36, 0x72, 0x77, 0x47, 0x35, 0x67, +0x31, 0x43, 0x7a, 0x50, 0x33, 0x45, 0x2b, 0x73, 0x4d, 0x48, 0x44, 0x63, 0x4f, 0x63, 0x2f, 0x54, +0x52, 0x71, 0x57, 0x47, 0x59, 0x6c, 0x44, 0x69, 0x2b, 0x59, 0x65, 0x50, 0x47, 0x2b, 0x6f, 0x54, +0x5a, 0x45, 0x77, 0x35, 0x7a, 0x31, 0x5a, 0x51, 0x70, 0x7a, 0x48, 0x6a, 0x6f, 0x49, 0x56, 0x54, +0x4d, 0x35, 0x2f, 0x41, 0x70, 0x6b, 0x35, 0x6c, 0x36, 0x77, 0x77, 0x31, 0x30, 0x4e, 0x44, 0x64, +0x33, 0x63, 0x33, 0x2f, 0x4c, 0x79, 0x68, 0x71, 0x48, 0x38, 0x67, 0x6f, 0x42, 0x57, 0x51, 0x71, +0x76, 0x31, 0x6e, 0x49, 0x58, 0x36, 0x6d, 0x38, 0x45, 0x75, 0x73, 0x30, 0x35, 0x4a, 0x4a, 0x4e, +0x59, 0x57, 0x65, 0x30, 0x71, 0x33, 0x45, 0x61, 0x75, 0x38, 0x57, 0x6e, 0x59, 0x47, 0x72, 0x4e, +0x37, 0x36, 0x32, 0x51, 0x43, 0x54, 0x57, 0x6d, 0x72, 0x41, 0x55, 0x75, 0x52, 0x42, 0x47, 0x49, +0x53, 0x6c, 0x6c, 0x6d, 0x31, 0x64, 0x38, 0x39, 0x63, 0x48, 0x4b, 0x45, 0x55, 0x59, 0x4a, 0x43, +0x62, 0x36, 0x73, 0x46, 0x6f, 0x6c, 0x77, 0x35, 0x71, 0x4f, 0x37, 0x33, 0x7a, 0x72, 0x79, 0x45, +0x6b, 0x6b, 0x6c, 0x42, 0x44, 0x47, 0x30, 0x49, 0x6c, 0x56, 0x64, 0x71, 0x4e, 0x52, 0x51, 0x6e, +0x58, 0x4f, 0x43, 0x68, 0x6f, 0x4c, 0x6d, 0x78, 0x76, 0x4d, 0x7a, 0x7a, 0x2b, 0x5a, 0x54, 0x4e, +0x37, 0x56, 0x54, 0x64, 0x7a, 0x79, 0x76, 0x42, 0x61, 0x38, 0x69, 0x4d, 0x6c, 0x51, 0x43, 0x64, +0x78, 0x70, 0x71, 0x61, 0x55, 0x6c, 0x31, 0x55, 0x41, 0x6e, 0x74, 0x66, 0x44, 0x4b, 0x74, 0x6c, +0x6b, 0x4b, 0x4b, 0x72, 0x62, 0x6d, 0x77, 0x76, 0x74, 0x78, 0x6b, 0x38, 0x4a, 0x68, 0x76, 0x63, +0x53, 0x6e, 0x4a, 0x77, 0x6a, 0x65, 0x4f, 0x77, 0x36, 0x7a, 0x51, 0x32, 0x33, 0x54, 0x2b, 0x50, +0x73, 0x73, 0x79, 0x38, 0x6b, 0x59, 0x6a, 0x59, 0x79, 0x6f, 0x4b, 0x36, 0x57, 0x7a, 0x79, 0x36, +0x42, 0x34, 0x55, 0x4e, 0x43, 0x35, 0x44, 0x78, 0x77, 0x50, 0x33, 0x72, 0x7a, 0x56, 0x6c, 0x41, +0x53, 0x37, 0x55, 0x75, 0x49, 0x68, 0x44, 0x42, 0x74, 0x64, 0x6e, 0x49, 0x61, 0x49, 0x65, 0x4e, +0x56, 0x67, 0x2b, 0x4e, 0x77, 0x61, 0x46, 0x38, 0x51, 0x71, 0x71, 0x6c, 0x6d, 0x33, 0x79, 0x66, +0x2f, 0x41, 0x5a, 0x33, 0x57, 0x41, 0x74, 0x79, 0x32, 0x62, 0x52, 0x76, 0x76, 0x76, 0x50, 0x4d, +0x4f, 0x54, 0x54, 0x75, 0x62, 0x71, 0x4b, 0x79, 0x71, 0x59, 0x75, 0x43, 0x41, 0x41, 0x5a, 0x68, +0x56, 0x71, 0x2b, 0x77, 0x6b, 0x48, 0x44, 0x53, 0x49, 0x68, 0x73, 0x31, 0x62, 0x65, 0x4f, 0x32, +0x31, 0x66, 0x31, 0x4e, 0x61, 0x56, 0x6b, 0x5a, 0x46, 0x65, 0x54, 0x6c, 0x39, 0x61, 0x6d, 0x76, +0x74, 0x66, 0x6e, 0x72, 0x74, 0x79, 0x6a, 0x59, 0x53, 0x75, 0x58, 0x74, 0x4a, 0x52, 0x7a, 0x35, +0x65, 0x58, 0x67, 0x56, 0x34, 0x59, 0x44, 0x71, 0x32, 0x59, 0x39, 0x50, 0x33, 0x75, 0x68, 0x7a, +0x32, 0x32, 0x6a, 0x62, 0x44, 0x78, 0x6e, 0x2f, 0x56, 0x6f, 0x77, 0x35, 0x53, 0x71, 0x41, 0x72, +0x37, 0x33, 0x45, 0x45, 0x2f, 0x42, 0x42, 0x77, 0x58, 0x63, 0x65, 0x64, 0x79, 0x4d, 0x71, 0x74, +0x7a, 0x46, 0x4a, 0x35, 0x6b, 0x48, 0x6a, 0x6d, 0x72, 0x39, 0x69, 0x4c, 0x79, 0x39, 0x58, 0x78, +0x43, 0x4f, 0x35, 0x71, 0x52, 0x6e, 0x5a, 0x33, 0x6b, 0x56, 0x70, 0x54, 0x52, 0x49, 0x51, 0x31, +0x72, 0x4e, 0x6b, 0x42, 0x32, 0x75, 0x49, 0x4f, 0x6d, 0x54, 0x6f, 0x4f, 0x4a, 0x52, 0x42, 0x67, +0x33, 0x39, 0x46, 0x4f, 0x65, 0x2f, 0x46, 0x69, 0x77, 0x66, 0x50, 0x31, 0x59, 0x65, 0x6c, 0x66, +0x6d, 0x45, 0x35, 0x68, 0x65, 0x44, 0x64, 0x54, 0x79, 0x72, 0x44, 0x69, 0x4a, 0x55, 0x41, 0x41, +0x75, 0x4d, 0x31, 0x62, 0x49, 0x2b, 0x2b, 0x68, 0x6c, 0x6a, 0x44, 0x4b, 0x7a, 0x32, 0x61, 0x37, +0x4c, 0x2b, 0x4e, 0x41, 0x63, 0x51, 0x35, 0x76, 0x4f, 0x63, 0x52, 0x57, 0x4f, 0x44, 0x44, 0x31, +0x7a, 0x50, 0x50, 0x41, 0x31, 0x6b, 0x38, 0x4f, 0x2f, 0x35, 0x71, 0x51, 0x65, 0x34, 0x32, 0x6a, +0x5a, 0x73, 0x68, 0x50, 0x6a, 0x69, 0x74, 0x42, 0x71, 0x5a, 0x55, 0x76, 0x43, 0x53, 0x61, 0x46, +0x51, 0x63, 0x58, 0x70, 0x78, 0x62, 0x66, 0x30, 0x43, 0x55, 0x69, 0x4b, 0x46, 0x70, 0x4b, 0x52, +0x58, 0x4f, 0x54, 0x63, 0x79, 0x6e, 0x5a, 0x6b, 0x41, 0x6b, 0x51, 0x68, 0x71, 0x55, 0x77, 0x4e, +0x6f, 0x36, 0x66, 0x78, 0x72, 0x53, 0x58, 0x6b, 0x72, 0x77, 0x62, 0x73, 0x76, 0x45, 0x70, 0x45, +0x34, 0x58, 0x78, 0x43, 0x71, 0x36, 0x59, 0x4d, 0x6d, 0x44, 0x51, 0x70, 0x38, 0x69, 0x46, 0x49, +0x4d, 0x45, 0x49, 0x4c, 0x2b, 0x52, 0x2f, 0x34, 0x4b, 0x4d, 0x2b, 0x6d, 0x33, 0x75, 0x2f, 0x53, +0x45, 0x65, 0x35, 0x37, 0x48, 0x75, 0x6e, 0x58, 0x72, 0x4d, 0x67, 0x76, 0x2f, 0x61, 0x36, 0x39, +0x68, 0x6e, 0x6e, 0x6b, 0x6d, 0x77, 0x53, 0x6f, 0x38, 0x64, 0x79, 0x36, 0x6d, 0x66, 0x69, 0x50, +0x6d, 0x33, 0x50, 0x4e, 0x53, 0x50, 0x4e, 0x6c, 0x61, 0x61, 0x37, 0x36, 0x66, 0x50, 0x35, 0x2b, +0x36, 0x6b, 0x53, 0x4e, 0x74, 0x6e, 0x44, 0x7a, 0x70, 0x37, 0x33, 0x64, 0x73, 0x33, 0x63, 0x70, +0x35, 0x41, 0x77, 0x5a, 0x59, 0x77, 0x45, 0x52, 0x52, 0x45, 0x61, 0x2b, 0x2f, 0x38, 0x45, 0x49, +0x43, 0x6a, 0x4b, 0x51, 0x31, 0x6f, 0x55, 0x69, 0x59, 0x54, 0x36, 0x61, 0x2f, 0x68, 0x54, 0x37, +0x33, 0x33, 0x48, 0x6a, 0x37, 0x34, 0x38, 0x4c, 0x76, 0x4b, 0x53, 0x4c, 0x48, 0x2b, 0x49, 0x52, +0x47, 0x53, 0x31, 0x41, 0x43, 0x62, 0x35, 0x68, 0x50, 0x62, 0x4a, 0x71, 0x50, 0x62, 0x6b, 0x2f, +0x31, 0x42, 0x6d, 0x74, 0x67, 0x62, 0x75, 0x78, 0x59, 0x42, 0x74, 0x52, 0x66, 0x69, 0x37, 0x39, +0x68, 0x51, 0x35, 0x78, 0x4b, 0x33, 0x43, 0x69, 0x4e, 0x38, 0x6d, 0x4e, 0x6b, 0x39, 0x2b, 0x71, +0x46, 0x56, 0x70, 0x72, 0x4f, 0x6c, 0x53, 0x74, 0x41, 0x4b, 0x6c, 0x51, 0x73, 0x47, 0x72, 0x38, +0x2b, 0x75, 0x32, 0x39, 0x66, 0x44, 0x72, 0x54, 0x64, 0x6a, 0x31, 0x45, 0x6d, 0x6f, 0x58, 0x6d, +0x64, 0x78, 0x74, 0x5a, 0x4b, 0x45, 0x44, 0x36, 0x35, 0x69, 0x43, 0x7a, 0x74, 0x34, 0x54, 0x2f, +0x6b, 0x67, 0x2b, 0x2b, 0x69, 0x49, 0x4c, 0x35, 0x41, 0x69, 0x78, 0x69, 0x65, 0x74, 0x4a, 0x52, +0x51, 0x75, 0x41, 0x79, 0x75, 0x50, 0x2f, 0x2f, 0x69, 0x65, 0x74, 0x70, 0x69, 0x62, 0x64, 0x77, +0x38, 0x35, 0x7a, 0x48, 0x4f, 0x33, 0x4f, 0x4d, 0x6f, 0x52, 0x76, 0x59, 0x59, 0x75, 0x59, 0x76, +0x2b, 0x31, 0x34, 0x43, 0x48, 0x71, 0x72, 0x77, 0x63, 0x64, 0x48, 0x55, 0x43, 0x69, 0x6d, 0x71, +0x73, 0x41, 0x31, 0x55, 0x4a, 0x52, 0x53, 0x6a, 0x62, 0x35, 0x39, 0x4a, 0x42, 0x6b, 0x76, 0x63, +0x66, 0x45, 0x64, 0x79, 0x37, 0x78, 0x6d, 0x66, 0x30, 0x66, 0x69, 0x64, 0x51, 0x55, 0x46, 0x44, +0x49, 0x4d, 0x55, 0x66, 0x75, 0x7a, 0x61, 0x48, 0x6a, 0x56, 0x6a, 0x4d, 0x6b, 0x4c, 0x47, 0x6a, +0x2b, 0x70, 0x56, 0x55, 0x65, 0x33, 0x74, 0x61, 0x74, 0x68, 0x45, 0x49, 0x51, 0x50, 0x76, 0x46, +0x6b, 0x76, 0x48, 0x37, 0x39, 0x38, 0x47, 0x49, 0x78, 0x2f, 0x46, 0x64, 0x66, 0x52, 0x58, 0x37, +0x77, 0x67, 0x51, 0x32, 0x58, 0x43, 0x4e, 0x2b, 0x2b, 0x58, 0x46, 0x31, 0x36, 0x57, 0x33, 0x34, +0x37, 0x6d, 0x67, 0x4a, 0x69, 0x61, 0x6d, 0x70, 0x71, 0x51, 0x67, 0x6a, 0x42, 0x58, 0x6d, 0x50, +0x32, 0x5a, 0x6d, 0x42, 0x4e, 0x4e, 0x65, 0x59, 0x76, 0x66, 0x38, 0x48, 0x4d, 0x6d, 0x59, 0x50, +0x78, 0x6f, 0x35, 0x67, 0x78, 0x65, 0x39, 0x50, 0x2f, 0x6d, 0x71, 0x6b, 0x63, 0x66, 0x76, 0x54, +0x52, 0x2f, 0x50, 0x65, 0x74, 0x74, 0x39, 0x69, 0x30, 0x65, 0x54, 0x4f, 0x39, 0x2b, 0x39, 0x69, +0x71, 0x51, 0x33, 0x6b, 0x58, 0x58, 0x64, 0x78, 0x56, 0x72, 0x48, 0x55, 0x59, 0x4c, 0x31, 0x76, +0x69, 0x35, 0x58, 0x35, 0x74, 0x46, 0x55, 0x44, 0x6e, 0x73, 0x52, 0x67, 0x2f, 0x43, 0x30, 0x4b, +0x71, 0x36, 0x37, 0x6d, 0x50, 0x50, 0x6d, 0x4b, 0x66, 0x76, 0x31, 0x55, 0x68, 0x2f, 0x36, 0x73, +0x34, 0x35, 0x62, 0x4c, 0x66, 0x55, 0x4e, 0x79, 0x6a, 0x32, 0x4a, 0x61, 0x41, 0x30, 0x39, 0x59, +0x61, 0x30, 0x4b, 0x35, 0x4d, 0x76, 0x44, 0x49, 0x36, 0x2f, 0x6e, 0x74, 0x42, 0x56, 0x67, 0x48, +0x5a, 0x46, 0x32, 0x59, 0x7a, 0x2f, 0x5a, 0x46, 0x79, 0x4c, 0x71, 0x6b, 0x62, 0x52, 0x45, 0x46, +0x4c, 0x49, 0x78, 0x31, 0x79, 0x44, 0x56, 0x52, 0x55, 0x6b, 0x6a, 0x65, 0x77, 0x4c, 0x39, 0x76, +0x57, 0x62, 0x55, 0x57, 0x49, 0x54, 0x55, 0x68, 0x74, 0x38, 0x48, 0x33, 0x4a, 0x33, 0x37, 0x61, +0x2b, 0x68, 0x4e, 0x70, 0x2f, 0x46, 0x4c, 0x6f, 0x6f, 0x6d, 0x39, 0x50, 0x65, 0x6e, 0x4d, 0x61, +0x31, 0x4a, 0x52, 0x65, 0x51, 0x69, 0x4c, 0x6b, 0x59, 0x54, 0x6a, 0x5a, 0x50, 0x38, 0x4b, 0x71, +0x2b, 0x41, 0x4e, 0x38, 0x59, 0x75, 0x78, 0x42, 0x6f, 0x79, 0x52, 0x6a, 0x7a, 0x50, 0x76, 0x76, +0x71, 0x74, 0x32, 0x6e, 0x53, 0x4a, 0x62, 0x53, 0x5a, 0x45, 0x47, 0x2f, 0x72, 0x34, 0x2f, 0x47, +0x63, 0x42, 0x53, 0x44, 0x64, 0x39, 0x75, 0x6a, 0x68, 0x75, 0x73, 0x6e, 0x55, 0x6c, 0x67, 0x39, +0x6b, 0x6b, 0x34, 0x72, 0x46, 0x47, 0x5a, 0x46, 0x6a, 0x76, 0x71, 0x4b, 0x69, 0x4a, 0x4d, 0x4c, +0x70, 0x68, 0x2f, 0x66, 0x41, 0x47, 0x4d, 0x50, 0x54, 0x30, 0x7a, 0x65, 0x78, 0x71, 0x69, 0x47, +0x4b, 0x42, 0x2f, 0x47, 0x6f, 0x52, 0x4f, 0x2f, 0x4b, 0x48, 0x46, 0x62, 0x78, 0x45, 0x4e, 0x6b, +0x62, 0x54, 0x69, 0x54, 0x48, 0x4f, 0x53, 0x32, 0x4a, 0x79, 0x35, 0x62, 0x48, 0x31, 0x76, 0x61, +0x74, 0x50, 0x4c, 0x58, 0x67, 0x4b, 0x61, 0x4b, 0x78, 0x54, 0x73, 0x37, 0x65, 0x35, 0x31, 0x78, +0x71, 0x69, 0x6d, 0x74, 0x53, 0x5a, 0x4d, 0x7a, 0x7a, 0x49, 0x50, 0x75, 0x38, 0x72, 0x32, 0x78, +0x78, 0x55, 0x45, 0x38, 0x70, 0x47, 0x44, 0x30, 0x61, 0x4d, 0x33, 0x38, 0x2b, 0x2f, 0x59, 0x58, +0x45, 0x76, 0x50, 0x64, 0x66, 0x54, 0x4d, 0x69, 0x42, 0x4b, 0x58, 0x59, 0x52, 0x43, 0x6b, 0x73, +0x48, 0x34, 0x68, 0x68, 0x6a, 0x59, 0x50, 0x74, 0x32, 0x7a, 0x4b, 0x75, 0x76, 0x64, 0x6b, 0x33, +0x69, 0x65, 0x4f, 0x35, 0x35, 0x7a, 0x4f, 0x46, 0x48, 0x59, 0x48, 0x72, 0x33, 0x6a, 0x6c, 0x38, +0x76, 0x70, 0x61, 0x52, 0x79, 0x6e, 0x33, 0x30, 0x77, 0x31, 0x39, 0x2b, 0x49, 0x32, 0x74, 0x67, +0x51, 0x31, 0x31, 0x5a, 0x49, 0x79, 0x5a, 0x33, 0x52, 0x64, 0x69, 0x37, 0x7a, 0x49, 0x6d, 0x51, +0x70, 0x78, 0x51, 0x30, 0x66, 0x58, 0x63, 0x44, 0x74, 0x4d, 0x59, 0x32, 0x4f, 0x78, 0x71, 0x77, +0x41, 0x4b, 0x6b, 0x57, 0x6b, 0x58, 0x31, 0x39, 0x4b, 0x50, 0x33, 0x7a, 0x58, 0x33, 0x6a, 0x67, +0x74, 0x67, 0x53, 0x63, 0x38, 0x55, 0x75, 0x41, 0x4e, 0x46, 0x4d, 0x6a, 0x35, 0x7a, 0x68, 0x73, +0x38, 0x78, 0x43, 0x63, 0x38, 0x7a, 0x45, 0x64, 0x39, 0x4c, 0x4f, 0x4c, 0x4a, 0x52, 0x41, 0x45, +0x51, 0x49, 0x2f, 0x6c, 0x36, 0x7a, 0x35, 0x6c, 0x4d, 0x42, 0x61, 0x4e, 0x47, 0x45, 0x56, 0x32, +0x2b, 0x6e, 0x46, 0x35, 0x54, 0x72, 0x38, 0x50, 0x67, 0x73, 0x65, 0x47, 0x50, 0x66, 0x79, 0x42, +0x6e, 0x38, 0x42, 0x43, 0x61, 0x5a, 0x38, 0x2f, 0x75, 0x41, 0x75, 0x57, 0x4d, 0x41, 0x43, 0x45, +0x50, 0x5a, 0x4d, 0x78, 0x48, 0x75, 0x7a, 0x78, 0x5a, 0x45, 0x2f, 0x50, 0x78, 0x66, 0x6c, 0x2b, +0x41, 0x36, 0x57, 0x33, 0x4c, 0x6c, 0x6f, 0x66, 0x2f, 0x6b, 0x49, 0x65, 0x38, 0x71, 0x38, 0x56, +0x4f, 0x77, 0x6d, 0x67, 0x6e, 0x52, 0x67, 0x6a, 0x43, 0x63, 0x55, 0x6f, 0x6f, 0x6d, 0x4c, 0x7a, +0x76, 0x46, 0x4d, 0x4c, 0x68, 0x4d, 0x44, 0x66, 0x4e, 0x76, 0x5a, 0x6e, 0x4c, 0x39, 0x35, 0x6e, +0x43, 0x54, 0x58, 0x4e, 0x75, 0x34, 0x5a, 0x6a, 0x42, 0x78, 0x33, 0x4c, 0x43, 0x37, 0x69, 0x64, +0x54, 0x35, 0x4f, 0x56, 0x6b, 0x36, 0x50, 0x39, 0x55, 0x47, 0x59, 0x68, 0x44, 0x55, 0x64, 0x32, +0x57, 0x62, 0x57, 0x41, 0x50, 0x77, 0x53, 0x6c, 0x46, 0x67, 0x6e, 0x2f, 0x63, 0x4a, 0x6c, 0x69, +0x79, 0x55, 0x69, 0x43, 0x45, 0x54, 0x39, 0x76, 0x4d, 0x35, 0x38, 0x6a, 0x79, 0x47, 0x6a, 0x6c, +0x6a, 0x2f, 0x4c, 0x38, 0x70, 0x76, 0x6c, 0x39, 0x67, 0x64, 0x6a, 0x67, 0x6f, 0x4b, 0x71, 0x43, +0x56, 0x49, 0x6e, 0x4c, 0x69, 0x69, 0x65, 0x6a, 0x6c, 0x79, 0x77, 0x6b, 0x5a, 0x6a, 0x66, 0x6a, +0x6d, 0x57, 0x38, 0x49, 0x6e, 0x6e, 0x6f, 0x6a, 0x34, 0x36, 0x43, 0x4e, 0x30, 0x57, 0x33, 0x75, +0x4b, 0x35, 0x52, 0x54, 0x30, 0x58, 0x7a, 0x67, 0x74, 0x46, 0x32, 0x50, 0x51, 0x6f, 0x45, 0x47, +0x63, 0x66, 0x66, 0x62, 0x5a, 0x35, 0x42, 0x63, 0x56, 0x30, 0x66, 0x48, 0x42, 0x48, 0x48, 0x4a, +0x6e, 0x7a, 0x72, 0x51, 0x5a, 0x62, 0x7a, 0x4a, 0x45, 0x62, 0x4e, 0x62, 0x6e, 0x6c, 0x50, 0x5a, +0x39, 0x67, 0x51, 0x4e, 0x4f, 0x4f, 0x35, 0x32, 0x52, 0x77, 0x34, 0x5a, 0x54, 0x30, 0x39, 0x74, +0x53, 0x78, 0x47, 0x73, 0x70, 0x4b, 0x66, 0x7a, 0x62, 0x77, 0x31, 0x32, 0x46, 0x47, 0x6b, 0x41, +0x2b, 0x42, 0x38, 0x76, 0x65, 0x74, 0x48, 0x76, 0x4a, 0x49, 0x65, 0x64, 0x44, 0x31, 0x73, 0x54, +0x4d, 0x35, 0x7a, 0x33, 0x36, 0x69, 0x4e, 0x75, 0x79, 0x53, 0x6d, 0x52, 0x55, 0x4d, 0x71, 0x5a, +0x38, 0x44, 0x44, 0x58, 0x56, 0x4e, 0x62, 0x74, 0x51, 0x6e, 0x6f, 0x6b, 0x46, 0x62, 0x45, 0x7a, +0x68, 0x47, 0x47, 0x36, 0x61, 0x39, 0x7a, 0x61, 0x68, 0x33, 0x44, 0x78, 0x65, 0x2f, 0x51, 0x45, +0x47, 0x68, 0x59, 0x6f, 0x4a, 0x43, 0x38, 0x57, 0x4d, 0x74, 0x68, 0x34, 0x63, 0x30, 0x6a, 0x63, +0x58, 0x58, 0x32, 0x78, 0x41, 0x53, 0x34, 0x58, 0x76, 0x47, 0x38, 0x7a, 0x6c, 0x4e, 0x39, 0x4c, +0x32, 0x7a, 0x6c, 0x74, 0x6f, 0x47, 0x61, 0x58, 0x67, 0x75, 0x6a, 0x73, 0x52, 0x4c, 0x36, 0x39, +0x78, 0x66, 0x61, 0x2f, 0x70, 0x5a, 0x56, 0x5a, 0x7a, 0x75, 0x37, 0x34, 0x61, 0x6a, 0x4d, 0x45, +0x7a, 0x41, 0x6b, 0x38, 0x4c, 0x38, 0x6b, 0x77, 0x7a, 0x77, 0x38, 0x30, 0x6e, 0x47, 0x47, 0x49, +0x55, 0x73, 0x35, 0x47, 0x39, 0x7a, 0x62, 0x76, 0x4d, 0x31, 0x67, 0x66, 0x52, 0x72, 0x49, 0x74, +0x74, 0x64, 0x6d, 0x45, 0x51, 0x6e, 0x6e, 0x46, 0x62, 0x54, 0x46, 0x39, 0x37, 0x4e, 0x6a, 0x67, +0x68, 0x46, 0x61, 0x47, 0x51, 0x78, 0x39, 0x55, 0x54, 0x2b, 0x31, 0x43, 0x55, 0x62, 0x38, 0x50, +0x54, 0x31, 0x35, 0x37, 0x64, 0x6c, 0x34, 0x76, 0x75, 0x58, 0x63, 0x6e, 0x4f, 0x4e, 0x6f, 0x58, +0x52, 0x48, 0x6b, 0x4a, 0x36, 0x78, 0x4c, 0x52, 0x6e, 0x2f, 0x30, 0x41, 0x6f, 0x46, 0x47, 0x64, +0x67, 0x73, 0x64, 0x50, 0x43, 0x77, 0x32, 0x42, 0x34, 0x62, 0x39, 0x56, 0x4d, 0x76, 0x74, 0x33, +0x38, 0x48, 0x53, 0x32, 0x78, 0x56, 0x71, 0x70, 0x58, 0x76, 0x73, 0x64, 0x76, 0x39, 0x35, 0x70, +0x6f, 0x61, 0x7a, 0x55, 0x6b, 0x6e, 0x53, 0x65, 0x31, 0x49, 0x77, 0x56, 0x6c, 0x30, 0x43, 0x44, +0x4d, 0x75, 0x65, 0x64, 0x69, 0x48, 0x6e, 0x34, 0x59, 0x33, 0x76, 0x38, 0x41, 0x30, 0x39, 0x6c, +0x68, 0x65, 0x66, 0x69, 0x32, 0x62, 0x73, 0x4e, 0x4d, 0x76, 0x69, 0x79, 0x7a, 0x41, 0x6e, 0x43, +0x46, 0x4f, 0x62, 0x71, 0x77, 0x41, 0x6d, 0x2f, 0x65, 0x6a, 0x47, 0x6c, 0x75, 0x37, 0x6c, 0x6f, +0x56, 0x57, 0x46, 0x6a, 0x65, 0x50, 0x31, 0x4e, 0x54, 0x45, 0x37, 0x39, 0x65, 0x61, 0x30, 0x30, +0x48, 0x6b, 0x4e, 0x73, 0x52, 0x52, 0x62, 0x57, 0x32, 0x78, 0x53, 0x32, 0x47, 0x6b, 0x4a, 0x5a, +0x73, 0x46, 0x35, 0x32, 0x6f, 0x72, 0x46, 0x79, 0x4d, 0x55, 0x47, 0x7a, 0x74, 0x36, 0x45, 0x54, +0x35, 0x42, 0x68, 0x50, 0x7a, 0x58, 0x54, 0x4b, 0x4f, 0x44, 0x39, 0x46, 0x59, 0x33, 0x44, 0x2b, +0x62, 0x7a, 0x4f, 0x70, 0x71, 0x68, 0x4d, 0x54, 0x72, 0x49, 0x54, 0x42, 0x68, 0x48, 0x37, 0x50, +0x5a, 0x4a, 0x75, 0x2b, 0x45, 0x68, 0x76, 0x71, 0x59, 0x50, 0x71, 0x6c, 0x62, 0x67, 0x41, 0x43, +0x49, 0x49, 0x51, 0x45, 0x64, 0x73, 0x50, 0x42, 0x49, 0x69, 0x52, 0x63, 0x4f, 0x55, 0x33, 0x37, +0x42, 0x68, 0x54, 0x52, 0x2f, 0x38, 0x41, 0x48, 0x6b, 0x57, 0x6a, 0x36, 0x42, 0x34, 0x68, 0x4e, +0x50, 0x70, 0x75, 0x69, 0x49, 0x49, 0x32, 0x69, 0x61, 0x2b, 0x77, 0x6e, 0x53, 0x62, 0x34, 0x6b, +0x4c, 0x63, 0x42, 0x52, 0x6f, 0x2b, 0x38, 0x75, 0x39, 0x6c, 0x4b, 0x6b, 0x6d, 0x53, 0x69, 0x36, +0x63, 0x6a, 0x47, 0x35, 0x72, 0x70, 0x66, 0x32, 0x66, 0x6a, 0x35, 0x41, 0x2f, 0x39, 0x55, 0x35, +0x30, 0x7a, 0x33, 0x78, 0x4d, 0x39, 0x42, 0x72, 0x72, 0x53, 0x78, 0x6a, 0x77, 0x4a, 0x37, 0x4c, +0x75, 0x4c, 0x61, 0x4a, 0x35, 0x38, 0x69, 0x54, 0x4b, 0x48, 0x6e, 0x6b, 0x65, 0x6b, 0x35, 0x4e, +0x4e, 0x35, 0x35, 0x33, 0x58, 0x30, 0x48, 0x62, 0x55, 0x42, 0x4f, 0x41, 0x44, 0x41, 0x4c, 0x35, +0x6f, 0x2b, 0x49, 0x4c, 0x4f, 0x57, 0x41, 0x64, 0x39, 0x43, 0x76, 0x76, 0x51, 0x4b, 0x64, 0x74, +0x35, 0x34, 0x62, 0x74, 0x6e, 0x71, 0x56, 0x2f, 0x36, 0x43, 0x56, 0x65, 0x4f, 0x75, 0x39, 0x7a, +0x56, 0x4d, 0x7a, 0x54, 0x78, 0x50, 0x5a, 0x37, 0x57, 0x6d, 0x6c, 0x42, 0x57, 0x44, 0x6d, 0x30, +0x4c, 0x50, 0x37, 0x46, 0x78, 0x61, 0x4b, 0x30, 0x51, 0x76, 0x6f, 0x41, 0x73, 0x79, 0x55, 0x56, +0x44, 0x4a, 0x59, 0x57, 0x62, 0x42, 0x41, 0x39, 0x64, 0x37, 0x37, 0x4e, 0x75, 0x6b, 0x39, 0x32, +0x2b, 0x56, 0x5a, 0x62, 0x34, 0x54, 0x4c, 0x35, 0x59, 0x73, 0x48, 0x2f, 0x75, 0x76, 0x2b, 0x48, +0x33, 0x50, 0x71, 0x5a, 0x5a, 0x77, 0x49, 0x41, 0x45, 0x69, 0x68, 0x43, 0x70, 0x6f, 0x45, 0x63, +0x6c, 0x6f, 0x66, 0x78, 0x38, 0x59, 0x74, 0x4f, 0x6d, 0x6b, 0x58, 0x58, 0x32, 0x32, 0x5a, 0x6a, +0x43, 0x51, 0x71, 0x69, 0x73, 0x78, 0x47, 0x7a, 0x5a, 0x6b, 0x69, 0x72, 0x38, 0x61, 0x66, 0x32, +0x58, 0x50, 0x50, 0x36, 0x56, 0x6c, 0x5a, 0x55, 0x41, 0x76, 0x4e, 0x64, 0x59, 0x7a, 0x4e, 0x34, +0x79, 0x6a, 0x41, 0x6a, 0x6c, 0x63, 0x63, 0x74, 0x65, 0x6c, 0x39, 0x45, 0x51, 0x79, 0x32, 0x48, +0x71, 0x68, 0x6b, 0x58, 0x73, 0x6d, 0x5a, 0x4e, 0x44, 0x51, 0x65, 0x2f, 0x45, 0x2b, 0x4d, 0x75, +0x30, 0x42, 0x53, 0x53, 0x68, 0x30, 0x62, 0x62, 0x42, 0x6f, 0x6b, 0x64, 0x68, 0x38, 0x30, 0x62, +0x37, 0x76, 0x65, 0x4e, 0x52, 0x32, 0x50, 0x73, 0x6f, 0x43, 0x46, 0x64, 0x6c, 0x50, 0x44, 0x30, +0x5a, 0x43, 0x71, 0x76, 0x70, 0x42, 0x6f, 0x53, 0x56, 0x59, 0x66, 0x35, 0x71, 0x72, 0x57, 0x6c, +0x61, 0x73, 0x49, 0x41, 0x58, 0x2b, 0x2f, 0x58, 0x6b, 0x38, 0x2b, 0x58, 0x4e, 0x6a, 0x43, 0x69, +0x30, 0x59, 0x4c, 0x62, 0x50, 0x76, 0x2f, 0x69, 0x53, 0x68, 0x51, 0x50, 0x4b, 0x38, 0x58, 0x32, +0x4a, 0x49, 0x59, 0x62, 0x66, 0x6f, 0x58, 0x68, 0x36, 0x77, 0x54, 0x4f, 0x55, 0x6a, 0x70, 0x69, +0x49, 0x55, 0x70, 0x72, 0x4e, 0x6e, 0x7a, 0x32, 0x4b, 0x6a, 0x42, 0x35, 0x6f, 0x62, 0x36, 0x37, +0x42, 0x47, 0x4d, 0x56, 0x76, 0x7a, 0x4d, 0x4f, 0x38, 0x59, 0x50, 0x35, 0x49, 0x70, 0x64, 0x36, +0x43, 0x31, 0x49, 0x5a, 0x42, 0x5a, 0x68, 0x46, 0x66, 0x36, 0x37, 0x45, 0x63, 0x6f, 0x46, 0x39, +0x6e, 0x70, 0x79, 0x37, 0x6c, 0x42, 0x7a, 0x32, 0x43, 0x6b, 0x66, 0x70, 0x54, 0x5a, 0x70, 0x73, +0x6a, 0x48, 0x57, 0x32, 0x39, 0x4b, 0x34, 0x7a, 0x69, 0x61, 0x38, 0x74, 0x75, 0x4a, 0x4a, 0x56, +0x6c, 0x56, 0x6f, 0x34, 0x70, 0x65, 0x6c, 0x5a, 0x6b, 0x78, 0x59, 0x58, 0x66, 0x47, 0x45, 0x4e, +0x5a, 0x63, 0x5a, 0x69, 0x65, 0x70, 0x57, 0x47, 0x32, 0x62, 0x49, 0x76, 0x69, 0x68, 0x58, 0x41, +0x34, 0x42, 0x46, 0x65, 0x64, 0x4f, 0x31, 0x33, 0x2b, 0x67, 0x47, 0x38, 0x33, 0x66, 0x38, 0x66, +0x37, 0x53, 0x39, 0x35, 0x6c, 0x52, 0x2b, 0x63, 0x4f, 0x74, 0x4e, 0x4b, 0x38, 0x39, 0x64, 0x31, +0x30, 0x78, 0x6c, 0x61, 0x50, 0x59, 0x58, 0x6a, 0x56, 0x38, 0x43, 0x37, 0x50, 0x62, 0x37, 0x63, +0x41, 0x33, 0x33, 0x39, 0x76, 0x59, 0x5a, 0x4d, 0x66, 0x66, 0x51, 0x54, 0x43, 0x78, 0x35, 0x67, +0x49, 0x35, 0x72, 0x67, 0x54, 0x4d, 0x42, 0x64, 0x64, 0x30, 0x4c, 0x30, 0x47, 0x54, 0x62, 0x49, +0x43, 0x34, 0x72, 0x39, 0x6a, 0x6f, 0x45, 0x63, 0x50, 0x53, 0x2f, 0x2b, 0x64, 0x56, 0x6b, 0x6a, +0x45, 0x51, 0x46, 0x7a, 0x34, 0x67, 0x2b, 0x75, 0x31, 0x31, 0x6d, 0x51, 0x44, 0x6f, 0x5a, 0x43, +0x74, 0x7a, 0x36, 0x30, 0x39, 0x4d, 0x4a, 0x36, 0x48, 0x5a, 0x7a, 0x79, 0x61, 0x70, 0x41, 0x41, +0x54, 0x4a, 0x71, 0x51, 0x55, 0x68, 0x55, 0x72, 0x6a, 0x75, 0x59, 0x77, 0x38, 0x68, 0x4e, 0x30, +0x50, 0x65, 0x53, 0x6f, 0x78, 0x65, 0x5a, 0x4a, 0x5a, 0x58, 0x59, 0x32, 0x51, 0x71, 0x48, 0x57, +0x43, 0x79, 0x42, 0x34, 0x2b, 0x70, 0x6b, 0x52, 0x59, 0x5a, 0x47, 0x4b, 0x62, 0x51, 0x47, 0x39, +0x30, 0x79, 0x73, 0x4f, 0x31, 0x52, 0x34, 0x73, 0x6b, 0x31, 0x70, 0x73, 0x6b, 0x56, 0x74, 0x64, +0x77, 0x58, 0x6a, 0x47, 0x68, 0x34, 0x6d, 0x4b, 0x4b, 0x4a, 0x78, 0x78, 0x47, 0x71, 0x4c, 0x51, +0x4d, 0x34, 0x2f, 0x73, 0x55, 0x48, 0x33, 0x55, 0x55, 0x6f, 0x64, 0x4a, 0x53, 0x51, 0x74, 0x6c, +0x5a, 0x6c, 0x74, 0x63, 0x74, 0x79, 0x51, 0x4a, 0x34, 0x61, 0x55, 0x63, 0x4e, 0x55, 0x79, 0x37, +0x36, 0x48, 0x59, 0x2f, 0x4e, 0x6a, 0x6e, 0x4c, 0x73, 0x66, 0x6b, 0x4f, 0x70, 0x6d, 0x6e, 0x6f, +0x2f, 0x6a, 0x33, 0x34, 0x73, 0x32, 0x4f, 0x6c, 0x72, 0x4c, 0x6a, 0x72, 0x2b, 0x50, 0x70, 0x53, +0x6e, 0x6d, 0x44, 0x71, 0x74, 0x68, 0x51, 0x67, 0x2b, 0x4e, 0x7a, 0x2f, 0x34, 0x49, 0x70, 0x50, +0x66, 0x38, 0x47, 0x6c, 0x73, 0x38, 0x58, 0x6e, 0x6b, 0x32, 0x6f, 0x65, 0x35, 0x34, 0x38, 0x77, +0x48, 0x6f, 0x4e, 0x51, 0x71, 0x67, 0x4e, 0x45, 0x39, 0x52, 0x36, 0x4e, 0x51, 0x72, 0x47, 0x31, +0x65, 0x69, 0x39, 0x41, 0x2b, 0x68, 0x36, 0x7a, 0x7a, 0x4f, 0x65, 0x48, 0x37, 0x37, 0x32, 0x69, +0x61, 0x64, 0x69, 0x62, 0x4b, 0x64, 0x30, 0x6a, 0x4c, 0x41, 0x4a, 0x75, 0x75, 0x42, 0x4a, 0x48, +0x61, 0x4f, 0x70, 0x61, 0x2b, 0x73, 0x77, 0x43, 0x75, 0x42, 0x79, 0x55, 0x6c, 0x4e, 0x65, 0x57, +0x53, 0x73, 0x38, 0x70, 0x39, 0x6c, 0x73, 0x77, 0x2b, 0x6d, 0x50, 0x2b, 0x2b, 0x2f, 0x56, 0x2f, +0x71, 0x74, 0x2f, 0x6e, 0x34, 0x76, 0x71, 0x42, 0x58, 0x70, 0x63, 0x2b, 0x6a, 0x66, 0x78, 0x61, +0x55, 0x7a, 0x2f, 0x4d, 0x78, 0x6a, 0x34, 0x67, 0x75, 0x55, 0x4e, 0x52, 0x34, 0x2f, 0x32, 0x33, +0x65, 0x67, 0x70, 0x77, 0x7a, 0x6d, 0x38, 0x6a, 0x78, 0x78, 0x79, 0x4e, 0x6e, 0x7a, 0x43, 0x42, +0x79, 0x36, 0x71, 0x6e, 0x6f, 0x54, 0x5a, 0x74, 0x73, 0x53, 0x65, 0x71, 0x6b, 0x6c, 0x54, 0x2b, +0x39, 0x2f, 0x37, 0x52, 0x4f, 0x54, 0x4c, 0x37, 0x74, 0x32, 0x37, 0x64, 0x54, 0x57, 0x4a, 0x42, +0x50, 0x2b, 0x35, 0x43, 0x52, 0x58, 0x44, 0x4c, 0x6b, 0x57, 0x73, 0x4c, 0x5a, 0x57, 0x61, 0x7a, +0x50, 0x71, 0x61, 0x49, 0x70, 0x47, 0x6d, 0x50, 0x56, 0x33, 0x6f, 0x63, 0x7a, 0x70, 0x4c, 0x4f, +0x56, 0x78, 0x75, 0x33, 0x4e, 0x56, 0x46, 0x64, 0x58, 0x32, 0x2f, 0x6e, 0x54, 0x6e, 0x51, 0x49, +0x49, 0x39, 0x34, 0x43, 0x36, 0x53, 0x65, 0x43, 0x76, 0x73, 0x42, 0x49, 0x32, 0x59, 0x46, 0x4b, +0x33, 0x77, 0x67, 0x2b, 0x70, 0x55, 0x46, 0x6a, 0x31, 0x45, 0x34, 0x51, 0x2f, 0x65, 0x66, 0x36, +0x39, 0x2f, 0x4e, 0x6c, 0x47, 0x65, 0x68, 0x30, 0x75, 0x6b, 0x64, 0x4a, 0x6e, 0x51, 0x53, 0x4e, +0x49, 0x34, 0x53, 0x47, 0x4d, 0x59, 0x4d, 0x6e, 0x33, 0x47, 0x2f, 0x48, 0x39, 0x51, 0x6e, 0x78, +0x50, 0x6f, 0x30, 0x4f, 0x61, 0x55, 0x30, 0x36, 0x34, 0x6d, 0x61, 0x43, 0x6f, 0x68, 0x74, 0x37, +0x33, 0x48, 0x71, 0x36, 0x35, 0x7a, 0x5a, 0x57, 0x56, 0x6b, 0x31, 0x42, 0x76, 0x2b, 0x76, 0x4b, +0x63, 0x4f, 0x51, 0x4f, 0x74, 0x44, 0x53, 0x32, 0x36, 0x67, 0x46, 0x35, 0x6d, 0x46, 0x53, 0x50, +0x4e, 0x48, 0x50, 0x36, 0x74, 0x7a, 0x32, 0x47, 0x46, 0x48, 0x73, 0x41, 0x32, 0x58, 0x55, 0x36, +0x54, 0x4c, 0x75, 0x5a, 0x51, 0x38, 0x7a, 0x7a, 0x76, 0x36, 0x79, 0x4d, 0x53, 0x72, 0x4d, 0x67, +0x75, 0x47, 0x71, 0x43, 0x55, 0x74, 0x74, 0x77, 0x35, 0x72, 0x73, 0x54, 0x38, 0x35, 0x75, 0x32, +0x43, 0x6c, 0x6e, 0x5a, 0x4a, 0x59, 0x5a, 0x35, 0x6c, 0x38, 0x47, 0x31, 0x73, 0x46, 0x71, 0x7a, +0x62, 0x48, 0x48, 0x4f, 0x4c, 0x6c, 0x66, 0x4e, 0x50, 0x43, 0x52, 0x4e, 0x58, 0x41, 0x4d, 0x6e, +0x79, 0x5a, 0x77, 0x77, 0x38, 0x38, 0x73, 0x6e, 0x44, 0x4b, 0x4b, 0x4d, 0x77, 0x47, 0x6c, 0x76, +0x41, 0x42, 0x6f, 0x38, 0x37, 0x5a, 0x39, 0x33, 0x46, 0x30, 0x36, 0x63, 0x2b, 0x51, 0x79, 0x6a, +0x70, 0x2b, 0x61, 0x57, 0x55, 0x62, 0x67, 0x73, 0x67, 0x42, 0x47, 0x62, 0x6d, 0x54, 0x4a, 0x43, +0x53, 0x64, 0x59, 0x55, 0x2b, 0x74, 0x51, 0x63, 0x65, 0x73, 0x30, 0x76, 0x68, 0x44, 0x7a, 0x52, +0x4f, 0x4a, 0x75, 0x31, 0x6a, 0x4b, 0x69, 0x6f, 0x77, 0x76, 0x2f, 0x34, 0x31, 0x35, 0x70, 0x2f, +0x2f, 0x54, 0x4c, 0x55, 0x41, 0x54, 0x6a, 0x38, 0x64, 0x30, 0x37, 0x64, 0x76, 0x79, 0x76, 0x55, +0x41, 0x54, 0x55, 0x74, 0x6d, 0x55, 0x39, 0x35, 0x2f, 0x44, 0x45, 0x71, 0x70, 0x65, 0x4f, 0x4f, +0x30, 0x30, 0x54, 0x79, 0x38, 0x65, 0x54, 0x30, 0x38, 0x2f, 0x42, 0x51, 0x68, 0x71, 0x62, 0x6a, +0x31, 0x6a, 0x78, 0x50, 0x4a, 0x72, 0x75, 0x35, 0x4c, 0x6e, 0x4e, 0x35, 0x61, 0x47, 0x79, 0x4c, +0x68, 0x43, 0x45, 0x32, 0x66, 0x76, 0x49, 0x77, 0x2b, 0x59, 0x55, 0x72, 0x69, 0x48, 0x6c, 0x4a, +0x61, 0x59, 0x4d, 0x63, 0x69, 0x67, 0x62, 0x65, 0x37, 0x54, 0x32, 0x69, 0x55, 0x77, 0x43, 0x69, +0x42, 0x2b, 0x74, 0x35, 0x48, 0x7a, 0x42, 0x61, 0x59, 0x57, 0x45, 0x44, 0x50, 0x4c, 0x65, 0x4f, +0x46, 0x4f, 0x54, 0x54, 0x45, 0x73, 0x2f, 0x7a, 0x51, 0x69, 0x70, 0x71, 0x2f, 0x33, 0x41, 0x2b, +0x41, 0x6c, 0x35, 0x56, 0x6c, 0x6e, 0x79, 0x73, 0x53, 0x77, 0x63, 0x76, 0x4a, 0x77, 0x51, 0x42, +0x39, 0x6e, 0x33, 0x2b, 0x65, 0x46, 0x51, 0x65, 0x4d, 0x74, 0x77, 0x6b, 0x5a, 0x62, 0x67, 0x55, +0x73, 0x37, 0x6c, 0x76, 0x46, 0x4d, 0x33, 0x4d, 0x36, 0x2b, 0x64, 0x56, 0x2b, 0x5a, 0x61, 0x7a, +0x59, 0x32, 0x4d, 0x48, 0x6a, 0x43, 0x32, 0x4a, 0x4d, 0x4f, 0x72, 0x59, 0x61, 0x62, 0x54, 0x52, +0x2f, 0x66, 0x6d, 0x49, 0x6a, 0x57, 0x6d, 0x6e, 0x2b, 0x63, 0x48, 0x49, 0x4e, 0x33, 0x36, 0x31, +0x73, 0x34, 0x39, 0x4c, 0x6e, 0x47, 0x70, 0x6c, 0x79, 0x56, 0x69, 0x31, 0x61, 0x61, 0x65, 0x35, +0x37, 0x65, 0x7a, 0x76, 0x39, 0x52, 0x39, 0x65, 0x78, 0x4d, 0x41, 0x72, 0x58, 0x66, 0x7a, 0x53, +0x56, 0x6d, 0x33, 0x35, 0x78, 0x43, 0x37, 0x66, 0x2b, 0x38, 0x6c, 0x62, 0x75, 0x65, 0x50, 0x31, +0x69, 0x4c, 0x6c, 0x38, 0x71, 0x32, 0x48, 0x2b, 0x44, 0x51, 0x30, 0x42, 0x6d, 0x43, 0x2f, 0x42, +0x38, 0x76, 0x4a, 0x43, 0x41, 0x6b, 0x49, 0x38, 0x58, 0x74, 0x6c, 0x75, 0x6b, 0x55, 0x49, 0x36, +0x30, 0x65, 0x2f, 0x41, 0x51, 0x6e, 0x4e, 0x78, 0x66, 0x45, 0x47, 0x6e, 0x77, 0x57, 0x54, 0x78, +0x6e, 0x41, 0x73, 0x63, 0x63, 0x64, 0x77, 0x62, 0x62, 0x64, 0x6b, 0x42, 0x30, 0x31, 0x69, 0x76, +0x6b, 0x35, 0x67, 0x71, 0x65, 0x75, 0x6c, 0x54, 0x67, 0x54, 0x66, 0x45, 0x78, 0x57, 0x35, 0x4a, +0x53, 0x75, 0x5a, 0x4f, 0x67, 0x71, 0x4c, 0x6a, 0x78, 0x39, 0x35, 0x39, 0x2f, 0x6e, 0x75, 0x79, +0x7a, 0x7a, 0x38, 0x5a, 0x55, 0x39, 0x79, 0x49, 0x79, 0x65, 0x44, 0x43, 0x78, 0x36, 0x36, 0x2f, +0x48, 0x4e, 0x44, 0x59, 0x6d, 0x47, 0x4a, 0x4e, 0x46, 0x59, 0x76, 0x39, 0x76, 0x58, 0x50, 0x2b, +0x46, 0x6e, 0x41, 0x59, 0x77, 0x78, 0x72, 0x42, 0x73, 0x32, 0x54, 0x4a, 0x65, 0x65, 0x65, 0x55, +0x56, 0x64, 0x68, 0x38, 0x2b, 0x6a, 0x43, 0x4e, 0x2f, 0x64, 0x51, 0x4a, 0x66, 0x72, 0x78, 0x72, +0x45, 0x78, 0x39, 0x2b, 0x30, 0x51, 0x6d, 0x65, 0x55, 0x51, 0x30, 0x66, 0x6b, 0x4d, 0x4f, 0x47, +0x51, 0x58, 0x73, 0x79, 0x61, 0x2b, 0x52, 0x61, 0x76, 0x76, 0x66, 0x34, 0x6d, 0x35, 0x35, 0x35, +0x37, 0x4c, 0x76, 0x76, 0x75, 0x75, 0x79, 0x39, 0x61, 0x61, 0x36, 0x36, 0x59, 0x63, 0x55, 0x64, +0x58, 0x67, 0x54, 0x59, 0x52, 0x38, 0x72, 0x30, 0x4f, 0x2b, 0x73, 0x56, 0x47, 0x59, 0x34, 0x44, +0x31, 0x72, 0x56, 0x76, 0x6f, 0x4d, 0x50, 0x63, 0x51, 0x39, 0x6d, 0x53, 0x58, 0x63, 0x34, 0x45, +0x34, 0x59, 0x74, 0x41, 0x67, 0x6b, 0x5a, 0x39, 0x2b, 0x69, 0x69, 0x34, 0x76, 0x74, 0x33, 0x6e, +0x35, 0x53, 0x69, 0x63, 0x53, 0x75, 0x37, 0x52, 0x31, 0x72, 0x71, 0x45, 0x74, 0x36, 0x55, 0x79, +0x6f, 0x73, 0x4a, 0x43, 0x32, 0x78, 0x78, 0x34, 0x44, 0x66, 0x49, 0x51, 0x78, 0x2b, 0x41, 0x45, +0x58, 0x6f, 0x70, 0x54, 0x34, 0x51, 0x75, 0x45, 0x62, 0x45, 0x4a, 0x35, 0x47, 0x52, 0x44, 0x56, +0x33, 0x6e, 0x4e, 0x5a, 0x43, 0x31, 0x71, 0x70, 0x48, 0x65, 0x4f, 0x4c, 0x7a, 0x46, 0x53, 0x67, +0x70, 0x6d, 0x54, 0x53, 0x71, 0x44, 0x31, 0x4e, 0x2f, 0x58, 0x63, 0x4e, 0x78, 0x30, 0x77, 0x46, +0x70, 0x55, 0x36, 0x68, 0x50, 0x31, 0x2f, 0x66, 0x7a, 0x6e, 0x4a, 0x37, 0x43, 0x64, 0x6c, 0x4e, +0x45, 0x6e, 0x69, 0x35, 0x67, 0x6a, 0x52, 0x37, 0x49, 0x55, 0x65, 0x61, 0x66, 0x46, 0x4a, 0x73, +0x74, 0x66, 0x47, 0x58, 0x32, 0x34, 0x55, 0x44, 0x7a, 0x4b, 0x6e, 0x50, 0x6a, 0x77, 0x6d, 0x2f, +0x4a, 0x58, 0x39, 0x41, 0x57, 0x59, 0x79, 0x4e, 0x64, 0x56, 0x45, 0x6b, 0x36, 0x51, 0x70, 0x32, +0x64, 0x6e, 0x5a, 0x4a, 0x72, 0x48, 0x31, 0x33, 0x48, 0x65, 0x63, 0x64, 0x5a, 0x70, 0x66, 0x66, +0x77, 0x71, 0x77, 0x31, 0x73, 0x61, 0x5a, 0x4b, 0x45, 0x50, 0x42, 0x75, 0x57, 0x56, 0x56, 0x4c, +0x48, 0x67, 0x55, 0x6a, 0x4a, 0x43, 0x73, 0x41, 0x4a, 0x46, 0x67, 0x38, 0x64, 0x39, 0x78, 0x44, +0x31, 0x72, 0x5a, 0x76, 0x34, 0x2f, 0x61, 0x76, 0x6e, 0x6f, 0x59, 0x7a, 0x69, 0x2f, 0x44, 0x47, +0x54, 0x47, 0x4e, 0x74, 0x33, 0x48, 0x45, 0x6f, 0x4c, 0x50, 0x4d, 0x49, 0x70, 0x38, 0x68, 0x66, +0x52, 0x4a, 0x46, 0x68, 0x56, 0x50, 0x39, 0x68, 0x4e, 0x38, 0x4f, 0x43, 0x52, 0x32, 0x51, 0x6a, +0x31, 0x42, 0x76, 0x37, 0x62, 0x4c, 0x36, 0x64, 0x69, 0x38, 0x65, 0x4f, 0x68, 0x46, 0x45, 0x75, +0x38, 0x4f, 0x62, 0x43, 0x6b, 0x6a, 0x6b, 0x39, 0x76, 0x2b, 0x35, 0x53, 0x64, 0x48, 0x2b, 0x39, +0x4d, 0x2b, 0x59, 0x50, 0x47, 0x47, 0x4d, 0x79, 0x6b, 0x53, 0x5a, 0x62, 0x72, 0x2f, 0x2f, 0x33, +0x33, 0x37, 0x61, 0x54, 0x37, 0x78, 0x53, 0x39, 0x53, 0x2f, 0x41, 0x6e, 0x42, 0x49, 0x61, 0x56, +0x6b, 0x72, 0x33, 0x38, 0x64, 0x7a, 0x4d, 0x56, 0x48, 0x58, 0x38, 0x4c, 0x53, 0x31, 0x6d, 0x55, +0x4f, 0x2f, 0x65, 0x66, 0x6a, 0x61, 0x30, 0x4f, 0x4f, 0x7a, 0x6d, 0x50, 0x76, 0x50, 0x67, 0x4c, +0x50, 0x46, 0x33, 0x7a, 0x34, 0x7a, 0x52, 0x64, 0x73, 0x58, 0x39, 0x53, 0x49, 0x72, 0x7a, 0x73, +0x73, 0x46, 0x46, 0x67, 0x72, 0x64, 0x69, 0x38, 0x5a, 0x78, 0x6f, 0x4b, 0x37, 0x35, 0x72, 0x4f, +0x46, 0x4a, 0x43, 0x68, 0x79, 0x6b, 0x73, 0x4b, 0x4a, 0x2f, 0x74, 0x30, 0x6e, 0x74, 0x4b, 0x66, +0x41, 0x52, 0x48, 0x33, 0x6b, 0x51, 0x6f, 0x46, 0x75, 0x64, 0x71, 0x75, 0x59, 0x54, 0x49, 0x55, +0x69, 0x48, 0x38, 0x6f, 0x7a, 0x2f, 0x4b, 0x6c, 0x6d, 0x44, 0x4f, 0x74, 0x30, 0x68, 0x78, 0x32, +0x45, 0x47, 0x78, 0x6f, 0x51, 0x59, 0x6f, 0x50, 0x7a, 0x2b, 0x43, 0x74, 0x38, 0x6b, 0x59, 0x51, +0x44, 0x56, 0x77, 0x59, 0x78, 0x38, 0x42, 0x6d, 0x6b, 0x55, 0x76, 0x53, 0x76, 0x4c, 0x57, 0x44, +0x57, 0x6f, 0x6c, 0x66, 0x67, 0x6e, 0x68, 0x39, 0x59, 0x50, 0x57, 0x64, 0x66, 0x2f, 0x76, 0x6d, +0x66, 0x42, 0x6b, 0x34, 0x2f, 0x73, 0x6f, 0x70, 0x44, 0x78, 0x70, 0x59, 0x79, 0x37, 0x63, 0x32, +0x4e, 0x43, 0x4b, 0x47, 0x35, 0x36, 0x44, 0x63, 0x31, 0x61, 0x47, 0x31, 0x34, 0x35, 0x4b, 0x58, +0x31, 0x53, 0x4b, 0x57, 0x35, 0x38, 0x71, 0x78, 0x61, 0x66, 0x6c, 0x6a, 0x54, 0x78, 0x6f, 0x78, +0x50, 0x47, 0x37, 0x6e, 0x6d, 0x6e, 0x44, 0x70, 0x2b, 0x38, 0x59, 0x39, 0x47, 0x47, 0x47, 0x66, +0x37, 0x34, 0x70, 0x70, 0x5a, 0x56, 0x31, 0x4f, 0x37, 0x74, 0x51, 0x65, 0x2f, 0x61, 0x50, 0x34, +0x54, 0x4b, 0x2f, 0x70, 0x56, 0x73, 0x72, 0x79, 0x76, 0x77, 0x31, 0x41, 0x34, 0x70, 0x36, 0x63, +0x78, 0x78, 0x6a, 0x6c, 0x35, 0x4e, 0x47, 0x67, 0x49, 0x35, 0x2b, 0x57, 0x78, 0x76, 0x76, 0x64, +0x61, 0x2f, 0x6e, 0x6e, 0x51, 0x36, 0x63, 0x79, 0x64, 0x4a, 0x76, 0x6e, 0x75, 0x57, 0x34, 0x48, +0x51, 0x63, 0x7a, 0x6e, 0x77, 0x6f, 0x47, 0x4f, 0x59, 0x39, 0x2f, 0x47, 0x2f, 0x75, 0x66, 0x31, +0x79, 0x6e, 0x34, 0x48, 0x4c, 0x42, 0x4f, 0x62, 0x38, 0x74, 0x4b, 0x31, 0x59, 0x47, 0x68, 0x52, +0x56, 0x41, 0x72, 0x71, 0x77, 0x45, 0x4c, 0x31, 0x2b, 0x50, 0x52, 0x31, 0x33, 0x33, 0x6d, 0x55, +0x6a, 0x41, 0x63, 0x5a, 0x67, 0x32, 0x74, 0x6f, 0x68, 0x50, 0x78, 0x2b, 0x54, 0x6c, 0x5a, 0x56, +0x53, 0x55, 0x46, 0x57, 0x37, 0x43, 0x49, 0x63, 0x75, 0x4b, 0x34, 0x74, 0x48, 0x78, 0x73, 0x47, +0x47, 0x67, 0x6f, 0x30, 0x78, 0x66, 0x50, 0x54, 0x78, 0x58, 0x49, 0x59, 0x4e, 0x48, 0x38, 0x62, +0x31, 0x70, 0x77, 0x7a, 0x6d, 0x32, 0x7a, 0x45, 0x35, 0x53, 0x47, 0x55, 0x59, 0x32, 0x54, 0x2b, +0x48, 0x31, 0x61, 0x75, 0x58, 0x38, 0x65, 0x71, 0x2f, 0x33, 0x36, 0x43, 0x69, 0x6f, 0x6f, 0x4c, +0x53, 0x55, 0x70, 0x74, 0x63, 0x4a, 0x4c, 0x58, 0x6d, 0x6f, 0x55, 0x2b, 0x66, 0x37, 0x69, 0x4c, +0x51, 0x42, 0x76, 0x44, 0x43, 0x2b, 0x52, 0x54, 0x6b, 0x56, 0x67, 0x44, 0x51, 0x45, 0x58, 0x30, +0x44, 0x72, 0x54, 0x72, 0x49, 0x68, 0x4d, 0x73, 0x4d, 0x35, 0x6c, 0x45, 0x45, 0x77, 0x54, 0x55, +0x64, 0x67, 0x6e, 0x36, 0x50, 0x50, 0x6b, 0x70, 0x48, 0x55, 0x74, 0x4a, 0x4e, 0x33, 0x48, 0x49, +0x52, 0x71, 0x65, 0x4d, 0x66, 0x48, 0x6a, 0x53, 0x49, 0x70, 0x6d, 0x2b, 0x2b, 0x41, 0x63, 0x59, +0x37, 0x77, 0x51, 0x39, 0x59, 0x6b, 0x5a, 0x56, 0x56, 0x41, 0x45, 0x4a, 0x61, 0x5a, 0x53, 0x41, +0x56, 0x4e, 0x37, 0x32, 0x53, 0x77, 0x2f, 0x35, 0x37, 0x47, 0x6b, 0x37, 0x65, 0x63, 0x77, 0x44, +0x74, 0x41, 0x76, 0x34, 0x35, 0x7a, 0x32, 0x50, 0x31, 0x35, 0x68, 0x78, 0x33, 0x64, 0x30, 0x32, +0x4e, 0x58, 0x73, 0x48, 0x56, 0x2b, 0x69, 0x5a, 0x77, 0x5a, 0x4b, 0x65, 0x72, 0x39, 0x43, 0x43, +0x57, 0x36, 0x49, 0x45, 0x55, 0x36, 0x71, 0x30, 0x63, 0x5a, 0x61, 0x5a, 0x52, 0x71, 0x6a, 0x66, +0x79, 0x68, 0x4c, 0x71, 0x4f, 0x75, 0x65, 0x59, 0x67, 0x36, 0x77, 0x54, 0x55, 0x57, 0x46, 0x4a, +0x55, 0x44, 0x63, 0x66, 0x75, 0x76, 0x49, 0x64, 0x78, 0x6d, 0x2f, 0x37, 0x41, 0x6f, 0x49, 0x33, +0x62, 0x55, 0x4d, 0x37, 0x72, 0x4c, 0x34, 0x58, 0x45, 0x58, 0x79, 0x48, 0x34, 0x65, 0x4b, 0x35, +0x45, 0x43, 0x73, 0x56, 0x51, 0x6f, 0x52, 0x6c, 0x75, 0x37, 0x50, 0x38, 0x70, 0x4a, 0x56, 0x46, +0x53, 0x55, 0x79, 0x46, 0x36, 0x4d, 0x49, 0x4d, 0x62, 0x69, 0x51, 0x36, 0x34, 0x6b, 0x59, 0x37, +0x72, 0x4c, 0x6b, 0x61, 0x74, 0x58, 0x35, 0x76, 0x49, 0x75, 0x52, 0x47, 0x43, 0x4d, 0x6a, 0x2f, +0x47, 0x4b, 0x31, 0x49, 0x67, 0x2f, 0x52, 0x6a, 0x65, 0x53, 0x7a, 0x64, 0x6a, 0x70, 0x4b, 0x51, +0x39, 0x71, 0x4c, 0x71, 0x6c, 0x4a, 0x4a, 0x46, 0x2b, 0x64, 0x62, 0x54, 0x4d, 0x57, 0x47, 0x41, +0x56, 0x77, 0x4d, 0x35, 0x73, 0x79, 0x62, 0x39, 0x50, 0x72, 0x57, 0x62, 0x52, 0x77, 0x43, 0x79, +0x71, 0x48, 0x51, 0x77, 0x30, 0x44, 0x73, 0x56, 0x31, 0x30, 0x46, 0x42, 0x6c, 0x4a, 0x45, 0x4b, +0x6e, 0x51, 0x55, 0x46, 0x6c, 0x59, 0x67, 0x75, 0x51, 0x72, 0x41, 0x54, 0x77, 0x50, 0x44, 0x6a, +0x6c, 0x46, 0x4c, 0x79, 0x54, 0x54, 0x37, 0x5a, 0x4f, 0x48, 0x4d, 0x39, 0x4c, 0x51, 0x71, 0x38, +0x6b, 0x6f, 0x4c, 0x53, 0x41, 0x79, 0x77, 0x55, 0x51, 0x39, 0x4d, 0x2f, 0x74, 0x6d, 0x38, 0x4c, +0x69, 0x4b, 0x72, 0x52, 0x67, 0x7a, 0x65, 0x37, 0x32, 0x63, 0x79, 0x38, 0x6c, 0x36, 0x61, 0x45, +0x4c, 0x4d, 0x63, 0x62, 0x43, 0x4c, 0x70, 0x57, 0x52, 0x61, 0x4b, 0x55, 0x68, 0x47, 0x71, 0x7a, +0x67, 0x6c, 0x70, 0x58, 0x56, 0x77, 0x6f, 0x2b, 0x54, 0x6f, 0x4d, 0x68, 0x72, 0x33, 0x47, 0x70, +0x56, 0x4a, 0x76, 0x43, 0x4b, 0x6b, 0x71, 0x44, 0x49, 0x4b, 0x67, 0x6d, 0x4b, 0x54, 0x44, 0x45, +0x74, 0x49, 0x6f, 0x65, 0x69, 0x79, 0x71, 0x78, 0x34, 0x47, 0x6e, 0x4d, 0x79, 0x63, 0x35, 0x46, +0x77, 0x4c, 0x4b, 0x72, 0x4a, 0x6a, 0x4b, 0x70, 0x4b, 0x47, 0x31, 0x71, 0x55, 0x41, 0x53, 0x6f, +0x35, 0x36, 0x66, 0x42, 0x65, 0x76, 0x44, 0x4f, 0x33, 0x6b, 0x51, 0x6e, 0x37, 0x6c, 0x54, 0x50, +0x6a, 0x30, 0x78, 0x31, 0x49, 0x70, 0x54, 0x6e, 0x71, 0x67, 0x42, 0x35, 0x6f, 0x72, 0x58, 0x6c, +0x7a, 0x64, 0x69, 0x4e, 0x53, 0x61, 0x61, 0x61, 0x63, 0x31, 0x59, 0x38, 0x31, 0x39, 0x5a, 0x32, +0x38, 0x4d, 0x6e, 0x4d, 0x62, 0x2b, 0x34, 0x38, 0x71, 0x35, 0x70, 0x54, 0x44, 0x71, 0x33, 0x6e, +0x36, 0x7a, 0x58, 0x6f, 0x36, 0x56, 0x79, 0x32, 0x46, 0x55, 0x53, 0x44, 0x38, 0x41, 0x6f, 0x71, +0x6a, 0x70, 0x79, 0x4a, 0x7a, 0x44, 0x32, 0x42, 0x6c, 0x62, 0x34, 0x67, 0x71, 0x34, 0x32, 0x44, +0x58, 0x78, 0x4d, 0x6c, 0x56, 0x6c, 0x4f, 0x50, 0x4f, 0x44, 0x36, 0x72, 0x77, 0x61, 0x41, 0x31, +0x76, 0x50, 0x56, 0x77, 0x46, 0x44, 0x38, 0x4d, 0x66, 0x4c, 0x70, 0x41, 0x55, 0x6c, 0x6c, 0x53, +0x54, 0x6d, 0x79, 0x31, 0x34, 0x37, 0x4b, 0x47, 0x70, 0x50, 0x48, 0x4e, 0x44, 0x44, 0x56, 0x6d, +0x66, 0x43, 0x48, 0x68, 0x58, 0x51, 0x4c, 0x39, 0x75, 0x6f, 0x4c, 0x41, 0x4f, 0x69, 0x72, 0x70, +0x67, 0x59, 0x53, 0x66, 0x44, 0x65, 0x30, 0x64, 0x73, 0x6a, 0x4e, 0x38, 0x35, 0x47, 0x45, 0x32, +0x38, 0x69, 0x68, 0x42, 0x78, 0x69, 0x38, 0x74, 0x61, 0x5a, 0x76, 0x62, 0x2f, 0x62, 0x53, 0x49, +0x4b, 0x76, 0x4c, 0x74, 0x67, 0x47, 0x78, 0x65, 0x35, 0x38, 0x65, 0x2f, 0x64, 0x75, 0x7a, 0x64, +0x48, 0x48, 0x48, 0x45, 0x45, 0x57, 0x37, 0x5a, 0x73, 0x6f, 0x61, 0x72, 0x4b, 0x55, 0x6f, 0x62, +0x76, 0x55, 0x5a, 0x63, 0x66, 0x56, 0x2f, 0x6f, 0x39, 0x65, 0x39, 0x5a, 0x77, 0x35, 0x4a, 0x46, +0x48, 0x55, 0x6c, 0x46, 0x52, 0x77, 0x5a, 0x41, 0x68, 0x51, 0x77, 0x4c, 0x5a, 0x59, 0x56, 0x42, +0x46, 0x76, 0x77, 0x77, 0x68, 0x51, 0x43, 0x66, 0x59, 0x78, 0x6f, 0x70, 0x38, 0x4a, 0x4c, 0x64, +0x48, 0x64, 0x36, 0x63, 0x55, 0x4c, 0x6d, 0x4d, 0x6c, 0x32, 0x70, 0x4d, 0x38, 0x55, 0x6c, 0x6c, +0x4e, 0x4c, 0x79, 0x47, 0x49, 0x53, 0x6b, 0x55, 0x6f, 0x75, 0x62, 0x53, 0x63, 0x54, 0x4e, 0x43, +0x4a, 0x42, 0x65, 0x4d, 0x66, 0x52, 0x49, 0x78, 0x43, 0x62, 0x67, 0x49, 0x4b, 0x6f, 0x61, 0x69, +0x75, 0x4b, 0x6e, 0x4c, 0x70, 0x36, 0x70, 0x49, 0x34, 0x54, 0x62, 0x70, 0x32, 0x31, 0x5a, 0x43, +0x46, 0x35, 0x4b, 0x74, 0x6c, 0x38, 0x4d, 0x31, 0x61, 0x33, 0x33, 0x4a, 0x5a, 0x74, 0x48, 0x69, +0x6f, 0x73, 0x4a, 0x73, 0x2f, 0x55, 0x71, 0x4f, 0x4e, 0x34, 0x4d, 0x4b, 0x73, 0x4a, 0x33, 0x6e, +0x4e, 0x6e, 0x47, 0x75, 0x74, 0x65, 0x6d, 0x4e, 0x4c, 0x51, 0x55, 0x68, 0x64, 0x78, 0x57, 0x66, +0x6d, 0x39, 0x32, 0x69, 0x74, 0x32, 0x57, 0x6c, 0x4b, 0x36, 0x4b, 0x38, 0x4e, 0x79, 0x6c, 0x67, +0x6f, 0x74, 0x32, 0x58, 0x31, 0x31, 0x72, 0x7a, 0x45, 0x52, 0x32, 0x53, 0x74, 0x48, 0x77, 0x6a, +0x78, 0x49, 0x6a, 0x4b, 0x57, 0x56, 0x52, 0x67, 0x74, 0x30, 0x45, 0x6e, 0x30, 0x61, 0x79, 0x5a, +0x70, 0x2f, 0x4c, 0x52, 0x53, 0x73, 0x46, 0x4a, 0x78, 0x46, 0x41, 0x34, 0x6b, 0x32, 0x39, 0x47, +0x42, 0x56, 0x31, 0x6f, 0x47, 0x55, 0x68, 0x42, 0x79, 0x31, 0x77, 0x64, 0x51, 0x2f, 0x4a, 0x43, +0x77, 0x73, 0x66, 0x38, 0x34, 0x4a, 0x69, 0x61, 0x41, 0x34, 0x72, 0x66, 0x62, 0x73, 0x4b, 0x70, +0x33, 0x4e, 0x35, 0x69, 0x72, 0x54, 0x38, 0x44, 0x53, 0x39, 0x33, 0x5a, 0x48, 0x53, 0x4a, 0x71, +0x47, 0x4b, 0x45, 0x75, 0x47, 0x30, 0x6d, 0x33, 0x37, 0x65, 0x46, 0x73, 0x61, 0x75, 0x6b, 0x2b, +0x69, 0x35, 0x61, 0x35, 0x68, 0x74, 0x4d, 0x6e, 0x52, 0x67, 0x37, 0x32, 0x6d, 0x37, 0x5a, 0x56, +0x41, 0x62, 0x2f, 0x33, 0x63, 0x2b, 0x78, 0x66, 0x43, 0x70, 0x69, 0x2b, 0x36, 0x41, 0x6a, 0x53, +0x37, 0x51, 0x2f, 0x36, 0x6c, 0x6f, 0x2f, 0x52, 0x43, 0x77, 0x44, 0x36, 0x38, 0x6c, 0x6e, 0x61, +0x54, 0x54, 0x4b, 0x39, 0x30, 0x4a, 0x47, 0x44, 0x77, 0x43, 0x6b, 0x47, 0x4f, 0x7a, 0x34, 0x53, +0x54, 0x68, 0x2f, 0x4c, 0x42, 0x43, 0x32, 0x73, 0x5a, 0x65, 0x32, 0x77, 0x56, 0x57, 0x73, 0x50, +0x43, 0x64, 0x31, 0x59, 0x44, 0x50, 0x75, 0x64, 0x4f, 0x47, 0x55, 0x45, 0x30, 0x36, 0x76, 0x50, +0x43, 0x59, 0x31, 0x38, 0x43, 0x6b, 0x70, 0x4d, 0x6d, 0x6a, 0x75, 0x62, 0x31, 0x4f, 0x51, 0x32, +0x59, 0x64, 0x61, 0x73, 0x35, 0x34, 0x74, 0x51, 0x78, 0x66, 0x4c, 0x6b, 0x79, 0x6e, 0x2b, 0x31, +0x31, 0x64, 0x38, 0x48, 0x47, 0x66, 0x30, 0x50, 0x48, 0x48, 0x74, 0x44, 0x69, 0x45, 0x48, 0x5a, +0x52, 0x4f, 0x7a, 0x6d, 0x49, 0x75, 0x75, 0x38, 0x6d, 0x30, 0x78, 0x4d, 0x46, 0x78, 0x38, 0x44, +0x34, 0x70, 0x32, 0x50, 0x33, 0x68, 0x47, 0x6d, 0x46, 0x77, 0x4b, 0x63, 0x2f, 0x48, 0x51, 0x6f, +0x37, 0x65, 0x47, 0x49, 0x37, 0x71, 0x69, 0x6b, 0x4a, 0x33, 0x53, 0x66, 0x64, 0x2f, 0x66, 0x32, +0x30, 0x33, 0x35, 0x4b, 0x52, 0x67, 0x46, 0x72, 0x62, 0x72, 0x69, 0x69, 0x47, 0x54, 0x59, 0x74, +0x4c, 0x75, 0x36, 0x44, 0x37, 0x41, 0x70, 0x53, 0x6e, 0x64, 0x75, 0x67, 0x33, 0x47, 0x55, 0x63, +0x44, 0x61, 0x6b, 0x68, 0x69, 0x55, 0x67, 0x4c, 0x4e, 0x57, 0x52, 0x39, 0x65, 0x2b, 0x54, 0x38, +0x68, 0x41, 0x5a, 0x64, 0x64, 0x2f, 0x6d, 0x48, 0x4e, 0x43, 0x71, 0x41, 0x4b, 0x32, 0x45, 0x48, +0x71, 0x65, 0x45, 0x50, 0x58, 0x65, 0x55, 0x48, 0x53, 0x2f, 0x77, 0x48, 0x73, 0x77, 0x30, 0x68, +0x53, 0x73, 0x65, 0x66, 0x4a, 0x37, 0x78, 0x6e, 0x43, 0x6a, 0x75, 0x6e, 0x48, 0x61, 0x2b, 0x33, +0x63, 0x4b, 0x59, 0x75, 0x35, 0x4e, 0x72, 0x51, 0x6a, 0x42, 0x65, 0x47, 0x58, 0x30, 0x6d, 0x38, +0x42, 0x47, 0x6a, 0x42, 0x41, 0x41, 0x75, 0x4c, 0x36, 0x4f, 0x41, 0x53, 0x74, 0x4e, 0x2f, 0x35, +0x76, 0x72, 0x4d, 0x6a, 0x52, 0x74, 0x50, 0x4d, 0x7a, 0x79, 0x55, 0x4b, 0x61, 0x79, 0x4b, 0x59, +0x38, 0x76, 0x7a, 0x66, 0x78, 0x6e, 0x70, 0x68, 0x70, 0x61, 0x66, 0x4d, 0x49, 0x75, 0x37, 0x77, +0x5a, 0x62, 0x57, 0x7a, 0x68, 0x42, 0x59, 0x43, 0x57, 0x44, 0x67, 0x39, 0x66, 0x47, 0x58, 0x4b, +0x7a, 0x4e, 0x46, 0x4a, 0x41, 0x54, 0x4c, 0x71, 0x45, 0x49, 0x47, 0x32, 0x49, 0x43, 0x5a, 0x75, +0x71, 0x2b, 0x75, 0x55, 0x37, 0x2f, 0x34, 0x33, 0x4c, 0x41, 0x6f, 0x53, 0x63, 0x6e, 0x4d, 0x68, +0x45, 0x44, 0x6b, 0x45, 0x38, 0x66, 0x79, 0x42, 0x64, 0x69, 0x75, 0x30, 0x72, 0x74, 0x6d, 0x78, +0x70, 0x57, 0x6f, 0x39, 0x61, 0x55, 0x67, 0x53, 0x55, 0x78, 0x6d, 0x44, 0x33, 0x63, 0x42, 0x67, +0x4c, 0x62, 0x74, 0x44, 0x47, 0x46, 0x64, 0x6c, 0x55, 0x74, 0x74, 0x43, 0x6d, 0x55, 0x70, 0x4c, +0x4b, 0x38, 0x55, 0x50, 0x54, 0x72, 0x74, 0x64, 0x38, 0x78, 0x59, 0x76, 0x78, 0x54, 0x74, 0x6f, +0x56, 0x44, 0x46, 0x49, 0x44, 0x52, 0x2f, 0x56, 0x2f, 0x2b, 0x6e, 0x2b, 0x61, 0x67, 0x4f, 0x4b, +0x64, 0x73, 0x32, 0x74, 0x53, 0x65, 0x68, 0x53, 0x37, 0x74, 0x64, 0x4e, 0x42, 0x41, 0x33, 0x54, +0x69, 0x75, 0x35, 0x5a, 0x4a, 0x33, 0x79, 0x58, 0x6f, 0x45, 0x46, 0x54, 0x65, 0x4d, 0x42, 0x4a, +0x61, 0x6d, 0x68, 0x4c, 0x58, 0x61, 0x75, 0x31, 0x79, 0x4c, 0x36, 0x4c, 0x67, 0x32, 0x30, 0x6f, +0x7a, 0x32, 0x68, 0x65, 0x57, 0x52, 0x56, 0x68, 0x30, 0x6e, 0x52, 0x54, 0x50, 0x38, 0x33, 0x38, +0x6e, 0x78, 0x51, 0x30, 0x42, 0x74, 0x31, 0x44, 0x65, 0x78, 0x50, 0x39, 0x77, 0x39, 0x47, 0x56, +0x48, 0x61, 0x63, 0x71, 0x7a, 0x70, 0x2f, 0x33, 0x2f, 0x6a, 0x79, 0x6d, 0x69, 0x38, 0x67, 0x7a, +0x6e, 0x2f, 0x35, 0x7a, 0x72, 0x4b, 0x2f, 0x49, 0x2b, 0x53, 0x4c, 0x31, 0x41, 0x67, 0x6c, 0x6f, +0x2b, 0x77, 0x63, 0x5a, 0x6e, 0x6d, 0x36, 0x7a, 0x63, 0x36, 0x58, 0x7a, 0x37, 0x2f, 0x76, 0x57, +0x51, 0x72, 0x76, 0x31, 0x7a, 0x32, 0x50, 0x6f, 0x4a, 0x73, 0x4e, 0x30, 0x51, 0x46, 0x77, 0x43, +0x63, 0x30, 0x52, 0x71, 0x45, 0x57, 0x35, 0x56, 0x32, 0x5a, 0x71, 0x5a, 0x46, 0x50, 0x77, 0x5a, +0x4d, 0x58, 0x46, 0x4a, 0x49, 0x56, 0x49, 0x46, 0x47, 0x44, 0x58, 0x34, 0x72, 0x74, 0x62, 0x31, +0x61, 0x55, 0x31, 0x70, 0x52, 0x38, 0x54, 0x50, 0x61, 0x50, 0x7a, 0x58, 0x74, 0x67, 0x57, 0x55, +0x61, 0x67, 0x33, 0x61, 0x6d, 0x6b, 0x62, 0x4e, 0x50, 0x4d, 0x4a, 0x34, 0x33, 0x2b, 0x63, 0x51, +0x41, 0x46, 0x77, 0x4a, 0x50, 0x5a, 0x4f, 0x69, 0x2f, 0x44, 0x65, 0x34, 0x2b, 0x74, 0x52, 0x6e, +0x75, 0x76, 0x52, 0x66, 0x6f, 0x57, 0x52, 0x42, 0x70, 0x61, 0x76, 0x55, 0x34, 0x35, 0x57, 0x6a, +0x6e, 0x30, 0x58, 0x64, 0x65, 0x52, 0x4b, 0x30, 0x4d, 0x7a, 0x63, 0x30, 0x77, 0x66, 0x49, 0x38, +0x51, 0x47, 0x4d, 0x4f, 0x69, 0x68, 0x5a, 0x72, 0x38, 0x41, 0x68, 0x4d, 0x33, 0x68, 0x5a, 0x57, +0x32, 0x6b, 0x4e, 0x6e, 0x6e, 0x33, 0x32, 0x34, 0x46, 0x43, 0x54, 0x66, 0x66, 0x76, 0x6a, 0x64, +0x39, 0x79, 0x37, 0x63, 0x79, 0x73, 0x4b, 0x4b, 0x42, 0x55, 0x62, 0x55, 0x72, 0x2b, 0x58, 0x4c, +0x64, 0x41, 0x48, 0x37, 0x59, 0x4e, 0x49, 0x43, 0x31, 0x6a, 0x65, 0x58, 0x49, 0x46, 0x46, 0x62, +0x56, 0x31, 0x47, 0x49, 0x46, 0x4c, 0x39, 0x2f, 0x32, 0x4a, 0x67, 0x42, 0x2f, 0x57, 0x6c, 0x53, +0x47, 0x42, 0x39, 0x7a, 0x76, 0x61, 0x2f, 0x41, 0x30, 0x34, 0x73, 0x42, 0x69, 0x57, 0x74, 0x61, +0x31, 0x73, 0x33, 0x78, 0x6d, 0x4b, 0x61, 0x31, 0x62, 0x44, 0x46, 0x70, 0x49, 0x6c, 0x42, 0x51, +0x6f, 0x78, 0x38, 0x61, 0x62, 0x57, 0x78, 0x61, 0x6a, 0x5a, 0x6d, 0x51, 0x54, 0x42, 0x62, 0x6b, +0x72, 0x41, 0x58, 0x6a, 0x72, 0x6e, 0x57, 0x73, 0x34, 0x37, 0x4a, 0x41, 0x68, 0x7a, 0x50, 0x78, +0x77, 0x47, 0x64, 0x39, 0x2b, 0x56, 0x38, 0x2b, 0x65, 0x56, 0x37, 0x2f, 0x67, 0x59, 0x75, 0x57, +0x37, 0x68, 0x69, 0x4b, 0x33, 0x72, 0x56, 0x38, 0x4c, 0x68, 0x33, 0x33, 0x57, 0x50, 0x52, 0x54, +0x31, 0x78, 0x34, 0x39, 0x43, 0x4a, 0x49, 0x52, 0x71, 0x62, 0x6e, 0x58, 0x33, 0x55, 0x47, 0x41, +0x30, 0x59, 0x52, 0x52, 0x68, 0x59, 0x77, 0x63, 0x78, 0x42, 0x63, 0x57, 0x6e, 0x4a, 0x51, 0x52, +0x46, 0x57, 0x4c, 0x57, 0x67, 0x35, 0x62, 0x75, 0x58, 0x6f, 0x61, 0x6b, 0x52, 0x72, 0x72, 0x33, +0x46, 0x58, 0x71, 0x38, 0x64, 0x4b, 0x36, 0x39, 0x55, 0x64, 0x71, 0x2b, 0x76, 0x46, 0x4a, 0x37, +0x53, 0x68, 0x4a, 0x55, 0x7a, 0x61, 0x2b, 0x4d, 0x51, 0x54, 0x2f, 0x75, 0x35, 0x37, 0x5a, 0x61, +0x37, 0x61, 0x51, 0x4d, 0x6d, 0x70, 0x4c, 0x45, 0x71, 0x57, 0x32, 0x37, 0x44, 0x42, 0x4a, 0x4e, +0x78, 0x77, 0x4b, 0x4b, 0x73, 0x33, 0x4c, 0x75, 0x57, 0x45, 0x69, 0x55, 0x45, 0x54, 0x30, 0x79, +0x66, 0x54, 0x6c, 0x39, 0x79, 0x53, 0x72, 0x74, 0x37, 0x4f, 0x4f, 0x4b, 0x37, 0x37, 0x6d, 0x34, +0x79, 0x73, 0x59, 0x4c, 0x6a, 0x66, 0x32, 0x48, 0x31, 0x2f, 0x66, 0x39, 0x77, 0x2f, 0x57, 0x30, +0x50, 0x32, 0x43, 0x31, 0x46, 0x77, 0x50, 0x66, 0x67, 0x56, 0x55, 0x79, 0x31, 0x34, 0x31, 0x34, +0x6b, 0x38, 0x49, 0x77, 0x69, 0x62, 0x46, 0x6f, 0x4a, 0x6d, 0x53, 0x7a, 0x36, 0x54, 0x55, 0x37, +0x73, 0x67, 0x62, 0x57, 0x51, 0x4c, 0x48, 0x6e, 0x79, 0x52, 0x53, 0x6a, 0x77, 0x55, 0x52, 0x4f, +0x6a, 0x30, 0x42, 0x35, 0x4e, 0x57, 0x59, 0x6b, 0x4e, 0x6f, 0x4e, 0x76, 0x73, 0x59, 0x71, 0x53, +0x4c, 0x49, 0x77, 0x37, 0x65, 0x61, 0x2b, 0x73, 0x52, 0x61, 0x67, 0x4d, 0x55, 0x35, 0x4a, 0x4c, +0x2f, 0x5a, 0x34, 0x75, 0x45, 0x4b, 0x43, 0x30, 0x74, 0x64, 0x65, 0x50, 0x76, 0x2b, 0x75, 0x6e, +0x32, 0x32, 0x7a, 0x48, 0x62, 0x47, 0x6e, 0x39, 0x36, 0x2b, 0x2f, 0x39, 0x36, 0x4c, 0x4b, 0x4f, +0x48, 0x39, 0x4b, 0x41, 0x6f, 0x4c, 0x34, 0x75, 0x50, 0x76, 0x32, 0x36, 0x67, 0x74, 0x56, 0x50, +0x59, 0x4c, 0x61, 0x65, 0x32, 0x45, 0x59, 0x49, 0x67, 0x6e, 0x54, 0x71, 0x6d, 0x4c, 0x43, 0x35, +0x72, 0x63, 0x47, 0x51, 0x6a, 0x4a, 0x78, 0x64, 0x2b, 0x53, 0x76, 0x57, 0x66, 0x73, 0x47, 0x55, +0x42, 0x48, 0x70, 0x77, 0x4b, 0x6c, 0x34, 0x4e, 0x35, 0x51, 0x2b, 0x50, 0x74, 0x54, 0x4f, 0x6f, +0x2f, 0x58, 0x2b, 0x4a, 0x35, 0x6b, 0x76, 0x44, 0x76, 0x4a, 0x53, 0x48, 0x66, 0x33, 0x62, 0x64, +0x51, 0x59, 0x43, 0x5a, 0x4b, 0x7a, 0x46, 0x42, 0x42, 0x32, 0x33, 0x48, 0x54, 0x69, 0x57, 0x51, +0x37, 0x55, 0x72, 0x44, 0x74, 0x4c, 0x54, 0x71, 0x78, 0x4d, 0x68, 0x6e, 0x44, 0x31, 0x6b, 0x36, +0x50, 0x2f, 0x66, 0x30, 0x6d, 0x73, 0x6a, 0x46, 0x73, 0x61, 0x43, 0x71, 0x6b, 0x71, 0x4e, 0x58, +0x79, 0x2b, 0x79, 0x6c, 0x70, 0x46, 0x55, 0x52, 0x35, 0x68, 0x64, 0x76, 0x4c, 0x4f, 0x30, 0x36, +0x70, 0x6f, 0x77, 0x65, 0x2f, 0x53, 0x55, 0x34, 0x6b, 0x53, 0x6b, 0x6a, 0x36, 0x6a, 0x4b, 0x39, +0x64, 0x51, 0x56, 0x31, 0x78, 0x45, 0x56, 0x64, 0x2b, 0x39, 0x31, 0x75, 0x37, 0x6e, 0x30, 0x37, +0x4b, 0x74, 0x77, 0x35, 0x79, 0x78, 0x48, 0x74, 0x58, 0x4f, 0x56, 0x5a, 0x56, 0x49, 0x43, 0x59, +0x4d, 0x6e, 0x53, 0x4b, 0x61, 0x49, 0x43, 0x59, 0x31, 0x45, 0x58, 0x35, 0x34, 0x4a, 0x35, 0x2b, +0x63, 0x6f, 0x6a, 0x5a, 0x6b, 0x75, 0x30, 0x65, 0x73, 0x77, 0x77, 0x70, 0x50, 0x4f, 0x42, 0x49, +0x6a, 0x31, 0x69, 0x62, 0x4a, 0x72, 0x2b, 0x78, 0x67, 0x37, 0x59, 0x49, 0x63, 0x2b, 0x67, 0x32, +0x7a, 0x75, 0x37, 0x6a, 0x44, 0x44, 0x68, 0x6c, 0x43, 0x54, 0x6b, 0x36, 0x45, 0x41, 0x38, 0x62, +0x58, 0x38, 0x65, 0x35, 0x37, 0x33, 0x37, 0x4e, 0x70, 0x36, 0x68, 0x55, 0x4a, 0x4d, 0x64, 0x6d, +0x31, 0x62, 0x51, 0x41, 0x41, 0x49, 0x41, 0x42, 0x4a, 0x52, 0x45, 0x46, 0x55, 0x52, 0x46, 0x37, +0x51, 0x36, 0x55, 0x71, 0x6d, 0x63, 0x50, 0x74, 0x46, 0x65, 0x6c, 0x58, 0x7a, 0x39, 0x55, 0x4e, +0x2f, 0x68, 0x38, 0x6a, 0x44, 0x33, 0x55, 0x42, 0x52, 0x41, 0x52, 0x66, 0x58, 0x70, 0x72, 0x45, +0x78, 0x34, 0x33, 0x38, 0x44, 0x62, 0x5a, 0x45, 0x51, 0x68, 0x58, 0x68, 0x67, 0x5a, 0x41, 0x4f, +0x65, 0x55, 0x58, 0x47, 0x68, 0x74, 0x7a, 0x58, 0x71, 0x72, 0x61, 0x42, 0x6a, 0x67, 0x70, 0x66, +0x6c, 0x41, 0x7a, 0x52, 0x61, 0x34, 0x47, 0x58, 0x31, 0x74, 0x6e, 0x38, 0x68, 0x61, 0x6c, 0x46, +0x32, 0x5a, 0x74, 0x74, 0x57, 0x48, 0x44, 0x75, 0x6c, 0x49, 0x31, 0x5a, 0x4a, 0x32, 0x71, 0x2f, +0x46, 0x71, 0x63, 0x69, 0x44, 0x46, 0x47, 0x75, 0x42, 0x31, 0x37, 0x4d, 0x58, 0x6d, 0x6f, 0x44, +0x54, 0x7a, 0x64, 0x44, 0x75, 0x57, 0x4a, 0x57, 0x31, 0x43, 0x69, 0x6f, 0x4c, 0x32, 0x58, 0x66, +0x6c, 0x51, 0x6e, 0x62, 0x4b, 0x46, 0x79, 0x69, 0x48, 0x67, 0x31, 0x42, 0x43, 0x55, 0x4f, 0x42, +0x59, 0x61, 0x65, 0x66, 0x51, 0x6d, 0x66, 0x48, 0x42, 0x51, 0x6e, 0x69, 0x30, 0x30, 0x55, 0x6f, +0x49, 0x79, 0x4b, 0x63, 0x49, 0x33, 0x59, 0x30, 0x53, 0x4f, 0x4d, 0x6a, 0x64, 0x2f, 0x2f, 0x2f, +0x4d, 0x36, 0x76, 0x76, 0x2f, 0x34, 0x33, 0x6f, 0x44, 0x39, 0x64, 0x75, 0x45, 0x53, 0x39, 0x6b, +0x31, 0x47, 0x4c, 0x6b, 0x42, 0x73, 0x6c, 0x70, 0x35, 0x2b, 0x2f, 0x55, 0x43, 0x74, 0x42, 0x4c, +0x38, 0x36, 0x70, 0x67, 0x4f, 0x6a, 0x42, 0x48, 0x45, 0x31, 0x69, 0x62, 0x2b, 0x58, 0x71, 0x53, +0x6d, 0x74, 0x77, 0x55, 0x79, 0x61, 0x63, 0x41, 0x44, 0x74, 0x57, 0x42, 0x70, 0x66, 0x48, 0x56, +0x55, 0x53, 0x44, 0x52, 0x68, 0x35, 0x4b, 0x41, 0x43, 0x54, 0x43, 0x53, 0x45, 0x6d, 0x74, 0x2f, +0x69, 0x66, 0x73, 0x75, 0x4b, 0x5a, 0x31, 0x64, 0x6d, 0x48, 0x7a, 0x77, 0x4b, 0x4b, 0x55, 0x31, +0x43, 0x52, 0x53, 0x59, 0x35, 0x74, 0x30, 0x31, 0x39, 0x50, 0x57, 0x7a, 0x61, 0x39, 0x4a, 0x50, +0x62, 0x33, 0x36, 0x73, 0x38, 0x6e, 0x79, 0x4d, 0x50, 0x47, 0x49, 0x41, 0x78, 0x73, 0x48, 0x68, +0x6c, 0x49, 0x39, 0x2b, 0x74, 0x33, 0x6d, 0x35, 0x7a, 0x54, 0x31, 0x54, 0x43, 0x41, 0x64, 0x30, +0x68, 0x77, 0x75, 0x53, 0x70, 0x46, 0x73, 0x34, 0x71, 0x6e, 0x4d, 0x50, 0x78, 0x75, 0x51, 0x76, +0x49, 0x71, 0x75, 0x78, 0x48, 0x79, 0x32, 0x2b, 0x42, 0x75, 0x34, 0x46, 0x65, 0x42, 0x6a, 0x4f, +0x32, 0x48, 0x73, 0x35, 0x51, 0x38, 0x43, 0x2b, 0x46, 0x2b, 0x64, 0x4c, 0x31, 0x33, 0x79, 0x71, +0x42, 0x69, 0x51, 0x6a, 0x4d, 0x53, 0x6e, 0x66, 0x2f, 0x55, 0x54, 0x37, 0x6d, 0x51, 0x68, 0x2b, +0x7a, 0x58, 0x4f, 0x41, 0x39, 0x56, 0x59, 0x75, 0x65, 0x43, 0x78, 0x48, 0x72, 0x6a, 0x44, 0x52, +0x6f, 0x4f, 0x2b, 0x66, 0x51, 0x78, 0x74, 0x44, 0x52, 0x37, 0x6a, 0x48, 0x73, 0x79, 0x42, 0x44, +0x7a, 0x6e, 0x33, 0x36, 0x47, 0x74, 0x74, 0x5a, 0x57, 0x64, 0x72, 0x2f, 0x30, 0x4f, 0x70, 0x62, +0x2b, 0x79, 0x79, 0x65, 0x55, 0x62, 0x61, 0x31, 0x37, 0x62, 0x55, 0x43, 0x4a, 0x52, 0x45, 0x71, +0x61, 0x4e, 0x76, 0x44, 0x75, 0x39, 0x79, 0x4d, 0x35, 0x59, 0x2b, 0x78, 0x48, 0x59, 0x43, 0x53, +0x2b, 0x31, 0x4c, 0x7a, 0x78, 0x31, 0x64, 0x34, 0x4a, 0x57, 0x69, 0x6a, 0x6c, 0x4d, 0x73, 0x70, +0x45, 0x51, 0x67, 0x6c, 0x49, 0x71, 0x51, 0x6e, 0x79, 0x66, 0x44, 0x55, 0x47, 0x48, 0x56, 0x42, +0x53, 0x61, 0x34, 0x48, 0x52, 0x69, 0x72, 0x62, 0x4e, 0x69, 0x6d, 0x31, 0x4c, 0x77, 0x2b, 0x78, +0x33, 0x33, 0x6d, 0x72, 0x71, 0x76, 0x38, 0x6d, 0x6c, 0x72, 0x45, 0x38, 0x7a, 0x79, 0x6c, 0x65, +0x30, 0x62, 0x74, 0x56, 0x73, 0x57, 0x4a, 0x52, 0x50, 0x2b, 0x38, 0x34, 0x49, 0x6f, 0x72, 0x39, +0x56, 0x49, 0x44, 0x4e, 0x6e, 0x4c, 0x75, 0x4f, 0x41, 0x41, 0x2b, 0x70, 0x34, 0x63, 0x2f, 0x71, +0x33, 0x43, 0x4b, 0x6e, 0x6f, 0x64, 0x64, 0x74, 0x39, 0x50, 0x78, 0x34, 0x48, 0x39, 0x6a, 0x7a, +0x47, 0x6e, 0x66, 0x64, 0x48, 0x58, 0x71, 0x73, 0x76, 0x36, 0x55, 0x36, 0x34, 0x2b, 0x65, 0x61, +0x62, 0x62, 0x38, 0x44, 0x41, 0x6e, 0x71, 0x4f, 0x4f, 0x37, 0x66, 0x61, 0x63, 0x62, 0x39, 0x73, +0x75, 0x6f, 0x63, 0x61, 0x58, 0x43, 0x46, 0x2f, 0x59, 0x37, 0x59, 0x6c, 0x54, 0x41, 0x48, 0x45, +0x48, 0x6a, 0x68, 0x4e, 0x34, 0x62, 0x58, 0x7a, 0x37, 0x6d, 0x79, 0x74, 0x54, 0x6e, 0x5a, 0x58, +0x6a, 0x38, 0x39, 0x56, 0x57, 0x4f, 0x50, 0x6d, 0x34, 0x6b, 0x7a, 0x46, 0x31, 0x75, 0x30, 0x46, +0x6c, 0x6c, 0x52, 0x56, 0x2b, 0x34, 0x35, 0x52, 0x41, 0x45, 0x4d, 0x5a, 0x53, 0x4b, 0x6c, 0x45, +0x71, 0x58, 0x61, 0x75, 0x34, 0x49, 0x34, 0x65, 0x53, 0x45, 0x6e, 0x53, 0x2f, 0x6e, 0x6b, 0x54, +0x58, 0x57, 0x65, 0x43, 0x4a, 0x53, 0x42, 0x64, 0x2b, 0x33, 0x37, 0x63, 0x72, 0x76, 0x68, 0x4e, +0x38, 0x4a, 0x58, 0x79, 0x72, 0x42, 0x4a, 0x77, 0x43, 0x79, 0x42, 0x61, 0x43, 0x46, 0x75, 0x42, +0x67, 0x66, 0x6d, 0x51, 0x48, 0x30, 0x4b, 0x73, 0x4d, 0x4e, 0x75, 0x2f, 0x73, 0x39, 0x72, 0x38, +0x4e, 0x43, 0x53, 0x68, 0x35, 0x69, 0x76, 0x44, 0x36, 0x66, 0x6c, 0x7a, 0x35, 0x57, 0x71, 0x4b, +0x4f, 0x56, 0x46, 0x78, 0x49, 0x6e, 0x46, 0x56, 0x36, 0x46, 0x39, 0x66, 0x48, 0x6f, 0x65, 0x52, +0x69, 0x46, 0x39, 0x66, 0x72, 0x67, 0x43, 0x63, 0x68, 0x51, 0x55, 0x69, 0x4c, 0x55, 0x57, 0x79, +0x74, 0x56, 0x2f, 0x53, 0x76, 0x37, 0x57, 0x44, 0x70, 0x55, 0x74, 0x6a, 0x59, 0x30, 0x45, 0x35, +0x4e, 0x4c, 0x2b, 0x4c, 0x34, 0x42, 0x66, 0x76, 0x75, 0x6b, 0x4a, 0x6a, 0x4b, 0x62, 0x51, 0x63, +0x69, 0x34, 0x55, 0x53, 0x71, 0x39, 0x4d, 0x68, 0x53, 0x31, 0x46, 0x64, 0x4e, 0x56, 0x44, 0x78, +0x52, 0x44, 0x51, 0x59, 0x32, 0x48, 0x4e, 0x5a, 0x4d, 0x61, 0x45, 0x77, 0x56, 0x38, 0x71, 0x75, +0x57, 0x75, 0x41, 0x49, 0x49, 0x59, 0x77, 0x45, 0x35, 0x57, 0x57, 0x53, 0x41, 0x77, 0x6b, 0x76, +0x35, 0x30, 0x39, 0x75, 0x50, 0x4a, 0x69, 0x66, 0x62, 0x62, 0x6a, 0x38, 0x38, 0x44, 0x37, 0x4b, +0x7a, 0x77, 0x2f, 0x45, 0x56, 0x58, 0x79, 0x6c, 0x44, 0x68, 0x2f, 0x44, 0x77, 0x42, 0x59, 0x7a, +0x4c, 0x57, 0x73, 0x7a, 0x5a, 0x4a, 0x65, 0x38, 0x79, 0x73, 0x4b, 0x67, 0x5a, 0x4d, 0x2b, 0x68, +0x51, 0x7a, 0x49, 0x48, 0x6e, 0x6f, 0x58, 0x2f, 0x7a, 0x4a, 0x44, 0x78, 0x58, 0x6a, 0x64, 0x6c, +0x71, 0x34, 0x48, 0x45, 0x46, 0x41, 0x78, 0x58, 0x6d, 0x49, 0x41, 0x45, 0x6c, 0x43, 0x76, 0x4f, +0x2b, 0x6a, 0x2f, 0x6c, 0x4b, 0x59, 0x68, 0x41, 0x59, 0x66, 0x4d, 0x79, 0x52, 0x50, 0x6d, 0x61, +0x34, 0x77, 0x4e, 0x7a, 0x74, 0x59, 0x2b, 0x59, 0x4c, 0x36, 0x47, 0x76, 0x76, 0x48, 0x77, 0x6b, +0x38, 0x75, 0x7a, 0x62, 0x66, 0x77, 0x48, 0x35, 0x75, 0x36, 0x39, 0x51, 0x4d, 0x7a, 0x67, 0x31, +0x78, 0x2b, 0x7a, 0x73, 0x7a, 0x61, 0x50, 0x63, 0x46, 0x4e, 0x31, 0x39, 0x78, 0x4c, 0x51, 0x75, +0x69, 0x48, 0x6b, 0x55, 0x68, 0x37, 0x58, 0x41, 0x34, 0x4a, 0x69, 0x6c, 0x6a, 0x4e, 0x6f, 0x54, +0x51, 0x48, 0x6a, 0x4f, 0x58, 0x6a, 0x65, 0x53, 0x44, 0x48, 0x77, 0x59, 0x6a, 0x6c, 0x53, 0x61, +0x6d, 0x73, 0x6c, 0x79, 0x68, 0x53, 0x47, 0x55, 0x4c, 0x35, 0x41, 0x71, 0x37, 0x72, 0x52, 0x58, +0x4b, 0x73, 0x2b, 0x38, 0x53, 0x59, 0x67, 0x6f, 0x67, 0x42, 0x4d, 0x5a, 0x6c, 0x2f, 0x6d, 0x6d, +0x58, 0x75, 0x61, 0x53, 0x73, 0x31, 0x31, 0x4f, 0x4a, 0x4c, 0x4c, 0x54, 0x57, 0x35, 0x42, 0x52, +0x32, 0x4d, 0x4f, 0x4b, 0x6b, 0x52, 0x6a, 0x71, 0x33, 0x4b, 0x75, 0x59, 0x38, 0x55, 0x4d, 0x4f, +0x77, 0x6f, 0x7a, 0x64, 0x52, 0x56, 0x75, 0x76, 0x54, 0x73, 0x6a, 0x56, 0x69, 0x43, 0x34, 0x63, +0x67, 0x2b, 0x57, 0x62, 0x78, 0x52, 0x6d, 0x61, 0x38, 0x74, 0x78, 0x67, 0x70, 0x4e, 0x55, 0x6f, +0x71, 0x47, 0x71, 0x37, 0x34, 0x6f, 0x36, 0x50, 0x33, 0x64, 0x70, 0x7a, 0x2b, 0x77, 0x63, 0x71, +0x76, 0x37, 0x45, 0x71, 0x71, 0x68, 0x55, 0x39, 0x57, 0x64, 0x52, 0x2b, 0x2b, 0x2b, 0x50, 0x75, +0x7a, 0x6e, 0x47, 0x5a, 0x32, 0x59, 0x64, 0x34, 0x32, 0x76, 0x59, 0x58, 0x57, 0x6d, 0x68, 0x4f, +0x50, 0x4f, 0x4b, 0x37, 0x62, 0x55, 0x37, 0x7a, 0x62, 0x34, 0x45, 0x38, 0x54, 0x4f, 0x6c, 0x6e, +0x66, 0x31, 0x68, 0x59, 0x6e, 0x30, 0x6b, 0x68, 0x4f, 0x51, 0x76, 0x47, 0x31, 0x63, 0x42, 0x57, +0x58, 0x55, 0x78, 0x6d, 0x4f, 0x2b, 0x68, 0x57, 0x58, 0x38, 0x4e, 0x45, 0x30, 0x32, 0x44, 0x37, +0x39, 0x44, 0x73, 0x72, 0x4b, 0x79, 0x68, 0x4b, 0x54, 0x78, 0x2f, 0x43, 0x54, 0x57, 0x4a, 0x48, +0x78, 0x50, 0x47, 0x49, 0x48, 0x48, 0x38, 0x36, 0x46, 0x57, 0x37, 0x5a, 0x51, 0x32, 0x4c, 0x63, +0x76, 0x79, 0x72, 0x48, 0x59, 0x6f, 0x48, 0x57, 0x63, 0x36, 0x69, 0x77, 0x49, 0x48, 0x38, 0x59, +0x2f, 0x75, 0x35, 0x78, 0x79, 0x6f, 0x7a, 0x57, 0x52, 0x37, 0x47, 0x78, 0x71, 0x50, 0x2f, 0x75, +0x4d, 0x66, 0x63, 0x34, 0x39, 0x4e, 0x2b, 0x4e, 0x7a, 0x56, 0x64, 0x54, 0x55, 0x63, 0x4d, 0x65, +0x74, 0x74, 0x33, 0x48, 0x48, 0x37, 0x62, 0x65, 0x79, 0x4c, 0x71, 0x66, 0x64, 0x63, 0x71, 0x68, +0x6e, 0x4f, 0x44, 0x51, 0x4f, 0x53, 0x75, 0x34, 0x73, 0x4c, 0x6c, 0x78, 0x2f, 0x64, 0x78, 0x72, +0x42, 0x77, 0x6a, 0x31, 0x73, 0x38, 0x74, 0x44, 0x65, 0x43, 0x33, 0x79, 0x79, 0x59, 0x34, 0x6d, +0x77, 0x58, 0x41, 0x6f, 0x72, 0x62, 0x6a, 0x66, 0x58, 0x64, 0x37, 0x64, 0x79, 0x70, 0x6c, 0x2b, +0x50, 0x57, 0x35, 0x44, 0x69, 0x35, 0x44, 0x58, 0x53, 0x59, 0x49, 0x78, 0x67, 0x7a, 0x73, 0x77, +0x38, 0x78, 0x6e, 0x2f, 0x61, 0x7a, 0x72, 0x35, 0x43, 0x38, 0x6d, 0x46, 0x37, 0x4e, 0x71, 0x65, +0x66, 0x32, 0x59, 0x62, 0x32, 0x70, 0x61, 0x4f, 0x59, 0x46, 0x34, 0x53, 0x44, 0x58, 0x41, 0x78, +0x6a, 0x34, 0x6b, 0x49, 0x64, 0x38, 0x43, 0x64, 0x6b, 0x58, 0x7a, 0x59, 0x41, 0x38, 0x2f, 0x46, +0x32, 0x48, 0x6c, 0x68, 0x34, 0x4e, 0x4f, 0x31, 0x74, 0x6d, 0x6e, 0x50, 0x4f, 0x46, 0x33, 0x69, +0x2f, 0x36, 0x6f, 0x6b, 0x34, 0x61, 0x57, 0x48, 0x63, 0x53, 0x73, 0x6a, 0x43, 0x56, 0x6a, 0x55, +0x4f, 0x4a, 0x7a, 0x6d, 0x30, 0x34, 0x2b, 0x50, 0x6e, 0x79, 0x35, 0x2f, 0x65, 0x66, 0x6c, 0x2b, +0x79, 0x73, 0x72, 0x36, 0x46, 0x56, 0x39, 0x39, 0x64, 0x53, 0x6d, 0x6c, 0x52, 0x4e, 0x70, 0x38, +0x76, 0x33, 0x68, 0x77, 0x76, 0x38, 0x42, 0x6b, 0x56, 0x59, 0x53, 0x72, 0x4d, 0x56, 0x73, 0x34, +0x73, 0x2b, 0x4a, 0x41, 0x6a, 0x79, 0x31, 0x64, 0x69, 0x68, 0x75, 0x79, 0x48, 0x47, 0x66, 0x63, +0x37, 0x54, 0x4e, 0x56, 0x51, 0x59, 0x73, 0x62, 0x6a, 0x74, 0x67, 0x64, 0x6e, 0x38, 0x74, 0x65, +0x78, 0x34, 0x50, 0x56, 0x56, 0x45, 0x4a, 0x57, 0x59, 0x56, 0x52, 0x4b, 0x57, 0x53, 0x38, 0x7a, +0x75, 0x41, 0x6a, 0x4e, 0x61, 0x59, 0x4d, 0x62, 0x61, 0x42, 0x63, 0x64, 0x73, 0x39, 0x7a, 0x45, +0x37, 0x66, 0x4d, 0x77, 0x39, 0x41, 0x74, 0x50, 0x68, 0x59, 0x32, 0x6f, 0x45, 0x44, 0x42, 0x55, +0x77, 0x45, 0x79, 0x4a, 0x43, 0x4f, 0x75, 0x33, 0x70, 0x30, 0x6a, 0x78, 0x6a, 0x55, 0x63, 0x6a, +0x74, 0x36, 0x37, 0x48, 0x7a, 0x42, 0x30, 0x47, 0x7a, 0x79, 0x37, 0x78, 0x72, 0x2b, 0x69, 0x35, +0x47, 0x54, 0x72, 0x38, 0x77, 0x30, 0x51, 0x32, 0x67, 0x50, 0x49, 0x4d, 0x53, 0x42, 0x69, 0x6e, +0x73, 0x46, 0x6d, 0x42, 0x59, 0x79, 0x37, 0x76, 0x73, 0x31, 0x6c, 0x46, 0x4d, 0x61, 0x58, 0x75, +0x7a, 0x39, 0x52, 0x46, 0x49, 0x5a, 0x66, 0x66, 0x72, 0x4c, 0x70, 0x77, 0x69, 0x6b, 0x34, 0x70, +0x4d, 0x71, 0x71, 0x54, 0x69, 0x6b, 0x31, 0x58, 0x35, 0x5a, 0x62, 0x7a, 0x50, 0x33, 0x39, 0x48, +0x6d, 0x43, 0x49, 0x73, 0x78, 0x63, 0x48, 0x73, 0x7a, 0x70, 0x46, 0x30, 0x31, 0x6c, 0x62, 0x41, +0x72, 0x61, 0x6e, 0x36, 0x76, 0x64, 0x70, 0x61, 0x39, 0x55, 0x30, 0x6a, 0x66, 0x4d, 0x64, 0x73, +0x35, 0x36, 0x4c, 0x4c, 0x6c, 0x35, 0x50, 0x54, 0x73, 0x6f, 0x4b, 0x4f, 0x78, 0x42, 0x43, 0x56, +0x4b, 0x72, 0x4f, 0x4c, 0x59, 0x2f, 0x67, 0x6a, 0x68, 0x73, 0x6f, 0x6f, 0x30, 0x6b, 0x4e, 0x4c, +0x70, 0x50, 0x32, 0x34, 0x42, 0x68, 0x45, 0x4c, 0x73, 0x66, 0x38, 0x46, 0x6c, 0x33, 0x51, 0x73, +0x2f, 0x63, 0x4e, 0x64, 0x66, 0x6e, 0x73, 0x58, 0x33, 0x66, 0x55, 0x34, 0x2b, 0x2f, 0x64, 0x4c, +0x75, 0x54, 0x34, 0x71, 0x53, 0x59, 0x49, 0x58, 0x56, 0x69, 0x52, 0x42, 0x71, 0x6b, 0x48, 0x55, +0x57, 0x56, 0x46, 0x67, 0x4f, 0x4b, 0x4d, 0x32, 0x53, 0x65, 0x51, 0x31, 0x70, 0x53, 0x2f, 0x79, +0x5a, 0x64, 0x4a, 0x44, 0x56, 0x54, 0x34, 0x57, 0x79, 0x56, 0x6f, 0x34, 0x5a, 0x45, 0x2b, 0x63, +0x30, 0x2f, 0x44, 0x6e, 0x58, 0x65, 0x36, 0x45, 0x51, 0x66, 0x55, 0x71, 0x36, 0x74, 0x33, 0x37, +0x65, 0x65, 0x2f, 0x4e, 0x4e, 0x48, 0x6e, 0x33, 0x73, 0x55, 0x64, 0x61, 0x74, 0x58, 0x6f, 0x4d, +0x78, 0x68, 0x74, 0x74, 0x75, 0x76, 0x5a, 0x58, 0x72, 0x62, 0x37, 0x67, 0x68, 0x38, 0x38, 0x6c, +0x4a, 0x55, 0x4f, 0x78, 0x41, 0x67, 0x46, 0x66, 0x31, 0x39, 0x57, 0x6e, 0x50, 0x46, 0x53, 0x67, +0x70, 0x57, 0x46, 0x72, 0x72, 0x4d, 0x2f, 0x49, 0x37, 0x6b, 0x5a, 0x45, 0x56, 0x6c, 0x36, 0x77, +0x73, 0x79, 0x39, 0x45, 0x58, 0x69, 0x62, 0x6a, 0x36, 0x44, 0x47, 0x6e, 0x70, 0x72, 0x78, 0x6c, +0x53, 0x59, 0x59, 0x30, 0x51, 0x55, 0x46, 0x4f, 0x44, 0x2f, 0x75, 0x67, 0x6a, 0x63, 0x4b, 0x48, +0x5a, 0x49, 0x45, 0x51, 0x72, 0x70, 0x62, 0x59, 0x4c, 0x69, 0x50, 0x49, 0x6f, 0x50, 0x4d, 0x4a, +0x75, 0x75, 0x65, 0x53, 0x57, 0x45, 0x45, 0x62, 0x37, 0x64, 0x74, 0x57, 0x50, 0x68, 0x77, 0x65, +0x64, 0x41, 0x6e, 0x41, 0x57, 0x51, 0x48, 0x4c, 0x56, 0x4a, 0x42, 0x70, 0x39, 0x51, 0x6e, 0x63, +0x50, 0x35, 0x66, 0x49, 0x37, 0x66, 0x67, 0x46, 0x35, 0x62, 0x5a, 0x78, 0x2f, 0x77, 0x64, 0x66, +0x6b, 0x76, 0x37, 0x65, 0x57, 0x5a, 0x6b, 0x68, 0x56, 0x46, 0x6f, 0x35, 0x53, 0x4c, 0x6e, 0x33, +0x38, 0x74, 0x75, 0x55, 0x49, 0x32, 0x67, 0x72, 0x39, 0x65, 0x43, 0x47, 0x5a, 0x51, 0x4f, 0x6c, +0x6f, 0x5a, 0x77, 0x6b, 0x6f, 0x4b, 0x63, 0x67, 0x70, 0x6b, 0x63, 0x77, 0x44, 0x55, 0x4a, 0x71, +0x4f, 0x71, 0x4f, 0x43, 0x4e, 0x75, 0x61, 0x76, 0x6a, 0x74, 0x47, 0x4f, 0x64, 0x4d, 0x51, 0x2b, +0x70, 0x4e, 0x49, 0x64, 0x47, 0x50, 0x75, 0x56, 0x33, 0x46, 0x51, 0x76, 0x6f, 0x73, 0x66, 0x74, +0x77, 0x7a, 0x50, 0x36, 0x50, 0x59, 0x63, 0x71, 0x48, 0x73, 0x58, 0x35, 0x62, 0x6a, 0x4c, 0x64, +0x65, 0x2b, 0x5a, 0x5a, 0x76, 0x56, 0x7a, 0x62, 0x79, 0x2f, 0x42, 0x31, 0x58, 0x38, 0x6c, 0x64, +0x6c, 0x48, 0x38, 0x4a, 0x30, 0x43, 0x45, 0x79, 0x62, 0x68, 0x48, 0x55, 0x53, 0x73, 0x38, 0x69, +0x74, 0x2b, 0x75, 0x4f, 0x46, 0x44, 0x53, 0x46, 0x2b, 0x35, 0x32, 0x50, 0x61, 0x42, 0x65, 0x59, +0x47, 0x48, 0x31, 0x50, 0x6e, 0x59, 0x34, 0x6f, 0x46, 0x46, 0x45, 0x76, 0x30, 0x74, 0x5a, 0x61, +0x54, 0x30, 0x70, 0x4a, 0x6b, 0x47, 0x73, 0x74, 0x45, 0x47, 0x2b, 0x75, 0x41, 0x67, 0x58, 0x75, +0x48, 0x65, 0x66, 0x65, 0x47, 0x6c, 0x33, 0x6e, 0x67, 0x50, 0x4a, 0x2f, 0x73, 0x73, 0x4d, 0x2f, +0x74, 0x44, 0x7a, 0x7a, 0x4a, 0x75, 0x4c, 0x39, 0x65, 0x79, 0x4f, 0x4a, 0x6e, 0x4c, 0x54, 0x65, +0x64, 0x64, 0x6a, 0x58, 0x61, 0x77, 0x54, 0x43, 0x6e, 0x2f, 0x57, 0x6d, 0x4b, 0x64, 0x68, 0x54, +0x44, 0x6c, 0x72, 0x57, 0x57, 0x38, 0x56, 0x59, 0x45, 0x32, 0x73, 0x2f, 0x76, 0x39, 0x6c, 0x31, +0x4c, 0x51, 0x54, 0x68, 0x55, 0x78, 0x78, 0x6d, 0x30, 0x59, 0x37, 0x53, 0x6a, 0x67, 0x4e, 0x4c, +0x53, 0x59, 0x76, 0x78, 0x56, 0x51, 0x67, 0x48, 0x49, 0x54, 0x73, 0x4f, 0x61, 0x57, 0x58, 0x6e, +0x73, 0x64, 0x74, 0x42, 0x6d, 0x77, 0x4a, 0x71, 0x30, 0x6f, 0x6b, 0x57, 0x79, 0x2b, 0x4f, 0x30, +0x53, 0x35, 0x78, 0x42, 0x55, 0x66, 0x46, 0x76, 0x52, 0x67, 0x7a, 0x37, 0x33, 0x33, 0x34, 0x46, +0x6f, 0x61, 0x43, 0x43, 0x6c, 0x6b, 0x45, 0x65, 0x38, 0x38, 0x78, 0x4d, 0x38, 0x2f, 0x39, 0x70, +0x56, 0x4d, 0x4e, 0x5a, 0x53, 0x6b, 0x74, 0x57, 0x37, 0x44, 0x2f, 0x4f, 0x66, 0x65, 0x5a, 0x58, +0x66, 0x64, 0x57, 0x4d, 0x42, 0x4c, 0x4a, 0x67, 0x2b, 0x6d, 0x36, 0x2b, 0x2b, 0x2b, 0x41, 0x49, +0x44, 0x7a, 0x48, 0x76, 0x39, 0x41, 0x2f, 0x59, 0x2f, 0x63, 0x55, 0x4b, 0x33, 0x77, 0x68, 0x4a, +0x55, 0x41, 0x77, 0x35, 0x59, 0x59, 0x61, 0x30, 0x46, 0x34, 0x4f, 0x4d, 0x6e, 0x31, 0x61, 0x52, +0x50, 0x71, 0x56, 0x46, 0x76, 0x42, 0x4d, 0x49, 0x6b, 0x6f, 0x4d, 0x67, 0x70, 0x55, 0x47, 0x72, +0x7a, 0x45, 0x77, 0x58, 0x59, 0x72, 0x65, 0x79, 0x4e, 0x69, 0x78, 0x5a, 0x52, 0x30, 0x4b, 0x63, +0x50, 0x79, 0x76, 0x66, 0x6a, 0x6f, 0x4b, 0x46, 0x67, 0x6c, 0x59, 0x39, 0x62, 0x41, 0x45, 0x6e, +0x66, 0x41, 0x32, 0x73, 0x67, 0x6b, 0x70, 0x50, 0x44, 0x2b, 0x76, 0x6e, 0x64, 0x73, 0x2f, 0x47, +0x63, 0x66, 0x50, 0x78, 0x4a, 0x33, 0x48, 0x6a, 0x7a, 0x7a, 0x58, 0x77, 0x77, 0x63, 0x78, 0x62, +0x6c, 0x52, 0x61, 0x55, 0x30, 0x74, 0x61, 0x56, 0x54, 0x72, 0x79, 0x53, 0x4f, 0x5a, 0x43, 0x67, +0x32, 0x62, 0x76, 0x77, 0x48, 0x4c, 0x2f, 0x4e, 0x70, 0x4d, 0x68, 0x62, 0x43, 0x50, 0x4f, 0x7a, +0x37, 0x42, 0x41, 0x6f, 0x7a, 0x48, 0x59, 0x71, 0x38, 0x6f, 0x36, 0x47, 0x42, 0x38, 0x76, 0x4c, +0x79, 0x6e, 0x2f, 0x2f, 0x38, 0x6f, 0x52, 0x41, 0x4e, 0x35, 0x35, 0x38, 0x50, 0x59, 0x37, 0x65, +0x69, 0x74, 0x49, 0x34, 0x6a, 0x36, 0x61, 0x54, 0x51, 0x47, 0x4f, 0x30, 0x6a, 0x70, 0x63, 0x64, +0x4a, 0x73, 0x2b, 0x39, 0x47, 0x43, 0x4d, 0x32, 0x5a, 0x77, 0x79, 0x5a, 0x6a, 0x54, 0x4d, 0x4c, +0x38, 0x44, 0x2b, 0x61, 0x41, 0x42, 0x70, 0x44, 0x47, 0x2b, 0x64, 0x6d, 0x64, 0x4a, 0x57, 0x44, +0x41, 0x6e, 0x37, 0x59, 0x42, 0x2f, 0x58, 0x49, 0x44, 0x2f, 0x37, 0x67, 0x76, 0x68, 0x39, 0x4a, +0x59, 0x4d, 0x30, 0x33, 0x62, 0x77, 0x7a, 0x7a, 0x36, 0x39, 0x69, 0x68, 0x4f, 0x5a, 0x70, 0x50, +0x64, 0x72, 0x6c, 0x71, 0x52, 0x63, 0x32, 0x69, 0x38, 0x72, 0x75, 0x4e, 0x33, 0x36, 0x63, 0x6d, +0x43, 0x68, 0x6c, 0x59, 0x66, 0x33, 0x77, 0x6a, 0x38, 0x73, 0x4a, 0x2b, 0x79, 0x49, 0x46, 0x68, +0x51, 0x6e, 0x61, 0x43, 0x75, 0x53, 0x4c, 0x41, 0x67, 0x42, 0x72, 0x77, 0x6e, 0x34, 0x2b, 0x30, +0x58, 0x53, 0x74, 0x50, 0x5a, 0x47, 0x61, 0x4c, 0x61, 0x62, 0x4f, 0x43, 0x33, 0x5a, 0x5a, 0x39, +0x7a, 0x34, 0x4b, 0x67, 0x69, 0x7a, 0x4c, 0x67, 0x62, 0x36, 0x43, 0x77, 0x62, 0x77, 0x32, 0x63, +0x2f, 0x37, 0x47, 0x44, 0x47, 0x63, 0x35, 0x38, 0x77, 0x5a, 0x38, 0x46, 0x36, 0x4e, 0x6d, 0x39, +0x72, 0x6f, 0x36, 0x36, 0x2f, 0x69, 0x39, 0x73, 0x66, 0x41, 0x47, 0x61, 0x53, 0x78, 0x43, 0x79, +0x56, 0x6d, 0x43, 0x30, 0x2b, 0x64, 0x46, 0x6f, 0x48, 0x6e, 0x77, 0x6e, 0x37, 0x6d, 0x4d, 0x38, +0x45, 0x78, 0x76, 0x69, 0x59, 0x74, 0x57, 0x37, 0x6c, 0x66, 0x39, 0x6c, 0x39, 0x37, 0x79, 0x48, +0x77, 0x52, 0x67, 0x72, 0x30, 0x58, 0x79, 0x45, 0x53, 0x31, 0x4a, 0x72, 0x7a, 0x68, 0x66, 0x55, +0x44, 0x64, 0x49, 0x59, 0x4d, 0x57, 0x37, 0x38, 0x55, 0x44, 0x4d, 0x31, 0x37, 0x6e, 0x4a, 0x48, +0x48, 0x57, 0x52, 0x4c, 0x4c, 0x2f, 0x65, 0x63, 0x2f, 0x77, 0x5a, 0x61, 0x35, 0x35, 0x39, 0x45, +0x6d, 0x44, 0x51, 0x56, 0x68, 0x67, 0x78, 0x42, 0x32, 0x47, 0x34, 0x43, 0x78, 0x79, 0x54, 0x78, +0x35, 0x53, 0x69, 0x41, 0x44, 0x34, 0x55, 0x39, 0x69, 0x41, 0x4e, 0x62, 0x78, 0x36, 0x6a, 0x70, +0x42, 0x41, 0x6b, 0x6e, 0x41, 0x46, 0x43, 0x77, 0x4a, 0x4b, 0x30, 0x6b, 0x6a, 0x73, 0x4a, 0x74, +0x78, 0x65, 0x64, 0x75, 0x42, 0x38, 0x45, 0x73, 0x66, 0x6f, 0x33, 0x32, 0x55, 0x6e, 0x34, 0x58, +0x30, 0x44, 0x51, 0x32, 0x4c, 0x63, 0x32, 0x6a, 0x5a, 0x58, 0x45, 0x70, 0x4a, 0x37, 0x31, 0x62, +0x71, 0x76, 0x38, 0x6d, 0x68, 0x62, 0x76, 0x78, 0x57, 0x5a, 0x45, 0x78, 0x5a, 0x62, 0x61, 0x34, +0x55, 0x77, 0x37, 0x64, 0x74, 0x49, 0x63, 0x74, 0x5a, 0x41, 0x43, 0x6d, 0x44, 0x73, 0x61, 0x76, +0x56, 0x45, 0x38, 0x76, 0x58, 0x74, 0x76, 0x2f, 0x46, 0x56, 0x2f, 0x4c, 0x57, 0x32, 0x73, 0x38, +0x7a, 0x54, 0x75, 0x71, 0x50, 0x6d, 0x78, 0x5a, 0x77, 0x78, 0x4e, 0x55, 0x54, 0x43, 0x59, 0x56, +0x44, 0x76, 0x4e, 0x47, 0x32, 0x69, 0x4f, 0x31, 0x72, 0x69, 0x7a, 0x4b, 0x65, 0x39, 0x39, 0x72, +0x74, 0x4d, 0x4e, 0x49, 0x49, 0x4f, 0x74, 0x66, 0x35, 0x62, 0x72, 0x74, 0x68, 0x39, 0x39, 0x6f, +0x36, 0x6e, 0x76, 0x71, 0x62, 0x75, 0x67, 0x4a, 0x6f, 0x74, 0x77, 0x33, 0x4a, 0x36, 0x79, 0x65, +0x5a, 0x2f, 0x67, 0x31, 0x63, 0x2b, 0x58, 0x6b, 0x78, 0x70, 0x77, 0x77, 0x31, 0x4e, 0x48, 0x57, +0x36, 0x36, 0x49, 0x6f, 0x78, 0x43, 0x65, 0x49, 0x49, 0x62, 0x56, 0x4b, 0x2b, 0x42, 0x37, 0x55, +0x43, 0x74, 0x59, 0x61, 0x79, 0x50, 0x4d, 0x4d, 0x31, 0x37, 0x34, 0x57, 0x35, 0x38, 0x4d, 0x61, +0x78, 0x48, 0x48, 0x33, 0x52, 0x52, 0x54, 0x53, 0x76, 0x57, 0x57, 0x4f, 0x39, 0x2b, 0x77, 0x37, +0x35, 0x46, 0x75, 0x7a, 0x31, 0x56, 0x66, 0x4a, 0x6e, 0x39, 0x33, 0x39, 0x61, 0x53, 0x6b, 0x72, +0x71, 0x36, 0x72, 0x67, 0x7a, 0x51, 0x32, 0x48, 0x56, 0x34, 0x46, 0x68, 0x62, 0x76, 0x35, 0x36, +0x7a, 0x7a, 0x7a, 0x75, 0x62, 0x59, 0x72, 0x71, 0x79, 0x7a, 0x69, 0x51, 0x66, 0x47, 0x68, 0x4a, +0x77, 0x34, 0x57, 0x44, 0x76, 0x4b, 0x77, 0x51, 0x68, 0x34, 0x62, 0x50, 0x50, 0x6c, 0x34, 0x6b, +0x56, 0x4d, 0x4d, 0x58, 0x38, 0x54, 0x59, 0x49, 0x69, 0x70, 0x30, 0x4e, 0x5a, 0x66, 0x2b, 0x72, +0x34, 0x42, 0x56, 0x73, 0x62, 0x43, 0x4c, 0x7a, 0x6b, 0x7a, 0x6b, 0x6b, 0x74, 0x4e, 0x4d, 0x62, +0x34, 0x6e, 0x48, 0x61, 0x36, 0x77, 0x49, 0x39, 0x64, 0x67, 0x5a, 0x49, 0x2b, 0x76, 0x35, 0x76, +0x59, 0x5a, 0x6b, 0x31, 0x68, 0x50, 0x32, 0x6b, 0x37, 0x4b, 0x42, 0x30, 0x70, 0x72, 0x64, 0x51, +0x6f, 0x44, 0x4d, 0x49, 0x6b, 0x72, 0x65, 0x36, 0x4c, 0x6d, 0x38, 0x69, 0x35, 0x62, 0x68, 0x44, +0x6e, 0x72, 0x6c, 0x36, 0x4f, 0x33, 0x72, 0x75, 0x63, 0x5a, 0x57, 0x2b, 0x33, 0x4d, 0x66, 0x69, +0x34, 0x51, 0x76, 0x53, 0x43, 0x78, 0x48, 0x5a, 0x42, 0x6b, 0x37, 0x41, 0x41, 0x30, 0x74, 0x75, +0x6c, 0x70, 0x45, 0x39, 0x4d, 0x2b, 0x45, 0x6e, 0x62, 0x77, 0x4e, 0x54, 0x74, 0x6e, 0x39, 0x51, +0x53, 0x46, 0x5a, 0x59, 0x75, 0x46, 0x56, 0x79, 0x69, 0x6c, 0x4b, 0x5a, 0x44, 0x68, 0x49, 0x6a, +0x34, 0x37, 0x52, 0x78, 0x66, 0x39, 0x44, 0x56, 0x6e, 0x37, 0x61, 0x58, 0x49, 0x47, 0x58, 0x30, +0x6d, 0x71, 0x30, 0x4e, 0x37, 0x38, 0x50, 0x37, 0x38, 0x62, 0x62, 0x77, 0x2f, 0x39, 0x31, 0x31, +0x2b, 0x57, 0x4e, 0x4e, 0x49, 0x72, 0x46, 0x4e, 0x67, 0x77, 0x68, 0x37, 0x68, 0x37, 0x44, 0x41, +0x68, 0x7a, 0x31, 0x36, 0x72, 0x50, 0x77, 0x4e, 0x76, 0x4c, 0x34, 0x46, 0x5a, 0x34, 0x30, 0x4f, +0x74, 0x78, 0x50, 0x7a, 0x47, 0x78, 0x36, 0x77, 0x57, 0x6d, 0x44, 0x64, 0x64, 0x6e, 0x78, 0x75, +0x42, 0x6d, 0x65, 0x56, 0x6a, 0x6a, 0x68, 0x47, 0x59, 0x79, 0x54, 0x37, 0x6d, 0x4f, 0x51, 0x46, +0x66, 0x53, 0x55, 0x79, 0x7a, 0x59, 0x36, 0x55, 0x57, 0x32, 0x70, 0x72, 0x30, 0x32, 0x6d, 0x55, +0x6f, 0x4e, 0x63, 0x55, 0x38, 0x44, 0x73, 0x36, 0x50, 0x4d, 0x65, 0x47, 0x30, 0x54, 0x73, 0x77, +0x6d, 0x67, 0x56, 0x45, 0x2b, 0x35, 0x35, 0x38, 0x6c, 0x65, 0x4b, 0x2b, 0x7a, 0x68, 0x59, 0x56, +0x4c, 0x69, 0x73, 0x67, 0x32, 0x78, 0x6a, 0x31, 0x34, 0x59, 0x68, 0x49, 0x6b, 0x46, 0x31, 0x53, +0x49, 0x72, 0x2f, 0x4c, 0x43, 0x54, 0x78, 0x33, 0x38, 0x77, 0x41, 0x71, 0x51, 0x49, 0x6c, 0x34, +0x6a, 0x58, 0x59, 0x4f, 0x31, 0x41, 0x4a, 0x54, 0x45, 0x54, 0x2f, 0x4a, 0x77, 0x47, 0x79, 0x33, +0x49, 0x4b, 0x34, 0x74, 0x52, 0x30, 0x6a, 0x66, 0x47, 0x75, 0x67, 0x57, 0x35, 0x52, 0x48, 0x4c, +0x41, 0x79, 0x46, 0x78, 0x6b, 0x54, 0x4c, 0x4c, 0x2b, 0x69, 0x32, 0x72, 0x36, 0x6a, 0x47, 0x31, +0x6e, 0x32, 0x34, 0x6f, 0x51, 0x6e, 0x69, 0x66, 0x35, 0x74, 0x6b, 0x64, 0x50, 0x2b, 0x74, 0x31, +0x78, 0x49, 0x37, 0x48, 0x36, 0x6a, 0x51, 0x53, 0x45, 0x46, 0x64, 0x71, 0x74, 0x52, 0x6f, 0x48, +0x4a, 0x46, 0x37, 0x43, 0x67, 0x78, 0x43, 0x30, 0x45, 0x71, 0x63, 0x6a, 0x70, 0x32, 0x35, 0x64, +0x35, 0x4c, 0x37, 0x37, 0x4a, 0x75, 0x58, 0x65, 0x4e, 0x79, 0x44, 0x79, 0x7a, 0x65, 0x2f, 0x51, +0x67, 0x5a, 0x78, 0x2b, 0x37, 0x4e, 0x33, 0x39, 0x72, 0x35, 0x33, 0x76, 0x63, 0x39, 0x2f, 0x4c, +0x7a, 0x47, 0x55, 0x2f, 0x62, 0x41, 0x4a, 0x51, 0x30, 0x53, 0x74, 0x53, 0x57, 0x68, 0x4d, 0x55, +0x52, 0x6d, 0x4c, 0x72, 0x70, 0x79, 0x54, 0x4d, 0x42, 0x46, 0x4e, 0x64, 0x49, 0x52, 0x53, 0x52, +0x50, 0x63, 0x53, 0x52, 0x77, 0x38, 0x4a, 0x65, 0x61, 0x67, 0x61, 0x56, 0x68, 0x4e, 0x72, 0x59, +0x61, 0x36, 0x79, 0x2f, 0x52, 0x74, 0x67, 0x36, 0x41, 0x63, 0x41, 0x34, 0x74, 0x6f, 0x52, 0x4f, +0x6c, 0x31, 0x6f, 0x52, 0x54, 0x43, 0x6c, 0x4a, 0x44, 0x33, 0x79, 0x4a, 0x6f, 0x66, 0x6a, 0x2f, +0x41, 0x46, 0x79, 0x54, 0x36, 0x50, 0x79, 0x68, 0x67, 0x6f, 0x64, 0x50, 0x75, 0x62, 0x39, 0x4c, +0x75, 0x48, 0x79, 0x41, 0x68, 0x61, 0x32, 0x2f, 0x61, 0x50, 0x2f, 0x50, 0x7a, 0x68, 0x36, 0x43, +0x35, 0x70, 0x59, 0x56, 0x51, 0x4b, 0x45, 0x53, 0x2f, 0x77, 0x67, 0x4b, 0x30, 0x7a, 0x67, 0x7a, +0x45, 0x31, 0x54, 0x66, 0x4e, 0x69, 0x30, 0x50, 0x4a, 0x53, 0x62, 0x35, 0x50, 0x30, 0x70, 0x36, +0x58, 0x74, 0x50, 0x73, 0x6e, 0x51, 0x35, 0x46, 0x33, 0x78, 0x59, 0x71, 0x38, 0x4b, 0x77, 0x55, +0x41, 0x75, 0x4f, 0x49, 0x57, 0x45, 0x71, 0x46, 0x77, 0x30, 0x53, 0x57, 0x72, 0x44, 0x49, 0x77, +0x57, 0x6d, 0x4d, 0x67, 0x4f, 0x7a, 0x6a, 0x6a, 0x4a, 0x4f, 0x6c, 0x79, 0x4e, 0x4a, 0x7a, 0x41, +0x36, 0x4e, 0x2b, 0x34, 0x50, 0x73, 0x74, 0x47, 0x53, 0x77, 0x41, 0x6c, 0x6f, 0x73, 0x2f, 0x47, +0x45, 0x55, 0x6b, 0x6e, 0x6d, 0x76, 0x59, 0x66, 0x2b, 0x66, 0x43, 0x64, 0x4c, 0x2f, 0x74, 0x34, +0x47, 0x4e, 0x51, 0x33, 0x49, 0x64, 0x65, 0x32, 0x4d, 0x48, 0x2f, 0x41, 0x44, 0x6a, 0x57, 0x37, +0x4f, 0x78, 0x6c, 0x38, 0x36, 0x63, 0x2f, 0x75, 0x54, 0x56, 0x2f, 0x72, 0x45, 0x75, 0x32, 0x4f, +0x31, 0x31, 0x68, 0x62, 0x4b, 0x4c, 0x68, 0x32, 0x53, 0x46, 0x6e, 0x77, 0x36, 0x6f, 0x34, 0x62, +0x42, 0x6f, 0x66, 0x56, 0x4d, 0x47, 0x74, 0x50, 0x49, 0x34, 0x46, 0x48, 0x37, 0x73, 0x4d, 0x44, +0x66, 0x6e, 0x65, 0x6e, 0x76, 0x4e, 0x6a, 0x4a, 0x33, 0x77, 0x55, 0x78, 0x32, 0x37, 0x6d, 0x78, +0x48, 0x75, 0x4a, 0x42, 0x32, 0x4b, 0x42, 0x4b, 0x4b, 0x31, 0x79, 0x6e, 0x55, 0x44, 0x6c, 0x75, +0x6a, 0x67, 0x58, 0x43, 0x78, 0x78, 0x50, 0x78, 0x65, 0x77, 0x41, 0x69, 0x42, 0x65, 0x55, 0x70, +0x67, 0x50, 0x6e, 0x44, 0x39, 0x50, 0x30, 0x70, 0x67, 0x73, 0x6e, 0x7a, 0x4d, 0x53, 0x77, 0x49, +0x7a, 0x54, 0x57, 0x41, 0x4f, 0x74, 0x6e, 0x34, 0x41, 0x46, 0x69, 0x68, 0x34, 0x79, 0x78, 0x47, +0x67, 0x74, 0x6e, 0x66, 0x61, 0x53, 0x56, 0x64, 0x57, 0x44, 0x4a, 0x33, 0x43, 0x30, 0x4c, 0x38, +0x49, 0x44, 0x75, 0x39, 0x33, 0x4c, 0x71, 0x61, 0x6a, 0x31, 0x72, 0x4b, 0x71, 0x49, 0x71, 0x46, +0x41, 0x63, 0x45, 0x54, 0x35, 0x61, 0x63, 0x79, 0x73, 0x66, 0x6f, 0x65, 0x51, 0x38, 0x41, 0x67, +0x62, 0x34, 0x31, 0x69, 0x74, 0x72, 0x54, 0x6c, 0x6b, 0x70, 0x4d, 0x53, 0x72, 0x71, 0x69, 0x62, +0x6b, 0x42, 0x6c, 0x63, 0x4c, 0x56, 0x2f, 0x68, 0x43, 0x43, 0x4a, 0x74, 0x30, 0x49, 0x78, 0x4e, +0x61, 0x58, 0x32, 0x73, 0x56, 0x68, 0x32, 0x4e, 0x71, 0x72, 0x50, 0x6e, 0x6f, 0x47, 0x55, 0x46, +0x2b, 0x4a, 0x49, 0x53, 0x57, 0x48, 0x6d, 0x53, 0x46, 0x67, 0x54, 0x41, 0x6a, 0x6a, 0x6d, 0x76, +0x6b, 0x32, 0x2f, 0x39, 0x55, 0x6b, 0x46, 0x57, 0x67, 0x30, 0x43, 0x49, 0x4c, 0x70, 0x54, 0x31, +0x4d, 0x79, 0x45, 0x50, 0x45, 0x50, 0x4c, 0x59, 0x74, 0x44, 0x31, 0x4e, 0x53, 0x73, 0x35, 0x4f, +0x43, 0x69, 0x68, 0x69, 0x44, 0x4e, 0x39, 0x57, 0x54, 0x58, 0x56, 0x6d, 0x56, 0x63, 0x52, 0x58, +0x4a, 0x50, 0x4b, 0x46, 0x73, 0x75, 0x77, 0x45, 0x4f, 0x75, 0x50, 0x51, 0x37, 0x2b, 0x48, 0x4a, +0x71, 0x35, 0x68, 0x42, 0x67, 0x68, 0x79, 0x48, 0x57, 0x73, 0x53, 0x50, 0x78, 0x76, 0x61, 0x41, +0x79, 0x30, 0x31, 0x6d, 0x46, 0x50, 0x74, 0x6a, 0x74, 0x53, 0x48, 0x57, 0x31, 0x57, 0x39, 0x31, +0x55, 0x58, 0x4a, 0x48, 0x46, 0x49, 0x62, 0x6a, 0x43, 0x31, 0x68, 0x4c, 0x45, 0x65, 0x66, 0x41, +0x39, 0x70, 0x5a, 0x42, 0x4b, 0x4f, 0x51, 0x43, 0x50, 0x4a, 0x6b, 0x53, 0x49, 0x33, 0x67, 0x55, +0x34, 0x79, 0x6e, 0x58, 0x6e, 0x31, 0x64, 0x59, 0x67, 0x74, 0x42, 0x66, 0x2f, 0x4c, 0x41, 0x4e, +0x76, 0x74, 0x2f, 0x5a, 0x51, 0x78, 0x6c, 0x6f, 0x42, 0x52, 0x4c, 0x53, 0x4e, 0x6f, 0x77, 0x68, +0x4a, 0x66, 0x6e, 0x57, 0x31, 0x55, 0x33, 0x62, 0x57, 0x42, 0x78, 0x4e, 0x58, 0x42, 0x6b, 0x6b, +0x59, 0x41, 0x43, 0x4f, 0x6c, 0x53, 0x35, 0x4b, 0x78, 0x45, 0x51, 0x4d, 0x4a, 0x6c, 0x42, 0x34, +0x33, 0x49, 0x4f, 0x50, 0x6a, 0x41, 0x35, 0x53, 0x48, 0x51, 0x73, 0x37, 0x4c, 0x6e, 0x77, 0x37, +0x50, 0x53, 0x52, 0x7a, 0x36, 0x70, 0x6e, 0x6d, 0x45, 0x68, 0x4c, 0x53, 0x63, 0x2f, 0x4f, 0x4a, +0x6e, 0x73, 0x50, 0x49, 0x47, 0x77, 0x70, 0x51, 0x4a, 0x53, 0x75, 0x36, 0x4f, 0x48, 0x32, 0x4e, +0x6c, 0x74, 0x6f, 0x66, 0x31, 0x4e, 0x66, 0x57, 0x71, 0x79, 0x43, 0x4b, 0x6f, 0x4f, 0x6b, 0x32, +0x34, 0x42, 0x6e, 0x51, 0x50, 0x77, 0x73, 0x55, 0x32, 0x74, 0x64, 0x79, 0x59, 0x5a, 0x67, 0x6a, +0x6e, 0x6b, 0x4e, 0x30, 0x33, 0x38, 0x65, 0x7a, 0x78, 0x2b, 0x53, 0x64, 0x74, 0x62, 0x6e, 0x35, +0x6b, 0x37, 0x4e, 0x41, 0x34, 0x70, 0x32, 0x4d, 0x59, 0x6b, 0x42, 0x73, 0x6c, 0x57, 0x62, 0x30, +0x71, 0x30, 0x46, 0x47, 0x4e, 0x31, 0x37, 0x63, 0x6e, 0x37, 0x54, 0x46, 0x44, 0x2f, 0x74, 0x68, +0x77, 0x48, 0x43, 0x50, 0x67, 0x2f, 0x4b, 0x30, 0x5a, 0x32, 0x39, 0x38, 0x7a, 0x72, 0x36, 0x65, +0x74, 0x61, 0x57, 0x41, 0x53, 0x30, 0x48, 0x61, 0x70, 0x5a, 0x46, 0x64, 0x57, 0x5a, 0x52, 0x2f, +0x41, 0x35, 0x35, 0x67, 0x42, 0x4f, 0x78, 0x6e, 0x38, 0x69, 0x34, 0x48, 0x38, 0x30, 0x4c, 0x6b, +0x66, 0x7a, 0x33, 0x37, 0x63, 0x7a, 0x70, 0x72, 0x31, 0x53, 0x78, 0x45, 0x78, 0x6e, 0x36, 0x72, +0x53, 0x50, 0x43, 0x70, 0x4b, 0x63, 0x68, 0x44, 0x53, 0x4a, 0x6a, 0x49, 0x4a, 0x6a, 0x52, 0x4e, +0x2b, 0x35, 0x56, 0x69, 0x35, 0x4a, 0x66, 0x70, 0x59, 0x43, 0x46, 0x30, 0x6a, 0x59, 0x55, 0x4d, +0x31, 0x35, 0x68, 0x45, 0x42, 0x39, 0x51, 0x72, 0x36, 0x75, 0x50, 0x34, 0x66, 0x4c, 0x43, 0x41, +0x6b, 0x6f, 0x62, 0x2b, 0x77, 0x6e, 0x76, 0x63, 0x56, 0x45, 0x6d, 0x35, 0x57, 0x63, 0x49, 0x57, +0x43, 0x58, 0x79, 0x74, 0x30, 0x4c, 0x58, 0x69, 0x48, 0x58, 0x39, 0x6c, 0x75, 0x74, 0x72, 0x65, +0x44, 0x4e, 0x74, 0x61, 0x4d, 0x30, 0x6c, 0x70, 0x67, 0x75, 0x56, 0x61, 0x74, 0x68, 0x39, 0x36, +0x71, 0x53, 0x58, 0x73, 0x7a, 0x53, 0x38, 0x38, 0x43, 0x65, 0x42, 0x71, 0x30, 0x42, 0x32, 0x48, +0x4e, 0x6d, 0x39, 0x4e, 0x32, 0x36, 0x34, 0x4b, 0x75, 0x49, 0x2b, 0x6e, 0x7a, 0x72, 0x75, 0x43, +0x35, 0x41, 0x50, 0x73, 0x74, 0x4f, 0x70, 0x68, 0x55, 0x64, 0x4a, 0x2b, 0x49, 0x6c, 0x2b, 0x66, +0x53, 0x41, 0x63, 0x57, 0x52, 0x51, 0x77, 0x44, 0x71, 0x41, 0x41, 0x69, 0x44, 0x63, 0x31, 0x77, +0x41, 0x36, 0x33, 0x2b, 0x39, 0x4c, 0x53, 0x4d, 0x4d, 0x4d, 0x68, 0x33, 0x45, 0x71, 0x7a, 0x4e, +0x38, 0x42, 0x72, 0x6a, 0x67, 0x62, 0x34, 0x66, 0x2b, 0x54, 0x30, 0x6a, 0x41, 0x46, 0x58, 0x2f, +0x38, 0x73, 0x4f, 0x62, 0x48, 0x34, 0x4a, 0x66, 0x70, 0x66, 0x52, 0x4b, 0x38, 0x51, 0x73, 0x43, +0x52, 0x74, 0x37, 0x64, 0x6a, 0x32, 0x6e, 0x51, 0x71, 0x31, 0x46, 0x61, 0x53, 0x67, 0x4a, 0x49, +0x47, 0x30, 0x4e, 0x76, 0x67, 0x65, 0x77, 0x41, 0x70, 0x31, 0x55, 0x41, 0x75, 0x58, 0x44, 0x56, +0x6a, 0x59, 0x4a, 0x79, 0x55, 0x39, 0x76, 0x2b, 0x41, 0x70, 0x47, 0x62, 0x37, 0x34, 0x34, 0x66, +0x2b, 0x54, 0x30, 0x6a, 0x41, 0x37, 0x79, 0x37, 0x38, 0x73, 0x44, 0x54, 0x54, 0x75, 0x48, 0x59, +0x33, 0x35, 0x73, 0x6e, 0x6e, 0x41, 0x47, 0x52, 0x76, 0x32, 0x47, 0x44, 0x37, 0x52, 0x73, 0x6f, +0x55, 0x42, 0x75, 0x54, 0x67, 0x74, 0x78, 0x52, 0x32, 0x5a, 0x4f, 0x78, 0x7a, 0x53, 0x79, 0x6b, +0x4a, 0x68, 0x55, 0x4a, 0x6f, 0x72, 0x52, 0x6b, 0x2f, 0x66, 0x69, 0x4f, 0x70, 0x49, 0x79, 0x37, +0x5a, 0x2f, 0x74, 0x6b, 0x46, 0x36, 0x42, 0x43, 0x32, 0x46, 0x71, 0x78, 0x4f, 0x76, 0x44, 0x36, +0x65, 0x30, 0x4c, 0x55, 0x4e, 0x4a, 0x33, 0x35, 0x2b, 0x41, 0x47, 0x4b, 0x6e, 0x77, 0x58, 0x68, +0x68, 0x70, 0x4e, 0x61, 0x59, 0x49, 0x4e, 0x66, 0x43, 0x42, 0x4b, 0x58, 0x75, 0x6a, 0x53, 0x73, +0x6b, 0x45, 0x77, 0x69, 0x35, 0x43, 0x78, 0x55, 0x4b, 0x42, 0x59, 0x57, 0x47, 0x34, 0x74, 0x46, +0x76, 0x70, 0x4c, 0x5a, 0x52, 0x61, 0x34, 0x62, 0x63, 0x4e, 0x67, 0x51, 0x32, 0x4a, 0x67, 0x33, +0x79, 0x4c, 0x67, 0x62, 0x67, 0x69, 0x4f, 0x49, 0x2f, 0x38, 0x6e, 0x6c, 0x44, 0x4c, 0x73, 0x31, +0x4c, 0x6f, 0x74, 0x68, 0x53, 0x65, 0x65, 0x6e, 0x55, 0x7a, 0x4f, 0x6b, 0x73, 0x79, 0x38, 0x6e, +0x73, 0x79, 0x74, 0x44, 0x65, 0x76, 0x68, 0x31, 0x39, 0x47, 0x75, 0x69, 0x33, 0x4d, 0x76, 0x54, +0x2f, 0x5a, 0x2b, 0x37, 0x5a, 0x78, 0x32, 0x66, 0x6f, 0x2f, 0x7a, 0x43, 0x77, 0x48, 0x44, 0x77, +0x65, 0x77, 0x71, 0x54, 0x51, 0x31, 0x6b, 0x72, 0x59, 0x4d, 0x42, 0x6c, 0x71, 0x38, 0x74, 0x31, +0x50, 0x51, 0x51, 0x64, 0x2b, 0x6d, 0x66, 0x6b, 0x50, 0x6c, 0x58, 0x31, 0x42, 0x39, 0x77, 0x49, +0x55, 0x4b, 0x4f, 0x72, 0x75, 0x30, 0x72, 0x69, 0x67, 0x78, 0x52, 0x75, 0x62, 0x53, 0x67, 0x70, +0x70, 0x4e, 0x66, 0x41, 0x57, 0x6f, 0x44, 0x4c, 0x70, 0x46, 0x77, 0x31, 0x30, 0x30, 0x45, 0x35, +0x5a, 0x6c, 0x2f, 0x74, 0x58, 0x50, 0x4d, 0x53, 0x75, 0x73, 0x62, 0x44, 0x70, 0x62, 0x4e, 0x54, +0x4a, 0x30, 0x68, 0x45, 0x42, 0x76, 0x72, 0x77, 0x35, 0x74, 0x55, 0x55, 0x42, 0x46, 0x4e, 0x4f, +0x6c, 0x61, 0x6c, 0x70, 0x73, 0x76, 0x6d, 0x39, 0x70, 0x30, 0x70, 0x32, 0x66, 0x49, 0x6d, 0x56, +0x67, 0x64, 0x6a, 0x73, 0x41, 0x6f, 0x70, 0x4b, 0x62, 0x72, 0x7a, 0x6d, 0x45, 0x77, 0x66, 0x33, +0x4c, 0x65, 0x58, 0x44, 0x61, 0x6c, 0x38, 0x79, 0x66, 0x75, 0x52, 0x79, 0x30, 0x52, 0x75, 0x32, +0x34, 0x42, 0x61, 0x30, 0x31, 0x57, 0x56, 0x6c, 0x2f, 0x41, 0x74, 0x6f, 0x34, 0x2f, 0x62, 0x4b, +0x6a, 0x47, 0x62, 0x31, 0x48, 0x46, 0x56, 0x65, 0x64, 0x2b, 0x7a, 0x78, 0x32, 0x41, 0x36, 0x6a, +0x68, 0x62, 0x32, 0x2f, 0x59, 0x61, 0x45, 0x44, 0x41, 0x72, 0x35, 0x58, 0x38, 0x63, 0x4f, 0x6c, +0x74, 0x54, 0x76, 0x34, 0x65, 0x42, 0x58, 0x4a, 0x68, 0x62, 0x76, 0x62, 0x31, 0x7a, 0x41, 0x6b, +0x4e, 0x35, 0x76, 0x70, 0x58, 0x57, 0x72, 0x67, 0x78, 0x4e, 0x4a, 0x33, 0x69, 0x69, 0x4f, 0x53, +0x4b, 0x68, 0x6f, 0x4f, 0x34, 0x6f, 0x50, 0x39, 0x79, 0x6a, 0x74, 0x36, 0x2f, 0x46, 0x37, 0x39, +0x2b, 0x4c, 0x6c, 0x6b, 0x39, 0x61, 0x4e, 0x49, 0x6e, 0x56, 0x6e, 0x50, 0x7a, 0x36, 0x33, 0x61, +0x41, 0x51, 0x31, 0x32, 0x5a, 0x4e, 0x33, 0x56, 0x6a, 0x49, 0x34, 0x55, 0x44, 0x42, 0x2b, 0x35, +0x53, 0x6b, 0x4a, 0x65, 0x54, 0x69, 0x69, 0x31, 0x50, 0x48, 0x67, 0x4c, 0x53, 0x68, 0x69, 0x4c, +0x39, 0x73, 0x51, 0x41, 0x4f, 0x53, 0x2f, 0x6f, 0x39, 0x2b, 0x66, 0x6f, 0x66, 0x55, 0x79, 0x54, +0x42, 0x39, 0x53, 0x4f, 0x37, 0x74, 0x4e, 0x6f, 0x65, 0x4f, 0x56, 0x69, 0x45, 0x72, 0x41, 0x61, +0x36, 0x34, 0x52, 0x79, 0x79, 0x78, 0x38, 0x51, 0x43, 0x57, 0x37, 0x4d, 0x68, 0x4f, 0x4b, 0x52, +0x6b, 0x79, 0x2f, 0x32, 0x72, 0x43, 0x52, 0x47, 0x4b, 0x4b, 0x79, 0x4b, 0x74, 0x4e, 0x54, 0x49, +0x61, 0x5a, 0x65, 0x75, 0x41, 0x41, 0x53, 0x6e, 0x50, 0x70, 0x49, 0x48, 0x78, 0x7a, 0x4b, 0x63, +0x73, 0x37, 0x32, 0x75, 0x6d, 0x50, 0x33, 0x38, 0x66, 0x41, 0x45, 0x65, 0x66, 0x63, 0x54, 0x6d, +0x74, 0x73, 0x54, 0x33, 0x69, 0x5a, 0x38, 0x7a, 0x6e, 0x6c, 0x35, 0x53, 0x6d, 0x74, 0x54, 0x76, +0x35, 0x2f, 0x5a, 0x4d, 0x39, 0x34, 0x59, 0x70, 0x54, 0x73, 0x4e, 0x6f, 0x34, 0x45, 0x37, 0x42, +0x2f, 0x56, 0x34, 0x6a, 0x67, 0x43, 0x50, 0x42, 0x30, 0x49, 0x41, 0x41, 0x52, 0x39, 0x77, 0x70, +0x79, 0x47, 0x64, 0x49, 0x6e, 0x55, 0x43, 0x55, 0x50, 0x2f, 0x65, 0x30, 0x59, 0x44, 0x68, 0x2f, +0x73, 0x55, 0x7a, 0x4e, 0x68, 0x37, 0x33, 0x68, 0x37, 0x49, 0x69, 0x6d, 0x73, 0x73, 0x74, 0x71, +0x79, 0x79, 0x70, 0x62, 0x6d, 0x42, 0x42, 0x46, 0x52, 0x42, 0x79, 0x55, 0x4d, 0x53, 0x30, 0x4c, +0x39, 0x42, 0x4f, 0x61, 0x73, 0x6a, 0x46, 0x44, 0x47, 0x7a, 0x46, 0x42, 0x61, 0x7a, 0x39, 0x33, +0x42, 0x75, 0x48, 0x5a, 0x6c, 0x64, 0x72, 0x5a, 0x62, 0x38, 0x33, 0x76, 0x71, 0x56, 0x4e, 0x67, +0x66, 0x7a, 0x41, 0x4b, 0x4e, 0x46, 0x39, 0x56, 0x63, 0x72, 0x77, 0x74, 0x70, 0x46, 0x5a, 0x34, +0x46, 0x64, 0x6b, 0x67, 0x50, 0x4b, 0x63, 0x4d, 0x67, 0x63, 0x73, 0x6d, 0x53, 0x5a, 0x33, 0x57, +0x39, 0x66, 0x33, 0x65, 0x73, 0x75, 0x46, 0x4c, 0x68, 0x68, 0x57, 0x77, 0x48, 0x74, 0x4d, 0x55, +0x6b, 0x30, 0x6f, 0x68, 0x45, 0x53, 0x6e, 0x50, 0x41, 0x43, 0x76, 0x75, 0x45, 0x68, 0x57, 0x49, +0x2b, 0x65, 0x4e, 0x31, 0x52, 0x41, 0x42, 0x68, 0x6a, 0x36, 0x61, 0x73, 0x72, 0x69, 0x77, 0x58, +0x39, 0x61, 0x67, 0x52, 0x37, 0x39, 0x2f, 0x48, 0x4a, 0x51, 0x37, 0x4b, 0x75, 0x4c, 0x59, 0x63, +0x5a, 0x43, 0x7a, 0x54, 0x72, 0x74, 0x33, 0x6d, 0x4f, 0x4d, 0x4e, 0x53, 0x61, 0x38, 0x49, 0x39, +0x65, 0x2b, 0x31, 0x66, 0x6f, 0x6b, 0x4e, 0x78, 0x7a, 0x79, 0x2b, 0x48, 0x6b, 0x35, 0x55, 0x51, +0x59, 0x4e, 0x37, 0x49, 0x58, 0x54, 0x39, 0x31, 0x31, 0x46, 0x4b, 0x2b, 0x39, 0x56, 0x78, 0x65, +0x66, 0x50, 0x4a, 0x37, 0x6e, 0x63, 0x66, 0x56, 0x39, 0x78, 0x2b, 0x46, 0x4c, 0x52, 0x58, 0x59, +0x6b, 0x78, 0x4b, 0x39, 0x2b, 0x4d, 0x5a, 0x43, 0x39, 0x50, 0x37, 0x75, 0x53, 0x5a, 0x36, 0x64, +0x2f, 0x7a, 0x37, 0x51, 0x37, 0x48, 0x34, 0x61, 0x6d, 0x37, 0x74, 0x75, 0x76, 0x59, 0x6f, 0x37, +0x52, 0x4e, 0x69, 0x4b, 0x52, 0x5a, 0x47, 0x43, 0x31, 0x66, 0x57, 0x77, 0x36, 0x46, 0x79, 0x2f, +0x50, 0x35, 0x6a, 0x2b, 0x50, 0x39, 0x4f, 0x65, 0x73, 0x33, 0x2f, 0x63, 0x6d, 0x74, 0x6d, 0x51, +0x41, 0x74, 0x4c, 0x56, 0x79, 0x64, 0x4b, 0x2f, 0x65, 0x46, 0x50, 0x51, 0x34, 0x67, 0x51, 0x2b, +0x57, 0x53, 0x61, 0x36, 0x75, 0x61, 0x30, 0x51, 0x4a, 0x54, 0x5a, 0x75, 0x77, 0x48, 0x6e, 0x4a, +0x69, 0x6e, 0x55, 0x68, 0x74, 0x36, 0x46, 0x52, 0x68, 0x58, 0x6e, 0x37, 0x79, 0x4c, 0x30, 0x51, +0x69, 0x45, 0x62, 0x49, 0x69, 0x45, 0x5a, 0x59, 0x74, 0x57, 0x38, 0x62, 0x75, 0x75, 0x77, 0x38, +0x48, 0x4c, 0x79, 0x69, 0x53, 0x41, 0x6b, 0x51, 0x69, 0x6d, 0x4d, 0x73, 0x76, 0x4a, 0x39, 0x7a, +0x61, 0x32, 0x69, 0x32, 0x55, 0x4e, 0x52, 0x75, 0x6f, 0x6d, 0x7a, 0x72, 0x56, 0x44, 0x71, 0x39, +0x62, 0x4c, 0x65, 0x49, 0x49, 0x78, 0x6f, 0x41, 0x46, 0x4f, 0x65, 0x6d, 0x36, 0x35, 0x4e, 0x54, +0x69, 0x72, 0x78, 0x77, 0x55, 0x74, 0x74, 0x68, 0x42, 0x67, 0x64, 0x4f, 0x76, 0x4a, 0x77, 0x6e, +0x4b, 0x48, 0x47, 0x77, 0x6a, 0x67, 0x75, 0x30, 0x4d, 0x51, 0x72, 0x44, 0x65, 0x58, 0x5a, 0x2f, +0x4d, 0x4b, 0x6d, 0x32, 0x30, 0x5a, 0x6f, 0x52, 0x53, 0x6a, 0x4a, 0x57, 0x4b, 0x4f, 0x65, 0x37, +0x36, 0x54, 0x36, 0x54, 0x6b, 0x65, 0x79, 0x48, 0x34, 0x56, 0x45, 0x70, 0x62, 0x59, 0x55, 0x67, +0x6d, 0x73, 0x30, 0x71, 0x48, 0x75, 0x50, 0x6e, 0x4d, 0x75, 0x77, 0x45, 0x50, 0x72, 0x52, 0x57, +0x2b, 0x45, 0x70, 0x53, 0x58, 0x56, 0x62, 0x6a, 0x69, 0x4c, 0x6b, 0x6c, 0x62, 0x53, 0x53, 0x48, +0x49, 0x75, 0x6e, 0x67, 0x79, 0x61, 0x47, 0x4d, 0x68, 0x31, 0x6b, 0x4b, 0x77, 0x2f, 0x4b, 0x6d, +0x2f, 0x55, 0x35, 0x62, 0x33, 0x4e, 0x65, 0x76, 0x57, 0x68, 0x49, 0x47, 0x72, 0x6d, 0x66, 0x33, +0x70, 0x45, 0x4c, 0x35, 0x65, 0x75, 0x4a, 0x37, 0x73, 0x37, 0x47, 0x57, 0x38, 0x38, 0x63, 0x35, +0x65, 0x72, 0x46, 0x68, 0x64, 0x7a, 0x6f, 0x68, 0x62, 0x32, 0x73, 0x6b, 0x4a, 0x71, 0x2f, 0x68, +0x57, 0x4b, 0x6e, 0x6b, 0x37, 0x32, 0x74, 0x62, 0x51, 0x77, 0x4c, 0x69, 0x52, 0x49, 0x7a, 0x6c, +0x78, 0x30, 0x6c, 0x53, 0x6d, 0x6a, 0x34, 0x54, 0x4e, 0x70, 0x52, 0x72, 0x74, 0x2f, 0x77, 0x78, +0x57, 0x34, 0x79, 0x65, 0x6d, 0x41, 0x78, 0x33, 0x63, 0x63, 0x50, 0x32, 0x68, 0x46, 0x42, 0x64, +0x30, 0x6b, 0x70, 0x73, 0x54, 0x5a, 0x55, 0x74, 0x6a, 0x49, 0x5a, 0x32, 0x78, 0x6b, 0x4d, 0x58, +0x45, 0x4f, 0x48, 0x2f, 0x42, 0x36, 0x48, 0x47, 0x39, 0x2b, 0x50, 0x57, 0x76, 0x2b, 0x70, 0x44, +0x58, 0x73, 0x49, 0x62, 0x73, 0x68, 0x2f, 0x36, 0x4b, 0x4f, 0x65, 0x6d, 0x6b, 0x2b, 0x50, 0x68, +0x46, 0x55, 0x6c, 0x68, 0x6c, 0x58, 0x51, 0x55, 0x59, 0x70, 0x51, 0x57, 0x45, 0x6c, 0x66, 0x55, +0x67, 0x42, 0x69, 0x39, 0x66, 0x59, 0x46, 0x5a, 0x30, 0x68, 0x54, 0x4a, 0x36, 0x45, 0x54, 0x4a, +0x44, 0x61, 0x51, 0x56, 0x51, 0x65, 0x6f, 0x69, 0x46, 0x4e, 0x7a, 0x56, 0x39, 0x61, 0x4a, 0x45, +0x54, 0x58, 0x51, 0x39, 0x33, 0x72, 0x63, 0x46, 0x55, 0x31, 0x30, 0x4f, 0x6a, 0x67, 0x68, 0x32, +0x4b, 0x44, 0x56, 0x4c, 0x52, 0x4c, 0x41, 0x31, 0x43, 0x4a, 0x46, 0x37, 0x47, 0x31, 0x32, 0x69, +0x78, 0x6f, 0x69, 0x75, 0x55, 0x4d, 0x70, 0x30, 0x56, 0x56, 0x79, 0x6d, 0x30, 0x45, 0x52, 0x52, +0x45, 0x46, 0x4d, 0x6f, 0x49, 0x4a, 0x76, 0x62, 0x30, 0x65, 0x48, 0x68, 0x64, 0x4f, 0x32, 0x31, +0x53, 0x30, 0x42, 0x4c, 0x7a, 0x38, 0x55, 0x30, 0x53, 0x4b, 0x32, 0x78, 0x38, 0x32, 0x54, 0x46, +0x73, 0x32, 0x64, 0x47, 0x4f, 0x55, 0x6f, 0x62, 0x71, 0x55, 0x70, 0x38, 0x52, 0x64, 0x61, 0x33, +0x49, 0x2b, 0x68, 0x39, 0x6f, 0x62, 0x61, 0x33, 0x47, 0x6f, 0x34, 0x7a, 0x61, 0x67, 0x65, 0x73, +0x34, 0x64, 0x46, 0x41, 0x37, 0x30, 0x7a, 0x62, 0x33, 0x59, 0x57, 0x31, 0x44, 0x79, 0x4b, 0x49, +0x4e, 0x4b, 0x77, 0x75, 0x78, 0x6e, 0x47, 0x78, 0x57, 0x75, 0x64, 0x56, 0x76, 0x62, 0x57, 0x50, +0x6c, 0x68, 0x70, 0x32, 0x4d, 0x48, 0x4e, 0x53, 0x44, 0x6e, 0x63, 0x31, 0x52, 0x6d, 0x6c, 0x70, +0x6a, 0x38, 0x59, 0x46, 0x65, 0x31, 0x39, 0x42, 0x4d, 0x4e, 0x43, 0x62, 0x4a, 0x7a, 0x67, 0x36, +0x7a, 0x74, 0x71, 0x47, 0x46, 0x36, 0x73, 0x70, 0x38, 0x5a, 0x31, 0x4a, 0x4b, 0x79, 0x45, 0x35, +0x72, 0x76, 0x31, 0x41, 0x49, 0x49, 0x31, 0x42, 0x53, 0x63, 0x65, 0x4a, 0x75, 0x74, 0x75, 0x2b, +0x6e, 0x66, 0x57, 0x2f, 0x44, 0x68, 0x72, 0x37, 0x30, 0x38, 0x62, 0x32, 0x6b, 0x39, 0x6b, 0x66, +0x67, 0x71, 0x61, 0x5a, 0x48, 0x79, 0x46, 0x6c, 0x65, 0x52, 0x75, 0x54, 0x7a, 0x44, 0x38, 0x68, +0x71, 0x62, 0x6b, 0x56, 0x33, 0x64, 0x4a, 0x42, 0x64, 0x58, 0x6b, 0x4a, 0x55, 0x68, 0x4e, 0x69, +0x76, 0x4d, 0x38, 0x61, 0x38, 0x39, 0x6e, 0x45, 0x30, 0x69, 0x54, 0x43, 0x44, 0x39, 0x39, 0x30, +0x33, 0x4a, 0x56, 0x62, 0x65, 0x76, 0x4f, 0x52, 0x72, 0x49, 0x49, 0x71, 0x57, 0x6b, 0x70, 0x56, +0x72, 0x56, 0x72, 0x4f, 0x31, 0x6f, 0x51, 0x45, 0x70, 0x42, 0x48, 0x76, 0x75, 0x74, 0x56, 0x64, +0x69, 0x30, 0x69, 0x74, 0x6c, 0x69, 0x32, 0x73, 0x32, 0x4e, 0x58, 0x55, 0x4c, 0x5a, 0x58, 0x30, +0x66, 0x4f, 0x49, 0x51, 0x69, 0x32, 0x6a, 0x64, 0x75, 0x54, 0x6a, 0x6a, 0x58, 0x68, 0x42, 0x56, +0x2b, 0x35, 0x5a, 0x79, 0x77, 0x4e, 0x67, 0x4a, 0x68, 0x38, 0x77, 0x38, 0x73, 0x4d, 0x6c, 0x46, +0x51, 0x57, 0x46, 0x76, 0x44, 0x55, 0x79, 0x53, 0x67, 0x78, 0x47, 0x70, 0x6a, 0x50, 0x62, 0x46, +0x73, 0x42, 0x31, 0x70, 0x79, 0x54, 0x4d, 0x52, 0x61, 0x2b, 0x48, 0x47, 0x61, 0x74, 0x37, 0x67, +0x54, 0x4f, 0x65, 0x61, 0x54, 0x30, 0x39, 0x53, 0x5a, 0x78, 0x4f, 0x72, 0x73, 0x2b, 0x73, 0x2b, +0x78, 0x53, 0x6b, 0x39, 0x51, 0x69, 0x68, 0x46, 0x43, 0x38, 0x4a, 0x68, 0x53, 0x33, 0x4f, 0x44, +0x38, 0x4d, 0x4c, 0x63, 0x4c, 0x77, 0x55, 0x6d, 0x2b, 0x34, 0x48, 0x50, 0x68, 0x73, 0x79, 0x77, +0x54, 0x71, 0x37, 0x53, 0x42, 0x68, 0x70, 0x61, 0x74, 0x4b, 0x4b, 0x33, 0x6f, 0x46, 0x41, 0x35, +0x51, 0x35, 0x61, 0x58, 0x35, 0x6a, 0x72, 0x54, 0x42, 0x58, 0x37, 0x30, 0x57, 0x57, 0x2b, 0x5a, +0x64, 0x45, 0x4b, 0x36, 0x70, 0x52, 0x67, 0x4e, 0x2f, 0x75, 0x6e, 0x51, 0x36, 0x63, 0x44, 0x7a, +0x7a, 0x35, 0x70, 0x63, 0x77, 0x64, 0x6f, 0x39, 0x35, 0x46, 0x4f, 0x5a, 0x33, 0x67, 0x46, 0x59, +0x63, 0x66, 0x66, 0x41, 0x6d, 0x4a, 0x6e, 0x39, 0x34, 0x43, 0x6f, 0x33, 0x6e, 0x6e, 0x45, 0x73, +0x75, 0x4d, 0x56, 0x4c, 0x4b, 0x7a, 0x66, 0x73, 0x2b, 0x34, 0x54, 0x36, 0x39, 0x57, 0x66, 0x6e, +0x53, 0x79, 0x78, 0x77, 0x41, 0x39, 0x47, 0x38, 0x30, 0x54, 0x48, 0x79, 0x35, 0x6e, 0x71, 0x66, +0x33, 0x55, 0x79, 0x77, 0x59, 0x59, 0x4f, 0x6e, 0x4e, 0x6c, 0x4d, 0x4f, 0x57, 0x70, 0x49, 0x4c, +0x4b, 0x45, 0x6a, 0x69, 0x53, 0x32, 0x6f, 0x4a, 0x61, 0x4e, 0x2f, 0x65, 0x7a, 0x79, 0x63, 0x34, +0x53, 0x54, 0x44, 0x72, 0x36, 0x46, 0x58, 0x4a, 0x7a, 0x4f, 0x72, 0x6e, 0x72, 0x79, 0x63, 0x4e, +0x59, 0x76, 0x36, 0x34, 0x4b, 0x49, 0x51, 0x56, 0x35, 0x65, 0x57, 0x48, 0x4f, 0x6e, 0x44, 0x53, +0x4d, 0x63, 0x55, 0x4e, 0x79, 0x4b, 0x62, 0x37, 0x2f, 0x4a, 0x73, 0x7a, 0x73, 0x75, 0x66, 0x45, +0x4b, 0x78, 0x39, 0x37, 0x31, 0x4e, 0x37, 0x44, 0x6f, 0x32, 0x6f, 0x6c, 0x45, 0x30, 0x48, 0x5a, +0x2f, 0x6f, 0x35, 0x78, 0x6e, 0x55, 0x69, 0x71, 0x42, 0x4e, 0x73, 0x72, 0x47, 0x43, 0x2b, 0x4d, +0x30, 0x31, 0x44, 0x59, 0x30, 0x6c, 0x77, 0x6e, 0x4b, 0x4f, 0x4c, 0x4d, 0x74, 0x55, 0x64, 0x67, +0x67, 0x79, 0x34, 0x76, 0x51, 0x49, 0x6c, 0x72, 0x59, 0x31, 0x42, 0x6d, 0x6a, 0x70, 0x52, 0x58, +0x4f, 0x4f, 0x58, 0x77, 0x71, 0x48, 0x6d, 0x47, 0x65, 0x2b, 0x75, 0x70, 0x44, 0x43, 0x6f, 0x75, +0x67, 0x4f, 0x69, 0x2b, 0x48, 0x6b, 0x71, 0x78, 0x69, 0x68, 0x45, 0x6b, 0x4d, 0x33, 0x57, 0x48, +0x73, 0x78, 0x42, 0x78, 0x72, 0x6f, 0x46, 0x54, 0x42, 0x61, 0x51, 0x72, 0x7a, 0x6b, 0x4c, 0x41, +0x6b, 0x69, 0x62, 0x35, 0x4e, 0x50, 0x68, 0x4b, 0x2b, 0x44, 0x56, 0x45, 0x69, 0x64, 0x4a, 0x66, +0x36, 0x36, 0x68, 0x70, 0x49, 0x61, 0x62, 0x2b, 0x78, 0x53, 0x75, 0x75, 0x63, 0x6d, 0x68, 0x42, +0x50, 0x31, 0x58, 0x64, 0x53, 0x6b, 0x64, 0x75, 0x50, 0x6a, 0x39, 0x6f, 0x72, 0x38, 0x66, 0x55, +0x63, 0x4d, 0x44, 0x45, 0x6d, 0x31, 0x33, 0x72, 0x63, 0x74, 0x6a, 0x70, 0x52, 0x64, 0x44, 0x51, +0x41, 0x67, 0x78, 0x75, 0x64, 0x79, 0x50, 0x66, 0x76, 0x57, 0x36, 0x4d, 0x5a, 0x56, 0x65, 0x33, +0x7a, 0x7a, 0x4c, 0x72, 0x42, 0x7a, 0x46, 0x6a, 0x58, 0x67, 0x7a, 0x47, 0x37, 0x6c, 0x7a, 0x44, +0x72, 0x32, 0x51, 0x4b, 0x75, 0x4f, 0x4f, 0x78, 0x4c, 0x4c, 0x6a, 0x76, 0x42, 0x38, 0x50, 0x75, +0x48, 0x48, 0x41, 0x47, 0x6c, 0x56, 0x46, 0x59, 0x42, 0x2b, 0x42, 0x49, 0x68, 0x4e, 0x53, 0x64, +0x4e, 0x32, 0x49, 0x33, 0x65, 0x50, 0x59, 0x75, 0x49, 0x68, 0x43, 0x45, 0x63, 0x39, 0x75, 0x69, +0x4d, 0x69, 0x66, 0x6a, 0x6b, 0x36, 0x65, 0x67, 0x55, 0x43, 0x4b, 0x6d, 0x34, 0x35, 0x76, 0x78, +0x78, 0x46, 0x42, 0x64, 0x6b, 0x30, 0x64, 0x72, 0x68, 0x4f, 0x78, 0x37, 0x48, 0x44, 0x72, 0x64, +0x79, 0x75, 0x66, 0x59, 0x72, 0x52, 0x55, 0x47, 0x4f, 0x59, 0x45, 0x65, 0x6e, 0x77, 0x6d, 0x2f, +0x7a, 0x4f, 0x62, 0x56, 0x4f, 0x67, 0x68, 0x48, 0x38, 0x2f, 0x58, 0x4d, 0x66, 0x6b, 0x65, 0x64, +0x54, 0x6d, 0x43, 0x76, 0x59, 0x33, 0x4f, 0x70, 0x77, 0x42, 0x4b, 0x37, 0x39, 0x62, 0x78, 0x66, +0x75, 0x79, 0x36, 0x52, 0x2b, 0x67, 0x38, 0x6b, 0x74, 0x79, 0x4b, 0x58, 0x44, 0x58, 0x77, 0x39, +0x6c, 0x46, 0x57, 0x54, 0x33, 0x37, 0x63, 0x32, 0x32, 0x4e, 0x59, 0x30, 0x73, 0x4a, 0x59, 0x2f, +0x4f, 0x4a, 0x68, 0x43, 0x2b, 0x7a, 0x57, 0x4f, 0x76, 0x71, 0x57, 0x67, 0x6b, 0x72, 0x47, 0x4d, +0x73, 0x71, 0x61, 0x39, 0x43, 0x43, 0x74, 0x76, 0x2b, 0x55, 0x43, 0x54, 0x43, 0x30, 0x4b, 0x48, +0x44, 0x61, 0x47, 0x31, 0x72, 0x54, 0x78, 0x58, 0x2b, 0x41, 0x44, 0x73, 0x51, 0x37, 0x2f, 0x50, +0x4d, 0x34, 0x33, 0x38, 0x74, 0x74, 0x33, 0x4a, 0x74, 0x79, 0x63, 0x46, 0x73, 0x36, 0x47, 0x69, +0x33, 0x43, 0x6b, 0x5a, 0x5a, 0x4e, 0x4b, 0x62, 0x76, 0x51, 0x43, 0x30, 0x4a, 0x55, 0x68, 0x56, +0x48, 0x74, 0x4f, 0x46, 0x62, 0x38, 0x6f, 0x32, 0x2b, 0x46, 0x55, 0x58, 0x4d, 0x5a, 0x43, 0x4f, +0x61, 0x6a, 0x7a, 0x44, 0x61, 0x49, 0x4e, 0x45, 0x38, 0x65, 0x74, 0x74, 0x67, 0x6f, 0x6c, 0x6b, +0x32, 0x46, 0x79, 0x4a, 0x71, 0x6f, 0x67, 0x79, 0x49, 0x39, 0x47, 0x64, 0x45, 0x39, 0x67, 0x68, +0x65, 0x61, 0x33, 0x32, 0x64, 0x6d, 0x49, 0x37, 0x68, 0x68, 0x78, 0x52, 0x65, 0x70, 0x38, 0x2b, +0x74, 0x78, 0x33, 0x31, 0x4f, 0x62, 0x6a, 0x44, 0x2b, 0x51, 0x49, 0x6b, 0x32, 0x64, 0x43, 0x6a, +0x46, 0x4d, 0x4b, 0x58, 0x59, 0x57, 0x77, 0x6a, 0x2b, 0x71, 0x52, 0x52, 0x6e, 0x2b, 0x44, 0x37, +0x72, 0x48, 0x42, 0x54, 0x36, 0x4a, 0x4f, 0x48, 0x7a, 0x73, 0x66, 0x44, 0x35, 0x76, 0x53, 0x2b, +0x34, 0x77, 0x53, 0x6d, 0x41, 0x63, 0x68, 0x48, 0x67, 0x4d, 0x4a, 0x7a, 0x56, 0x70, 0x56, 0x33, +0x68, 0x54, 0x79, 0x33, 0x6a, 0x53, 0x4d, 0x7a, 0x56, 0x69, 0x2b, 0x65, 0x67, 0x74, 0x61, 0x5a, +0x32, 0x36, 0x48, 0x6a, 0x72, 0x2b, 0x42, 0x59, 0x2b, 0x61, 0x4f, 0x30, 0x59, 0x70, 0x55, 0x53, +0x53, 0x41, 0x74, 0x4a, 0x73, 0x33, 0x6c, 0x4c, 0x49, 0x34, 0x4c, 0x6f, 0x51, 0x68, 0x62, 0x6d, +0x53, 0x6a, 0x73, 0x34, 0x77, 0x78, 0x69, 0x69, 0x45, 0x67, 0x4e, 0x4a, 0x2f, 0x50, 0x45, 0x70, +0x75, 0x57, 0x42, 0x4b, 0x77, 0x57, 0x51, 0x55, 0x6c, 0x31, 0x72, 0x31, 0x77, 0x6d, 0x45, 0x47, +0x58, 0x54, 0x59, 0x62, 0x39, 0x39, 0x73, 0x4e, 0x6f, 0x51, 0x37, 0x47, 0x6e, 0x75, 0x4f, 0x67, +0x39, 0x78, 0x57, 0x39, 0x75, 0x6e, 0x45, 0x4a, 0x57, 0x64, 0x62, 0x2f, 0x34, 0x33, 0x4e, 0x46, +0x4a, 0x31, 0x32, 0x6d, 0x54, 0x51, 0x48, 0x5a, 0x47, 0x49, 0x68, 0x47, 0x57, 0x31, 0x43, 0x7a, +0x68, 0x69, 0x44, 0x63, 0x57, 0x34, 0x36, 0x48, 0x78, 0x45, 0x49, 0x51, 0x39, 0x67, 0x59, 0x65, +0x74, 0x73, 0x54, 0x6c, 0x6f, 0x63, 0x41, 0x57, 0x58, 0x58, 0x54, 0x4b, 0x55, 0x6f, 0x70, 0x33, +0x31, 0x35, 0x46, 0x35, 0x32, 0x41, 0x57, 0x5a, 0x54, 0x6f, 0x78, 0x32, 0x2f, 0x33, 0x6e, 0x57, +0x30, 0x33, 0x6a, 0x69, 0x46, 0x6c, 0x54, 0x30, 0x39, 0x6a, 0x72, 0x68, 0x32, 0x76, 0x4e, 0x55, +0x68, 0x63, 0x56, 0x5a, 0x5a, 0x48, 0x64, 0x51, 0x33, 0x46, 0x32, 0x6d, 0x76, 0x7a, 0x41, 0x6f, +0x41, 0x59, 0x47, 0x4c, 0x6a, 0x73, 0x50, 0x69, 0x45, 0x61, 0x52, 0x45, 0x74, 0x6a, 0x4b, 0x33, +0x38, 0x46, 0x51, 0x66, 0x31, 0x50, 0x34, 0x67, 0x56, 0x4c, 0x53, 0x76, 0x51, 0x68, 0x51, 0x63, +0x52, 0x39, 0x6b, 0x4a, 0x38, 0x31, 0x66, 0x2f, 0x50, 0x44, 0x43, 0x6f, 0x63, 0x78, 0x4d, 0x75, +0x62, 0x50, 0x32, 0x4a, 0x42, 0x2f, 0x51, 0x4b, 0x4b, 0x73, 0x34, 0x72, 0x6a, 0x48, 0x74, 0x34, +0x4e, 0x7a, 0x4d, 0x4f, 0x62, 0x72, 0x57, 0x41, 0x33, 0x69, 0x56, 0x6b, 0x69, 0x49, 0x53, 0x53, +0x52, 0x30, 0x63, 0x54, 0x4b, 0x37, 0x2f, 0x75, 0x42, 0x42, 0x57, 0x42, 0x53, 0x56, 0x71, 0x41, +0x34, 0x6c, 0x44, 0x4b, 0x35, 0x2f, 0x55, 0x6f, 0x53, 0x51, 0x76, 0x4c, 0x63, 0x4a, 0x73, 0x48, +0x4f, 0x6d, 0x4f, 0x54, 0x55, 0x67, 0x52, 0x4f, 0x59, 0x30, 0x48, 0x73, 0x43, 0x4a, 0x37, 0x37, +0x33, 0x42, 0x56, 0x4b, 0x33, 0x38, 0x4e, 0x63, 0x4e, 0x64, 0x68, 0x55, 0x4e, 0x74, 0x47, 0x72, +0x41, 0x79, 0x6d, 0x71, 0x39, 0x37, 0x39, 0x61, 0x52, 0x4d, 0x36, 0x37, 0x58, 0x64, 0x72, 0x37, +0x62, 0x30, 0x4d, 0x70, 0x4c, 0x37, 0x77, 0x78, 0x69, 0x76, 0x35, 0x48, 0x5a, 0x52, 0x4f, 0x6a, +0x46, 0x4a, 0x34, 0x75, 0x58, 0x55, 0x56, 0x42, 0x62, 0x78, 0x2b, 0x55, 0x39, 0x31, 0x79, 0x50, +0x38, 0x47, 0x6f, 0x52, 0x53, 0x38, 0x56, 0x79, 0x47, 0x66, 0x7a, 0x78, 0x79, 0x50, 0x4f, 0x4e, +0x47, 0x39, 0x71, 0x5a, 0x2b, 0x53, 0x77, 0x74, 0x4e, 0x4c, 0x56, 0x47, 0x4d, 0x67, 0x5a, 0x4d, +0x6d, 0x37, 0x4a, 0x61, 0x69, 0x41, 0x43, 0x34, 0x36, 0x66, 0x52, 0x52, 0x61, 0x61, 0x35, 0x61, +0x73, 0x62, 0x69, 0x51, 0x37, 0x45, 0x6b, 0x49, 0x71, 0x7a, 0x57, 0x2b, 0x50, 0x48, 0x59, 0x34, +0x55, 0x6c, 0x2f, 0x4b, 0x43, 0x50, 0x44, 0x50, 0x52, 0x2f, 0x6e, 0x62, 0x4a, 0x30, 0x51, 0x4d, +0x6c, 0x54, 0x79, 0x30, 0x56, 0x69, 0x49, 0x6a, 0x67, 0x69, 0x42, 0x6b, 0x43, 0x58, 0x77, 0x70, +0x45, 0x78, 0x47, 0x72, 0x2b, 0x33, 0x77, 0x38, 0x55, 0x33, 0x44, 0x58, 0x58, 0x52, 0x2b, 0x51, +0x6e, 0x32, 0x74, 0x39, 0x34, 0x35, 0x46, 0x6d, 0x45, 0x53, 0x6b, 0x74, 0x35, 0x63, 0x37, 0x57, +0x68, 0x4c, 0x6b, 0x2b, 0x52, 0x68, 0x57, 0x4a, 0x6d, 0x33, 0x6a, 0x6a, 0x47, 0x6a, 0x31, 0x68, +0x50, 0x30, 0x37, 0x64, 0x4e, 0x74, 0x50, 0x6f, 0x47, 0x36, 0x55, 0x75, 0x6b, 0x4e, 0x45, 0x52, +0x46, 0x4e, 0x73, 0x56, 0x35, 0x4c, 0x79, 0x50, 0x6c, 0x65, 0x57, 0x52, 0x70, 0x36, 0x77, 0x50, +0x51, 0x62, 0x76, 0x38, 0x2f, 0x64, 0x74, 0x77, 0x34, 0x4b, 0x2f, 0x7a, 0x70, 0x55, 0x4f, 0x51, +0x4d, 0x59, 0x62, 0x33, 0x55, 0x2f, 0x73, 0x39, 0x46, 0x65, 0x52, 0x47, 0x6b, 0x46, 0x30, 0x47, +0x47, 0x62, 0x4a, 0x31, 0x4a, 0x51, 0x51, 0x69, 0x42, 0x52, 0x75, 0x44, 0x68, 0x45, 0x30, 0x4b, +0x67, 0x38, 0x45, 0x30, 0x49, 0x59, 0x55, 0x4c, 0x75, 0x65, 0x77, 0x6a, 0x68, 0x5a, 0x51, 0x48, +0x35, 0x56, 0x6f, 0x67, 0x64, 0x4b, 0x37, 0x50, 0x53, 0x74, 0x69, 0x4b, 0x77, 0x72, 0x32, 0x4c, +0x30, 0x6a, 0x74, 0x52, 0x77, 0x52, 0x4e, 0x34, 0x45, 0x4f, 0x6e, 0x51, 0x6e, 0x34, 0x37, 0x4c, +0x48, 0x38, 0x46, 0x48, 0x37, 0x48, 0x4d, 0x74, 0x7a, 0x70, 0x30, 0x51, 0x63, 0x58, 0x79, 0x47, +0x78, 0x47, 0x39, 0x56, 0x6b, 0x4b, 0x4c, 0x45, 0x52, 0x6b, 0x72, 0x75, 0x6c, 0x4c, 0x53, 0x5a, +0x71, 0x56, 0x31, 0x75, 0x42, 0x4a, 0x33, 0x78, 0x47, 0x75, 0x58, 0x44, 0x6b, 0x66, 0x35, 0x4b, +0x41, 0x53, 0x50, 0x63, 0x42, 0x31, 0x56, 0x71, 0x69, 0x6a, 0x4c, 0x61, 0x55, 0x36, 0x6b, 0x6f, +0x68, 0x58, 0x48, 0x6e, 0x76, 0x44, 0x63, 0x73, 0x2f, 0x70, 0x33, 0x48, 0x4e, 0x31, 0x33, 0x7a, +0x34, 0x6e, 0x37, 0x63, 0x34, 0x37, 0x76, 0x65, 0x58, 0x4d, 0x58, 0x6a, 0x50, 0x77, 0x2b, 0x32, +0x7a, 0x47, 0x2b, 0x50, 0x43, 0x79, 0x7a, 0x59, 0x45, 0x64, 0x39, 0x74, 0x39, 0x78, 0x33, 0x44, +0x70, 0x46, 0x5a, 0x4b, 0x54, 0x6a, 0x35, 0x33, 0x48, 0x58, 0x51, 0x38, 0x66, 0x7a, 0x61, 0x52, +0x54, 0x5a, 0x6f, 0x4f, 0x52, 0x50, 0x44, 0x5a, 0x74, 0x50, 0x4c, 0x34, 0x76, 0x32, 0x54, 0x35, +0x70, 0x45, 0x6e, 0x6e, 0x45, 0x34, 0x74, 0x45, 0x59, 0x34, 0x39, 0x74, 0x77, 0x64, 0x37, 0x68, +0x50, 0x48, 0x35, 0x62, 0x38, 0x35, 0x7a, 0x38, 0x55, 0x41, 0x30, 0x76, 0x7a, 0x46, 0x51, 0x4f, +0x4f, 0x6b, 0x58, 0x53, 0x2b, 0x49, 0x4b, 0x6d, 0x2b, 0x34, 0x56, 0x36, 0x2b, 0x46, 0x52, 0x48, +0x2b, 0x49, 0x51, 0x51, 0x4e, 0x51, 0x72, 0x71, 0x61, 0x48, 0x4c, 0x37, 0x62, 0x75, 0x74, 0x6a, +0x36, 0x48, 0x45, 0x49, 0x49, 0x61, 0x76, 0x76, 0x57, 0x4d, 0x76, 0x33, 0x39, 0x36, 0x63, 0x43, +0x64, 0x74, 0x4c, 0x52, 0x6c, 0x63, 0x63, 0x76, 0x6a, 0x52, 0x35, 0x4b, 0x66, 0x33, 0x63, 0x36, +0x61, 0x54, 0x65, 0x57, 0x63, 0x65, 0x4f, 0x6f, 0x51, 0x6a, 0x76, 0x70, 0x6c, 0x47, 0x63, 0x55, +0x76, 0x50, 0x49, 0x35, 0x35, 0x59, 0x33, 0x70, 0x43, 0x62, 0x6b, 0x34, 0x35, 0x6a, 0x63, 0x31, +0x6e, 0x48, 0x63, 0x74, 0x54, 0x57, 0x31, 0x35, 0x6e, 0x37, 0x76, 0x79, 0x5a, 0x73, 0x42, 0x45, +0x69, 0x79, 0x43, 0x51, 0x6f, 0x71, 0x30, 0x70, 0x57, 0x41, 0x48, 0x36, 0x71, 0x41, 0x6a, 0x43, +0x5a, 0x6f, 0x5a, 0x77, 0x39, 0x49, 0x67, 0x6d, 0x4d, 0x65, 0x4c, 0x34, 0x6e, 0x61, 0x59, 0x38, +0x74, 0x35, 0x35, 0x65, 0x56, 0x35, 0x33, 0x48, 0x6a, 0x73, 0x49, 0x6e, 0x78, 0x33, 0x35, 0x38, +0x66, 0x64, 0x79, 0x73, 0x66, 0x4e, 0x58, 0x37, 0x47, 0x6a, 0x48, 0x56, 0x2f, 0x70, 0x32, 0x65, +0x32, 0x70, 0x43, 0x69, 0x53, 0x52, 0x4d, 0x67, 0x4a, 0x38, 0x42, 0x75, 0x46, 0x2b, 0x56, 0x70, +0x67, 0x54, 0x70, 0x4b, 0x77, 0x53, 0x53, 0x4a, 0x57, 0x4a, 0x67, 0x51, 0x2f, 0x55, 0x41, 0x49, +0x49, 0x6b, 0x78, 0x6c, 0x4b, 0x6d, 0x74, 0x78, 0x2b, 0x4c, 0x54, 0x6d, 0x33, 0x32, 0x6d, 0x4f, +0x78, 0x4f, 0x4a, 0x42, 0x66, 0x39, 0x78, 0x76, 0x49, 0x38, 0x4e, 0x4a, 0x68, 0x59, 0x41, 0x78, +0x58, 0x37, 0x48, 0x45, 0x70, 0x54, 0x62, 0x46, 0x57, 0x62, 0x76, 0x72, 0x69, 0x5a, 0x71, 0x37, +0x75, 0x46, 0x2b, 0x4b, 0x47, 0x6c, 0x52, 0x61, 0x78, 0x5a, 0x2f, 0x30, 0x6a, 0x45, 0x75, 0x31, +0x77, 0x35, 0x46, 0x49, 0x70, 0x56, 0x4a, 0x37, 0x43, 0x64, 0x4f, 0x37, 0x47, 0x6d, 0x4e, 0x30, +0x4c, 0x4b, 0x53, 0x2f, 0x78, 0x4f, 0x47, 0x6a, 0x76, 0x4b, 0x6f, 0x34, 0x37, 0x70, 0x43, 0x39, +0x7a, 0x46, 0x7a, 0x53, 0x54, 0x64, 0x65, 0x67, 0x47, 0x66, 0x42, 0x56, 0x55, 0x68, 0x37, 0x55, +0x2b, 0x6b, 0x6e, 0x4e, 0x4f, 0x33, 0x41, 0x50, 0x50, 0x38, 0x78, 0x69, 0x78, 0x57, 0x77, 0x55, +0x78, 0x58, 0x2b, 0x45, 0x42, 0x6b, 0x55, 0x67, 0x43, 0x6d, 0x6d, 0x75, 0x4d, 0x34, 0x5a, 0x64, +0x6a, 0x2b, 0x38, 0x51, 0x31, 0x64, 0x7a, 0x53, 0x6d, 0x43, 0x49, 0x63, 0x68, 0x4b, 0x79, 0x76, +0x43, 0x73, 0x50, 0x34, 0x48, 0x38, 0x63, 0x49, 0x30, 0x31, 0x33, 0x34, 0x74, 0x6b, 0x45, 0x61, +0x79, 0x63, 0x4a, 0x76, 0x6b, 0x2b, 0x55, 0x4d, 0x45, 0x4a, 0x7a, 0x79, 0x58, 0x56, 0x42, 0x34, +0x39, 0x35, 0x76, 0x50, 0x61, 0x4a, 0x4d, 0x48, 0x39, 0x33, 0x79, 0x55, 0x4b, 0x57, 0x77, 0x54, +0x74, 0x31, 0x77, 0x76, 0x6d, 0x38, 0x65, 0x61, 0x41, 0x59, 0x6a, 0x35, 0x62, 0x72, 0x78, 0x6b, +0x56, 0x79, 0x51, 0x55, 0x70, 0x6d, 0x62, 0x74, 0x30, 0x47, 0x64, 0x2f, 0x33, 0x4c, 0x57, 0x42, +0x59, 0x6c, 0x73, 0x48, 0x7a, 0x6f, 0x33, 0x59, 0x31, 0x56, 0x70, 0x71, 0x59, 0x62, 0x45, 0x4a, +0x70, 0x61, 0x59, 0x75, 0x64, 0x4f, 0x41, 0x73, 0x6d, 0x49, 0x36, 0x39, 0x6a, 0x73, 0x75, 0x6d, +0x62, 0x4c, 0x76, 0x7a, 0x70, 0x2f, 0x56, 0x38, 0x39, 0x68, 0x35, 0x72, 0x79, 0x33, 0x51, 0x6a, +0x4c, 0x6e, 0x58, 0x47, 0x59, 0x64, 0x79, 0x42, 0x49, 0x67, 0x51, 0x55, 0x67, 0x5a, 0x41, 0x49, +0x43, 0x4c, 0x71, 0x56, 0x45, 0x53, 0x45, 0x56, 0x4e, 0x56, 0x54, 0x6b, 0x66, 0x4d, 0x63, 0x50, +0x65, 0x7a, 0x34, 0x55, 0x4f, 0x67, 0x37, 0x31, 0x76, 0x54, 0x48, 0x57, 0x79, 0x57, 0x38, 0x35, +0x41, 0x70, 0x46, 0x48, 0x38, 0x5a, 0x64, 0x74, 0x39, 0x5a, 0x4a, 0x48, 0x6c, 0x2f, 0x6b, 0x2b, +0x43, 0x43, 0x76, 0x41, 0x45, 0x43, 0x56, 0x72, 0x31, 0x64, 0x43, 0x69, 0x79, 0x4a, 0x77, 0x58, +0x5a, 0x6d, 0x56, 0x69, 0x70, 0x4d, 0x37, 0x58, 0x66, 0x39, 0x2b, 0x33, 0x71, 0x72, 0x36, 0x52, +0x74, 0x73, 0x31, 0x49, 0x59, 0x59, 0x38, 0x67, 0x75, 0x72, 0x61, 0x49, 0x74, 0x56, 0x45, 0x78, +0x2b, 0x33, 0x39, 0x30, 0x70, 0x37, 0x54, 0x33, 0x45, 0x57, 0x6b, 0x50, 0x53, 0x4d, 0x6c, 0x45, +0x46, 0x66, 0x67, 0x30, 0x4a, 0x74, 0x4b, 0x73, 0x39, 0x65, 0x50, 0x72, 0x46, 0x41, 0x6f, 0x34, +0x36, 0x61, 0x41, 0x61, 0x54, 0x54, 0x70, 0x6e, 0x46, 0x5a, 0x64, 0x65, 0x64, 0x6a, 0x70, 0x41, +0x47, 0x33, 0x39, 0x63, 0x49, 0x59, 0x53, 0x68, 0x39, 0x66, 0x68, 0x70, 0x35, 0x59, 0x54, 0x39, +0x68, 0x55, 0x52, 0x6e, 0x6a, 0x4b, 0x4d, 0x2f, 0x43, 0x44, 0x4c, 0x2f, 0x71, 0x4b, 0x76, 0x7a, +0x78, 0x34, 0x36, 0x6b, 0x2b, 0x33, 0x4f, 0x4f, 0x47, 0x6c, 0x36, 0x75, 0x34, 0x59, 0x32, 0x49, +0x54, 0x35, 0x76, 0x37, 0x74, 0x6a, 0x47, 0x67, 0x58, 0x6e, 0x4f, 0x6a, 0x37, 0x33, 0x43, 0x69, +0x53, 0x71, 0x69, 0x55, 0x48, 0x69, 0x73, 0x42, 0x5a, 0x4d, 0x50, 0x6e, 0x74, 0x2b, 0x63, 0x48, +0x44, 0x49, 0x36, 0x52, 0x6d, 0x34, 0x35, 0x59, 0x69, 0x4b, 0x69, 0x74, 0x37, 0x63, 0x66, 0x65, +0x39, 0x49, 0x79, 0x67, 0x54, 0x4f, 0x38, 0x6e, 0x39, 0x30, 0x77, 0x57, 0x59, 0x31, 0x66, 0x58, +0x32, 0x75, 0x51, 0x76, 0x4b, 0x61, 0x62, 0x2f, 0x6e, 0x43, 0x6c, 0x59, 0x4d, 0x4c, 0x4f, 0x53, +0x61, 0x52, 0x5a, 0x65, 0x77, 0x59, 0x73, 0x74, 0x53, 0x42, 0x70, 0x51, 0x4f, 0x41, 0x4f, 0x6b, +0x55, 0x67, 0x48, 0x49, 0x72, 0x66, 0x77, 0x42, 0x6c, 0x54, 0x56, 0x55, 0x41, 0x37, 0x6a, 0x33, +0x4e, 0x41, 0x67, 0x69, 0x67, 0x6e, 0x49, 0x33, 0x6c, 0x43, 0x66, 0x39, 0x74, 0x4a, 0x46, 0x54, +0x43, 0x44, 0x2f, 0x35, 0x57, 0x44, 0x70, 0x35, 0x37, 0x41, 0x43, 0x2b, 0x4d, 0x65, 0x6f, 0x45, +0x7a, 0x36, 0x73, 0x34, 0x41, 0x34, 0x4b, 0x58, 0x56, 0x4c, 0x33, 0x48, 0x36, 0x4e, 0x36, 0x64, +0x54, 0x55, 0x44, 0x47, 0x49, 0x79, 0x72, 0x4a, 0x79, 0x47, 0x6e, 0x57, 0x71, 0x33, 0x39, 0x68, +0x34, 0x45, 0x6a, 0x4e, 0x49, 0x59, 0x69, 0x49, 0x57, 0x53, 0x6d, 0x72, 0x35, 0x2b, 0x4b, 0x7a, +0x67, 0x42, 0x34, 0x71, 0x41, 0x4e, 0x41, 0x73, 0x67, 0x7a, 0x6d, 0x71, 0x62, 0x31, 0x76, 0x35, +0x48, 0x31, 0x69, 0x6e, 0x75, 0x33, 0x65, 0x38, 0x6f, 0x68, 0x70, 0x59, 0x4d, 0x70, 0x56, 0x32, +0x30, 0x73, 0x36, 0x46, 0x74, 0x41, 0x37, 0x2f, 0x6f, 0x39, 0x55, 0x73, 0x61, 0x4f, 0x68, 0x72, +0x34, 0x34, 0x2b, 0x34, 0x58, 0x63, 0x76, 0x32, 0x69, 0x4f, 0x36, 0x77, 0x4a, 0x6e, 0x57, 0x77, +0x42, 0x75, 0x4c, 0x69, 0x38, 0x6c, 0x4a, 0x72, 0x57, 0x6c, 0x6e, 0x4a, 0x32, 0x48, 0x39, 0x44, +0x49, 0x44, 0x52, 0x74, 0x61, 0x69, 0x49, 0x53, 0x4b, 0x57, 0x62, 0x78, 0x71, 0x4c, 0x51, 0x76, +0x58, 0x68, 0x54, 0x6c, 0x6b, 0x76, 0x78, 0x38, 0x51, 0x7a, 0x54, 0x6b, 0x49, 0x6f, 0x65, 0x49, +0x35, 0x32, 0x75, 0x44, 0x7a, 0x31, 0x4c, 0x2b, 0x2f, 0x5a, 0x65, 0x79, 0x65, 0x4e, 0x5a, 0x51, +0x57, 0x35, 0x5a, 0x43, 0x64, 0x35, 0x62, 0x46, 0x78, 0x63, 0x78, 0x76, 0x74, 0x48, 0x56, 0x61, +0x77, 0x78, 0x6f, 0x2f, 0x75, 0x6a, 0x54, 0x47, 0x47, 0x32, 0x66, 0x50, 0x58, 0x6f, 0x37, 0x53, +0x6d, 0x72, 0x6e, 0x63, 0x4a, 0x6b, 0x53, 0x79, 0x50, 0x35, 0x57, 0x74, 0x32, 0x6b, 0x70, 0x30, +0x56, 0x34, 0x74, 0x6b, 0x33, 0x46, 0x6b, 0x4b, 0x70, 0x61, 0x37, 0x2b, 0x53, 0x2b, 0x44, 0x6b, +0x2b, 0x58, 0x79, 0x79, 0x54, 0x62, 0x42, 0x67, 0x6f, 0x65, 0x47, 0x2b, 0x69, 0x7a, 0x32, 0x4d, +0x2f, 0x43, 0x4b, 0x54, 0x32, 0x75, 0x57, 0x69, 0x59, 0x59, 0x45, 0x4f, 0x48, 0x7a, 0x39, 0x74, +0x66, 0x43, 0x50, 0x7a, 0x53, 0x52, 0x49, 0x34, 0x42, 0x50, 0x76, 0x78, 0x74, 0x6f, 0x65, 0x53, +0x71, 0x34, 0x33, 0x4b, 0x51, 0x73, 0x52, 0x59, 0x2b, 0x61, 0x79, 0x2b, 0x78, 0x75, 0x52, 0x64, +0x53, 0x38, 0x74, 0x32, 0x79, 0x48, 0x53, 0x77, 0x55, 0x42, 0x69, 0x45, 0x6a, 0x68, 0x49, 0x52, +0x69, 0x33, 0x2f, 0x78, 0x62, 0x47, 0x52, 0x44, 0x5a, 0x79, 0x4c, 0x4c, 0x4e, 0x6c, 0x52, 0x78, +0x59, 0x63, 0x41, 0x4f, 0x76, 0x2b, 0x73, 0x66, 0x46, 0x46, 0x63, 0x41, 0x75, 0x6f, 0x63, 0x69, +0x42, 0x30, 0x4b, 0x52, 0x5a, 0x41, 0x45, 0x48, 0x2f, 0x71, 0x34, 0x33, 0x76, 0x41, 0x49, 0x4d, +0x77, 0x5a, 0x69, 0x30, 0x47, 0x33, 0x36, 0x56, 0x44, 0x5a, 0x35, 0x67, 0x2f, 0x61, 0x65, 0x2b, +0x68, 0x55, 0x42, 0x30, 0x33, 0x54, 0x51, 0x5a, 0x64, 0x36, 0x36, 0x44, 0x45, 0x51, 0x69, 0x43, +0x4d, 0x52, 0x4b, 0x44, 0x52, 0x48, 0x76, 0x77, 0x67, 0x6c, 0x6a, 0x49, 0x6f, 0x65, 0x7a, 0x63, +0x75, 0x4c, 0x5a, 0x2f, 0x4d, 0x31, 0x39, 0x47, 0x76, 0x2b, 0x4c, 0x42, 0x74, 0x4e, 0x72, 0x47, +0x51, 0x78, 0x43, 0x4e, 0x67, 0x68, 0x30, 0x36, 0x59, 0x34, 0x4a, 0x6d, 0x67, 0x79, 0x46, 0x31, +0x59, 0x71, 0x62, 0x74, 0x70, 0x50, 0x39, 0x4b, 0x34, 0x42, 0x63, 0x51, 0x71, 0x41, 0x46, 0x39, +0x62, 0x79, 0x32, 0x33, 0x57, 0x77, 0x6b, 0x2b, 0x52, 0x75, 0x65, 0x57, 0x55, 0x6a, 0x64, 0x71, +0x54, 0x39, 0x78, 0x64, 0x38, 0x78, 0x4f, 0x6c, 0x48, 0x6e, 0x47, 0x6e, 0x42, 0x56, 0x64, 0x72, +0x45, 0x55, 0x38, 0x73, 0x42, 0x35, 0x6a, 0x4f, 0x65, 0x76, 0x71, 0x75, 0x76, 0x4a, 0x6a, 0x5a, +0x72, 0x50, 0x51, 0x6a, 0x42, 0x77, 0x2f, 0x4b, 0x4c, 0x65, 0x4e, 0x71, 0x32, 0x46, 0x6f, 0x4b, +0x32, 0x59, 0x31, 0x70, 0x6f, 0x7a, 0x38, 0x31, 0x4a, 0x41, 0x63, 0x70, 0x70, 0x49, 0x63, 0x6a, +0x71, 0x31, 0x34, 0x2f, 0x76, 0x5a, 0x38, 0x35, 0x6b, 0x46, 0x50, 0x44, 0x71, 0x4f, 0x34, 0x71, +0x37, 0x66, 0x74, 0x76, 0x42, 0x6a, 0x6e, 0x64, 0x7a, 0x79, 0x64, 0x32, 0x68, 0x2b, 0x46, 0x78, +0x6c, 0x38, 0x59, 0x53, 0x30, 0x75, 0x66, 0x2b, 0x2b, 0x43, 0x2b, 0x48, 0x37, 0x77, 0x72, 0x50, +0x76, 0x30, 0x6b, 0x50, 0x49, 0x4d, 0x45, 0x49, 0x47, 0x4e, 0x52, 0x6c, 0x39, 0x6c, 0x46, 0x49, +0x63, 0x63, 0x45, 0x68, 0x76, 0x66, 0x6e, 0x64, 0x79, 0x62, 0x77, 0x72, 0x2f, 0x2b, 0x78, 0x72, +0x65, 0x63, 0x38, 0x39, 0x59, 0x36, 0x4c, 0x55, 0x76, 0x4d, 0x49, 0x64, 0x4d, 0x59, 0x4e, 0x75, +0x46, 0x70, 0x2f, 0x4e, 0x32, 0x78, 0x33, 0x77, 0x65, 0x6d, 0x48, 0x55, 0x33, 0x62, 0x58, 0x34, +0x62, 0x67, 0x73, 0x54, 0x38, 0x69, 0x53, 0x43, 0x78, 0x44, 0x69, 0x62, 0x6c, 0x63, 0x4f, 0x7a, +0x4b, 0x52, 0x32, 0x65, 0x79, 0x41, 0x48, 0x52, 0x6d, 0x4b, 0x4f, 0x63, 0x44, 0x44, 0x36, 0x64, +0x36, 0x39, 0x7a, 0x79, 0x2f, 0x6d, 0x42, 0x32, 0x78, 0x66, 0x75, 0x7a, 0x33, 0x39, 0x6d, 0x48, +0x49, 0x37, 0x35, 0x5a, 0x67, 0x6a, 0x47, 0x62, 0x66, 0x50, 0x51, 0x37, 0x6c, 0x69, 0x63, 0x73, +0x47, 0x55, 0x4a, 0x35, 0x64, 0x6a, 0x4d, 0x6e, 0x32, 0x53, 0x50, 0x59, 0x49, 0x61, 0x73, 0x44, +0x54, 0x46, 0x69, 0x59, 0x4d, 0x46, 0x6b, 0x72, 0x71, 0x2b, 0x34, 0x5a, 0x59, 0x72, 0x42, 0x73, +0x4c, 0x49, 0x4f, 0x33, 0x2b, 0x4b, 0x65, 0x33, 0x58, 0x74, 0x76, 0x31, 0x58, 0x7a, 0x72, 0x75, +0x53, 0x76, 0x45, 0x67, 0x65, 0x4d, 0x52, 0x6d, 0x6a, 0x55, 0x33, 0x59, 0x53, 0x38, 0x53, 0x4c, +0x73, 0x69, 0x4f, 0x35, 0x67, 0x57, 0x2b, 0x65, 0x32, 0x4f, 0x4d, 0x2b, 0x68, 0x30, 0x73, 0x34, +0x43, 0x69, 0x50, 0x70, 0x6f, 0x5a, 0x56, 0x79, 0x4b, 0x73, 0x75, 0x4b, 0x74, 0x68, 0x62, 0x6e, +0x30, 0x44, 0x71, 0x33, 0x68, 0x79, 0x56, 0x4e, 0x67, 0x37, 0x73, 0x36, 0x39, 0x57, 0x4e, 0x57, +0x77, 0x69, 0x63, 0x73, 0x50, 0x33, 0x38, 0x52, 0x65, 0x4e, 0x5a, 0x33, 0x63, 0x2f, 0x78, 0x37, +0x4f, 0x6b, 0x61, 0x61, 0x51, 0x79, 0x69, 0x71, 0x41, 0x38, 0x38, 0x2f, 0x36, 0x46, 0x39, 0x66, +0x64, 0x63, 0x77, 0x77, 0x37, 0x57, 0x36, 0x4a, 0x63, 0x63, 0x4d, 0x6f, 0x65, 0x52, 0x4b, 0x4f, +0x43, 0x65, 0x35, 0x36, 0x61, 0x6a, 0x39, 0x47, 0x47, 0x2f, 0x66, 0x63, 0x36, 0x48, 0x6d, 0x4d, +0x4d, 0x74, 0x7a, 0x77, 0x2b, 0x44, 0x2b, 0x45, 0x72, 0x2b, 0x76, 0x51, 0x71, 0x35, 0x4d, 0x71, +0x7a, 0x78, 0x2f, 0x44, 0x57, 0x37, 0x42, 0x57, 0x73, 0x58, 0x4e, 0x2f, 0x4d, 0x72, 0x47, 0x65, +0x6e, 0x77, 0x76, 0x56, 0x70, 0x37, 0x53, 0x2f, 0x79, 0x75, 0x66, 0x41, 0x4e, 0x77, 0x5a, 0x46, +0x37, 0x2b, 0x6c, 0x77, 0x79, 0x30, 0x76, 0x49, 0x49, 0x33, 0x50, 0x4f, 0x74, 0x7a, 0x39, 0x4d, +0x66, 0x4f, 0x65, 0x46, 0x33, 0x70, 0x64, 0x4b, 0x56, 0x6c, 0x73, 0x36, 0x48, 0x49, 0x5a, 0x4e, +0x34, 0x44, 0x4e, 0x32, 0x4b, 0x36, 0x39, 0x4b, 0x75, 0x2f, 0x65, 0x43, 0x7a, 0x6b, 0x50, 0x7a, +0x6c, 0x35, 0x66, 0x32, 0x34, 0x35, 0x50, 0x68, 0x5a, 0x6d, 0x50, 0x77, 0x57, 0x37, 0x6e, 0x72, +0x38, 0x43, 0x47, 0x70, 0x72, 0x45, 0x38, 0x47, 0x30, 0x62, 0x6c, 0x64, 0x2f, 0x62, 0x54, 0x49, +0x4b, 0x54, 0x79, 0x71, 0x55, 0x46, 0x7a, 0x7a, 0x50, 0x7a, 0x68, 0x47, 0x51, 0x47, 0x51, 0x53, +0x2b, 0x71, 0x2f, 0x44, 0x62, 0x38, 0x79, 0x52, 0x53, 0x75, 0x67, 0x43, 0x52, 0x45, 0x77, 0x71, +0x70, 0x42, 0x41, 0x70, 0x46, 0x53, 0x47, 0x70, 0x57, 0x78, 0x4a, 0x62, 0x79, 0x6c, 0x71, 0x38, +0x59, 0x6b, 0x62, 0x63, 0x48, 0x2f, 0x34, 0x2b, 0x30, 0x38, 0x77, 0x36, 0x7a, 0x6f, 0x72, 0x72, +0x37, 0x2b, 0x47, 0x64, 0x75, 0x32, 0x64, 0x37, 0x59, 0x70, 0x65, 0x33, 0x53, 0x71, 0x34, 0x4b, +0x6f, 0x69, 0x4c, 0x32, 0x67, 0x52, 0x74, 0x46, 0x67, 0x69, 0x64, 0x47, 0x6f, 0x69, 0x53, 0x5a, +0x71, 0x4c, 0x4c, 0x46, 0x72, 0x31, 0x47, 0x43, 0x4a, 0x59, 0x75, 0x39, 0x52, 0x59, 0x30, 0x2b, +0x69, 0x59, 0x75, 0x78, 0x52, 0x54, 0x4b, 0x7a, 0x59, 0x45, 0x79, 0x56, 0x59, 0x73, 0x4b, 0x41, +0x43, 0x30, 0x6b, 0x48, 0x71, 0x73, 0x69, 0x79, 0x77, 0x43, 0x32, 0x7a, 0x66, 0x65, 0x2b, 0x2b, +0x63, 0x39, 0x76, 0x35, 0x78, 0x7a, 0x73, 0x77, 0x74, 0x75, 0x34, 0x76, 0x34, 0x5a, 0x70, 0x35, +0x6e, 0x6d, 0x4e, 0x6e, 0x4c, 0x6e, 0x58, 0x76, 0x4f, 0x6e, 0x48, 0x35, 0x2b, 0x35, 0x2f, 0x50, +0x37, 0x6e, 0x6c, 0x6b, 0x74, 0x4d, 0x39, 0x48, 0x61, 0x64, 0x77, 0x43, 0x50, 0x79, 0x47, 0x4c, +0x35, 0x6f, 0x37, 0x2b, 0x42, 0x6d, 0x79, 0x59, 0x4c, 0x61, 0x70, 0x76, 0x54, 0x35, 0x56, 0x64, +0x4a, 0x53, 0x39, 0x30, 0x4a, 0x36, 0x55, 0x52, 0x73, 0x56, 0x54, 0x43, 0x61, 0x38, 0x6b, 0x4e, +0x72, 0x2b, 0x75, 0x42, 0x65, 0x6b, 0x72, 0x65, 0x2b, 0x43, 0x30, 0x61, 0x51, 0x4d, 0x68, 0x77, +0x42, 0x2b, 0x4d, 0x4c, 0x48, 0x59, 0x44, 0x68, 0x73, 0x37, 0x38, 0x4e, 0x35, 0x2f, 0x2f, 0x50, +0x33, 0x55, 0x45, 0x6f, 0x78, 0x36, 0x59, 0x44, 0x4a, 0x47, 0x47, 0x4e, 0x51, 0x76, 0x67, 0x42, +0x6a, 0x51, 0x70, 0x70, 0x55, 0x41, 0x68, 0x4d, 0x32, 0x62, 0x73, 0x41, 0x72, 0x4c, 0x62, 0x4e, +0x6b, 0x70, 0x53, 0x45, 0x39, 0x31, 0x77, 0x2f, 0x53, 0x4c, 0x38, 0x4d, 0x6e, 0x49, 0x31, 0x50, +0x63, 0x31, 0x59, 0x76, 0x46, 0x32, 0x48, 0x6e, 0x56, 0x4b, 0x69, 0x6f, 0x6e, 0x54, 0x75, 0x52, +0x69, 0x32, 0x59, 0x6d, 0x5a, 0x75, 0x6f, 0x48, 0x71, 0x59, 0x6f, 0x6c, 0x2b, 0x38, 0x41, 0x5a, +0x32, 0x72, 0x69, 0x6a, 0x6c, 0x49, 0x61, 0x31, 0x44, 0x33, 0x77, 0x37, 0x6a, 0x56, 0x75, 0x66, +0x51, 0x32, 0x74, 0x72, 0x6e, 0x74, 0x43, 0x59, 0x61, 0x4c, 0x32, 0x54, 0x35, 0x67, 0x76, 0x63, +0x34, 0x34, 0x6f, 0x51, 0x43, 0x72, 0x76, 0x6a, 0x44, 0x37, 0x6c, 0x52, 0x47, 0x45, 0x78, 0x54, +0x65, 0x64, 0x52, 0x31, 0x6d, 0x33, 0x69, 0x4b, 0x62, 0x56, 0x39, 0x46, 0x43, 0x4f, 0x6d, 0x36, +0x59, 0x51, 0x74, 0x32, 0x65, 0x49, 0x37, 0x68, 0x39, 0x36, 0x5a, 0x2b, 0x59, 0x73, 0x2f, 0x5a, +0x54, 0x66, 0x50, 0x77, 0x75, 0x35, 0x64, 0x39, 0x4f, 0x41, 0x5a, 0x51, 0x4d, 0x68, 0x35, 0x74, +0x43, 0x42, 0x52, 0x6d, 0x56, 0x4f, 0x77, 0x4c, 0x6f, 0x48, 0x75, 0x55, 0x38, 0x2b, 0x59, 0x4f, +0x30, 0x6c, 0x42, 0x49, 0x41, 0x54, 0x63, 0x31, 0x77, 0x79, 0x46, 0x48, 0x77, 0x79, 0x6e, 0x64, +0x73, 0x50, 0x76, 0x39, 0x69, 0x4d, 0x49, 0x61, 0x68, 0x6a, 0x2f, 0x2b, 0x56, 0x38, 0x7a, 0x6f, +0x6d, 0x77, 0x39, 0x73, 0x7a, 0x6f, 0x56, 0x64, 0x56, 0x31, 0x74, 0x64, 0x39, 0x49, 0x4b, 0x6f, +0x6b, 0x70, 0x6c, 0x35, 0x41, 0x76, 0x6d, 0x30, 0x35, 0x4d, 0x33, 0x76, 0x2b, 0x63, 0x41, 0x51, +0x51, 0x4e, 0x41, 0x41, 0x35, 0x34, 0x57, 0x66, 0x46, 0x33, 0x31, 0x6c, 0x4c, 0x45, 0x79, 0x4c, +0x4a, 0x79, 0x63, 0x4e, 0x4f, 0x70, 0x71, 0x61, 0x34, 0x68, 0x6c, 0x31, 0x37, 0x37, 0x63, 0x71, +0x37, 0x74, 0x65, 0x38, 0x79, 0x72, 0x33, 0x45, 0x2b, 0x72, 0x36, 0x35, 0x2b, 0x42, 0x57, 0x6c, +0x79, 0x55, 0x45, 0x78, 0x66, 0x32, 0x72, 0x2b, 0x64, 0x4d, 0x75, 0x79, 0x43, 0x56, 0x61, 0x33, +0x63, 0x45, 0x43, 0x33, 0x6c, 0x76, 0x69, 0x4d, 0x31, 0x61, 0x71, 0x74, 0x64, 0x53, 0x74, 0x6d, +0x6a, 0x7a, 0x30, 0x61, 0x2b, 0x57, 0x64, 0x57, 0x66, 0x64, 0x2b, 0x5a, 0x34, 0x62, 0x68, 0x63, +0x61, 0x2b, 0x37, 0x6b, 0x72, 0x50, 0x51, 0x43, 0x30, 0x64, 0x61, 0x54, 0x34, 0x66, 0x4e, 0x34, +0x47, 0x39, 0x74, 0x32, 0x74, 0x6d, 0x74, 0x34, 0x56, 0x68, 0x54, 0x51, 0x32, 0x64, 0x59, 0x51, +0x46, 0x51, 0x53, 0x6d, 0x72, 0x69, 0x37, 0x65, 0x70, 0x73, 0x59, 0x4f, 0x76, 0x76, 0x71, 0x76, +0x6e, 0x32, 0x45, 0x4e, 0x48, 0x38, 0x4d, 0x42, 0x7a, 0x63, 0x39, 0x33, 0x7a, 0x4f, 0x66, 0x45, +0x33, 0x41, 0x72, 0x2f, 0x63, 0x35, 0x35, 0x58, 0x35, 0x50, 0x69, 0x2f, 0x4e, 0x79, 0x55, 0x42, +0x4a, 0x71, 0x36, 0x79, 0x44, 0x55, 0x61, 0x43, 0x4b, 0x4c, 0x4c, 0x56, 0x7a, 0x59, 0x38, 0x4e, +0x48, 0x53, 0x5a, 0x4e, 0x56, 0x2b, 0x63, 0x4f, 0x4b, 0x4c, 0x39, 0x50, 0x33, 0x4d, 0x61, 0x58, +0x35, 0x30, 0x34, 0x73, 0x48, 0x68, 0x62, 0x37, 0x6d, 0x53, 0x54, 0x65, 0x46, 0x32, 0x54, 0x36, +0x4b, 0x71, 0x37, 0x76, 0x32, 0x2f, 0x6a, 0x6e, 0x70, 0x66, 0x39, 0x35, 0x4d, 0x4f, 0x47, 0x55, +0x6e, 0x53, 0x56, 0x50, 0x4b, 0x69, 0x6c, 0x68, 0x4b, 0x4c, 0x56, 0x44, 0x61, 0x74, 0x36, 0x65, +0x78, 0x39, 0x31, 0x6f, 0x4c, 0x56, 0x50, 0x43, 0x35, 0x73, 0x52, 0x62, 0x75, 0x79, 0x67, 0x4c, +0x46, 0x56, 0x54, 0x4e, 0x68, 0x45, 0x5a, 0x59, 0x6b, 0x6a, 0x53, 0x5a, 0x38, 0x70, 0x70, 0x77, +0x37, 0x7a, 0x31, 0x72, 0x2b, 0x66, 0x65, 0x63, 0x33, 0x34, 0x58, 0x2b, 0x4a, 0x45, 0x5a, 0x4c, +0x62, 0x68, 0x4d, 0x53, 0x49, 0x6c, 0x46, 0x74, 0x43, 0x46, 0x4d, 0x51, 0x36, 0x2f, 0x62, 0x53, +0x6f, 0x61, 0x77, 0x31, 0x73, 0x4c, 0x4a, 0x61, 0x73, 0x7a, 0x79, 0x69, 0x2f, 0x6d, 0x64, 0x62, +0x79, 0x4d, 0x50, 0x31, 0x30, 0x42, 0x6f, 0x71, 0x72, 0x46, 0x4a, 0x51, 0x72, 0x47, 0x47, 0x6b, +0x4c, 0x6f, 0x4a, 0x4c, 0x42, 0x43, 0x45, 0x44, 0x67, 0x4b, 0x34, 0x6e, 0x52, 0x68, 0x73, 0x71, +0x4b, 0x50, 0x70, 0x78, 0x36, 0x56, 0x48, 0x70, 0x37, 0x50, 0x42, 0x30, 0x59, 0x51, 0x67, 0x31, +0x4f, 0x61, 0x6c, 0x77, 0x6a, 0x67, 0x64, 0x58, 0x56, 0x41, 0x2b, 0x68, 0x7a, 0x32, 0x57, 0x58, +0x49, 0x74, 0x57, 0x75, 0x7a, 0x31, 0x5a, 0x4e, 0x7a, 0x31, 0x49, 0x69, 0x44, 0x52, 0x73, 0x73, +0x49, 0x69, 0x38, 0x4c, 0x6e, 0x44, 0x52, 0x73, 0x69, 0x69, 0x4e, 0x6e, 0x37, 0x41, 0x41, 0x41, +0x67, 0x41, 0x45, 0x6c, 0x45, 0x51, 0x56, 0x54, 0x47, 0x67, 0x74, 0x6d, 0x7a, 0x37, 0x52, 0x72, +0x36, 0x46, 0x6f, 0x6d, 0x4a, 0x43, 0x6a, 0x68, 0x4b, 0x51, 0x4e, 0x34, 0x66, 0x4b, 0x57, 0x74, +0x7a, 0x4e, 0x6a, 0x63, 0x74, 0x4d, 0x71, 0x37, 0x75, 0x33, 0x67, 0x67, 0x77, 0x43, 0x69, 0x39, +0x2f, 0x4a, 0x43, 0x50, 0x72, 0x76, 0x32, 0x50, 0x56, 0x30, 0x6f, 0x31, 0x55, 0x72, 0x35, 0x32, +0x50, 0x64, 0x38, 0x39, 0x74, 0x6d, 0x48, 0x61, 0x58, 0x54, 0x2b, 0x50, 0x32, 0x70, 0x4f, 0x45, +0x50, 0x76, 0x2b, 0x57, 0x72, 0x2b, 0x48, 0x72, 0x75, 0x2b, 0x76, 0x68, 0x73, 0x74, 0x69, 0x53, +0x33, 0x34, 0x4e, 0x4d, 0x39, 0x69, 0x68, 0x77, 0x6a, 0x61, 0x5a, 0x56, 0x32, 0x71, 0x34, 0x75, +0x72, 0x62, 0x57, 0x73, 0x70, 0x46, 0x52, 0x46, 0x50, 0x41, 0x41, 0x4c, 0x50, 0x63, 0x79, 0x67, +0x77, 0x41, 0x75, 0x49, 0x53, 0x68, 0x6e, 0x64, 0x46, 0x4f, 0x52, 0x76, 0x37, 0x6d, 0x65, 0x77, +0x6c, 0x77, 0x4e, 0x37, 0x6c, 0x65, 0x4a, 0x32, 0x72, 0x55, 0x42, 0x64, 0x65, 0x41, 0x76, 0x6c, +0x35, 0x65, 0x4a, 0x37, 0x48, 0x35, 0x6f, 0x73, 0x75, 0x4a, 0x54, 0x70, 0x73, 0x4d, 0x47, 0x5a, +0x55, 0x4f, 0x55, 0x53, 0x7a, 0x67, 0x49, 0x43, 0x53, 0x30, 0x69, 0x61, 0x49, 0x50, 0x43, 0x36, +0x68, 0x76, 0x52, 0x6f, 0x54, 0x45, 0x34, 0x43, 0x69, 0x5a, 0x6b, 0x43, 0x45, 0x49, 0x67, 0x46, +0x43, 0x65, 0x43, 0x46, 0x4a, 0x36, 0x73, 0x6b, 0x49, 0x6e, 0x68, 0x7a, 0x65, 0x4a, 0x66, 0x77, +0x75, 0x38, 0x58, 0x66, 0x65, 0x68, 0x57, 0x2b, 0x75, 0x65, 0x7a, 0x4d, 0x55, 0x4b, 0x55, 0x32, +0x71, 0x4a, 0x46, 0x4a, 0x4c, 0x68, 0x6c, 0x63, 0x4d, 0x37, 0x34, 0x70, 0x69, 0x4f, 0x67, 0x74, +0x35, 0x37, 0x31, 0x35, 0x46, 0x34, 0x62, 0x71, 0x70, 0x32, 0x46, 0x7a, 0x41, 0x5a, 0x55, 0x38, +0x62, 0x6a, 0x6a, 0x75, 0x6b, 0x45, 0x47, 0x30, 0x55, 0x6c, 0x37, 0x77, 0x39, 0x6d, 0x73, 0x54, +0x57, 0x54, 0x67, 0x62, 0x31, 0x73, 0x31, 0x5a, 0x75, 0x72, 0x64, 0x4b, 0x36, 0x37, 0x4a, 0x67, +0x6b, 0x55, 0x69, 0x6b, 0x75, 0x2b, 0x63, 0x30, 0x45, 0x68, 0x76, 0x51, 0x76, 0x77, 0x56, 0x65, +0x4b, 0x6e, 0x59, 0x64, 0x58, 0x45, 0x6c, 0x6d, 0x54, 0x52, 0x6c, 0x6b, 0x48, 0x39, 0x43, 0x31, +0x46, 0x4b, 0x38, 0x31, 0x56, 0x35, 0x2b, 0x78, 0x4e, 0x2f, 0x36, 0x70, 0x69, 0x4f, 0x70, 0x49, +0x2b, 0x45, 0x63, 0x38, 0x74, 0x41, 0x37, 0x5a, 0x33, 0x45, 0x33, 0x38, 0x6c, 0x72, 0x4b, 0x46, +0x50, 0x4f, 0x70, 0x54, 0x55, 0x45, 0x30, 0x6a, 0x52, 0x44, 0x55, 0x72, 0x61, 0x62, 0x6c, 0x74, +0x41, 0x49, 0x52, 0x54, 0x39, 0x2b, 0x78, 0x59, 0x37, 0x74, 0x32, 0x76, 0x33, 0x44, 0x73, 0x4a, +0x61, 0x74, 0x53, 0x30, 0x66, 0x37, 0x34, 0x79, 0x57, 0x77, 0x67, 0x71, 0x76, 0x52, 0x46, 0x43, +0x30, 0x2b, 0x77, 0x48, 0x64, 0x6d, 0x56, 0x33, 0x35, 0x4d, 0x77, 0x38, 0x76, 0x47, 0x6f, 0x57, +0x42, 0x41, 0x36, 0x47, 0x30, 0x6c, 0x4a, 0x35, 0x51, 0x33, 0x71, 0x66, 0x2f, 0x43, 0x5a, 0x77, +0x69, 0x6b, 0x62, 0x72, 0x61, 0x49, 0x61, 0x38, 0x71, 0x6c, 0x49, 0x38, 0x50, 0x45, 0x4e, 0x67, +0x73, 0x46, 0x44, 0x5a, 0x59, 0x61, 0x6a, 0x61, 0x4b, 0x6c, 0x76, 0x74, 0x73, 0x44, 0x41, 0x4a, +0x56, 0x35, 0x79, 0x4b, 0x48, 0x45, 0x6d, 0x75, 0x5a, 0x39, 0x69, 0x73, 0x49, 0x52, 0x55, 0x55, +0x43, 0x64, 0x53, 0x65, 0x6c, 0x38, 0x50, 0x76, 0x61, 0x33, 0x35, 0x42, 0x42, 0x2f, 0x6b, 0x74, +0x4a, 0x64, 0x55, 0x46, 0x4f, 0x2b, 0x75, 0x6d, 0x30, 0x71, 0x6e, 0x57, 0x33, 0x4b, 0x4b, 0x35, +0x55, 0x49, 0x54, 0x4d, 0x6a, 0x74, 0x4b, 0x52, 0x66, 0x53, 0x52, 0x56, 0x43, 0x43, 0x54, 0x70, +0x46, 0x4b, 0x73, 0x79, 0x33, 0x54, 0x42, 0x54, 0x5a, 0x69, 0x30, 0x53, 0x49, 0x44, 0x37, 0x5a, +0x4c, 0x68, 0x30, 0x59, 0x62, 0x36, 0x33, 0x4d, 0x43, 0x44, 0x46, 0x36, 0x7a, 0x68, 0x6c, 0x69, +0x76, 0x58, 0x75, 0x6e, 0x65, 0x6e, 0x66, 0x52, 0x36, 0x66, 0x36, 0x44, 0x4e, 0x6b, 0x44, 0x6e, +0x33, 0x4e, 0x36, 0x35, 0x6e, 0x42, 0x78, 0x69, 0x33, 0x66, 0x44, 0x6e, 0x36, 0x69, 0x43, 0x4f, +0x49, 0x39, 0x4a, 0x46, 0x77, 0x52, 0x6a, 0x56, 0x6d, 0x6b, 0x49, 0x43, 0x6b, 0x41, 0x71, 0x63, +0x67, 0x35, 0x5a, 0x6d, 0x4d, 0x2b, 0x75, 0x64, 0x4a, 0x65, 0x32, 0x49, 0x31, 0x4d, 0x6b, 0x6b, +0x70, 0x39, 0x42, 0x61, 0x6f, 0x32, 0x57, 0x63, 0x6f, 0x6b, 0x5a, 0x4e, 0x2b, 0x67, 0x36, 0x6e, +0x73, 0x6a, 0x36, 0x6d, 0x49, 0x34, 0x50, 0x2f, 0x71, 0x35, 0x7a, 0x54, 0x73, 0x74, 0x78, 0x76, +0x2f, 0x71, 0x6e, 0x2b, 0x54, 0x6d, 0x55, 0x73, 0x2b, 0x6f, 0x4b, 0x4b, 0x67, 0x67, 0x75, 0x4b, +0x38, 0x34, 0x68, 0x35, 0x52, 0x5a, 0x49, 0x2b, 0x72, 0x4d, 0x43, 0x46, 0x4c, 0x36, 0x72, 0x59, +0x2b, 0x2f, 0x2f, 0x6f, 0x2b, 0x47, 0x46, 0x71, 0x53, 0x6a, 0x56, 0x48, 0x71, 0x6d, 0x61, 0x42, +0x50, 0x37, 0x30, 0x70, 0x74, 0x6c, 0x65, 0x36, 0x38, 0x66, 0x7a, 0x59, 0x4a, 0x47, 0x49, 0x6c, +0x67, 0x55, 0x69, 0x6d, 0x62, 0x61, 0x50, 0x6c, 0x57, 0x4f, 0x7a, 0x33, 0x72, 0x37, 0x32, 0x79, +0x75, 0x76, 0x4c, 0x56, 0x34, 0x32, 0x52, 0x63, 0x31, 0x58, 0x65, 0x67, 0x2b, 0x46, 0x67, 0x4c, +0x39, 0x63, 0x7a, 0x35, 0x74, 0x5a, 0x78, 0x30, 0x37, 0x64, 0x51, 0x6c, 0x2f, 0x78, 0x46, 0x58, +0x51, 0x49, 0x77, 0x75, 0x62, 0x43, 0x30, 0x56, 0x31, 0x78, 0x38, 0x4c, 0x4f, 0x50, 0x61, 0x73, +0x72, 0x33, 0x64, 0x64, 0x46, 0x67, 0x44, 0x45, 0x58, 0x71, 0x67, 0x31, 0x2b, 0x42, 0x4f, 0x41, +0x34, 0x30, 0x76, 0x35, 0x79, 0x65, 0x65, 0x35, 0x37, 0x7a, 0x55, 0x41, 0x37, 0x6d, 0x7a, 0x64, +0x50, 0x52, 0x32, 0x74, 0x4e, 0x64, 0x66, 0x58, 0x52, 0x32, 0x43, 0x57, 0x2f, 0x49, 0x76, 0x63, +0x64, 0x44, 0x64, 0x54, 0x61, 0x36, 0x37, 0x57, 0x4e, 0x61, 0x54, 0x6e, 0x62, 0x37, 0x6f, 0x4c, +0x4c, 0x4a, 0x55, 0x47, 0x44, 0x6f, 0x4a, 0x4e, 0x59, 0x52, 0x63, 0x33, 0x5a, 0x70, 0x33, 0x62, +0x7a, 0x38, 0x6a, 0x75, 0x4f, 0x6b, 0x6a, 0x59, 0x32, 0x72, 0x73, 0x68, 0x43, 0x62, 0x6a, 0x4f, +0x52, 0x56, 0x74, 0x33, 0x51, 0x51, 0x4e, 0x6d, 0x42, 0x42, 0x33, 0x5a, 0x4c, 0x34, 0x6f, 0x58, +0x70, 0x2f, 0x39, 0x73, 0x65, 0x6b, 0x6d, 0x31, 0x48, 0x65, 0x4f, 0x51, 0x49, 0x72, 0x4e, 0x71, +0x51, 0x7a, 0x61, 0x7a, 0x31, 0x52, 0x4d, 0x78, 0x31, 0x64, 0x30, 0x61, 0x41, 0x49, 0x37, 0x61, +0x58, 0x2f, 0x7a, 0x2f, 0x45, 0x51, 0x68, 0x65, 0x35, 0x4d, 0x79, 0x67, 0x72, 0x32, 0x6d, 0x62, +0x64, 0x64, 0x2b, 0x39, 0x2b, 0x52, 0x31, 0x34, 0x6b, 0x4c, 0x79, 0x74, 0x64, 0x2f, 0x50, 0x5a, +0x32, 0x36, 0x69, 0x64, 0x4f, 0x44, 0x4d, 0x6c, 0x65, 0x58, 0x50, 0x69, 0x48, 0x66, 0x54, 0x45, +0x37, 0x72, 0x59, 0x4c, 0x74, 0x47, 0x71, 0x6e, 0x4d, 0x2b, 0x33, 0x44, 0x37, 0x50, 0x47, 0x31, +0x56, 0x6b, 0x36, 0x55, 0x4d, 0x37, 0x6a, 0x55, 0x52, 0x59, 0x50, 0x41, 0x66, 0x7a, 0x30, 0x48, +0x66, 0x42, 0x37, 0x6f, 0x76, 0x36, 0x47, 0x59, 0x4c, 0x6f, 0x43, 0x4a, 0x64, 0x6e, 0x5a, 0x4e, +0x59, 0x4d, 0x56, 0x69, 0x64, 0x38, 0x62, 0x63, 0x6b, 0x74, 0x48, 0x32, 0x52, 0x42, 0x2f, 0x32, +0x76, 0x79, 0x61, 0x41, 0x79, 0x58, 0x33, 0x36, 0x45, 0x64, 0x34, 0x64, 0x32, 0x63, 0x74, 0x4f, +0x54, 0x31, 0x36, 0x52, 0x52, 0x35, 0x42, 0x39, 0x67, 0x77, 0x54, 0x32, 0x4f, 0x2b, 0x54, 0x71, +0x37, 0x32, 0x5a, 0x66, 0x61, 0x50, 0x61, 0x41, 0x74, 0x43, 0x75, 0x75, 0x47, 0x79, 0x5a, 0x5a, +0x54, 0x6c, 0x30, 0x36, 0x71, 0x57, 0x6c, 0x6f, 0x30, 0x4e, 0x71, 0x6b, 0x78, 0x4a, 0x35, 0x31, +0x6f, 0x4d, 0x38, 0x43, 0x52, 0x70, 0x44, 0x6f, 0x49, 0x31, 0x46, 0x33, 0x44, 0x53, 0x43, 0x66, +0x64, 0x79, 0x2f, 0x6a, 0x75, 0x76, 0x68, 0x4e, 0x30, 0x43, 0x56, 0x54, 0x6c, 0x69, 0x50, 0x70, +0x4f, 0x75, 0x32, 0x34, 0x61, 0x78, 0x30, 0x38, 0x34, 0x6e, 0x6f, 0x4a, 0x59, 0x67, 0x55, 0x31, +0x34, 0x36, 0x52, 0x4f, 0x4c, 0x78, 0x4f, 0x6a, 0x30, 0x4f, 0x33, 0x6e, 0x78, 0x6d, 0x78, 0x65, +0x35, 0x36, 0x6f, 0x79, 0x72, 0x30, 0x69, 0x69, 0x73, 0x41, 0x44, 0x4a, 0x52, 0x59, 0x50, 0x64, +0x69, 0x61, 0x38, 0x35, 0x62, 0x51, 0x30, 0x56, 0x65, 0x52, 0x52, 0x62, 0x4b, 0x75, 0x53, 0x32, +0x35, 0x6a, 0x5a, 0x33, 0x75, 0x33, 0x43, 0x6d, 0x64, 0x41, 0x41, 0x46, 0x4b, 0x57, 0x57, 0x48, +0x63, 0x58, 0x44, 0x72, 0x34, 0x44, 0x5a, 0x31, 0x4f, 0x73, 0x43, 0x41, 0x64, 0x4d, 0x6a, 0x6e, +0x39, 0x7a, 0x42, 0x4d, 0x77, 0x58, 0x2f, 0x55, 0x69, 0x38, 0x38, 0x68, 0x71, 0x33, 0x75, 0x69, +0x35, 0x38, 0x4b, 0x61, 0x62, 0x74, 0x66, 0x51, 0x78, 0x32, 0x42, 0x69, 0x4b, 0x66, 0x72, 0x32, +0x41, 0x39, 0x68, 0x66, 0x47, 0x73, 0x54, 0x59, 0x61, 0x37, 0x52, 0x61, 0x4a, 0x7a, 0x61, 0x30, +0x59, 0x46, 0x34, 0x37, 0x35, 0x69, 0x71, 0x33, 0x35, 0x70, 0x51, 0x42, 0x36, 0x37, 0x62, 0x77, +0x78, 0x4f, 0x66, 0x4f, 0x78, 0x48, 0x7a, 0x36, 0x38, 0x6d, 0x6a, 0x4e, 0x4e, 0x46, 0x73, 0x75, +0x72, 0x67, 0x33, 0x79, 0x58, 0x39, 0x71, 0x70, 0x79, 0x61, 0x31, 0x4e, 0x77, 0x57, 0x69, 0x33, +0x33, 0x4b, 0x56, 0x50, 0x65, 0x35, 0x70, 0x37, 0x59, 0x59, 0x39, 0x78, 0x5a, 0x63, 0x6a, 0x6d, +0x79, 0x6f, 0x49, 0x67, 0x62, 0x76, 0x7a, 0x79, 0x4e, 0x50, 0x34, 0x78, 0x38, 0x67, 0x71, 0x53, +0x66, 0x35, 0x4f, 0x47, 0x56, 0x6c, 0x7a, 0x43, 0x78, 0x37, 0x76, 0x64, 0x38, 0x4d, 0x50, 0x30, +0x46, 0x38, 0x67, 0x76, 0x7a, 0x72, 0x46, 0x53, 0x5a, 0x4f, 0x36, 0x30, 0x32, 0x67, 0x57, 0x4c, +0x4a, 0x6b, 0x33, 0x76, 0x78, 0x66, 0x6d, 0x74, 0x76, 0x37, 0x76, 0x6a, 0x37, 0x41, 0x6d, 0x37, +0x71, 0x73, 0x34, 0x69, 0x38, 0x53, 0x49, 0x53, 0x70, 0x6d, 0x2f, 0x74, 0x7a, 0x37, 0x68, 0x44, +0x4e, 0x30, 0x59, 0x65, 0x4f, 0x35, 0x6f, 0x52, 0x6e, 0x36, 0x37, 0x47, 0x4e, 0x5a, 0x35, 0x41, +0x68, 0x79, 0x59, 0x77, 0x34, 0x78, 0x50, 0x67, 0x76, 0x6e, 0x33, 0x5a, 0x35, 0x70, 0x2f, 0x46, +0x4e, 0x4c, 0x59, 0x44, 0x4f, 0x79, 0x76, 0x2b, 0x65, 0x7a, 0x73, 0x72, 0x4b, 0x58, 0x46, 0x33, +0x69, 0x6f, 0x49, 0x39, 0x79, 0x7a, 0x31, 0x64, 0x56, 0x64, 0x55, 0x47, 0x51, 0x4d, 0x2f, 0x38, +0x65, 0x6e, 0x76, 0x73, 0x73, 0x77, 0x4d, 0x61, 0x4e, 0x59, 0x55, 0x65, 0x58, 0x46, 0x64, 0x36, +0x77, 0x59, 0x56, 0x33, 0x79, 0x76, 0x77, 0x47, 0x79, 0x6b, 0x68, 0x2b, 0x36, 0x4c, 0x79, 0x66, +0x42, 0x64, 0x32, 0x54, 0x4f, 0x33, 0x77, 0x38, 0x44, 0x54, 0x32, 0x43, 0x37, 0x79, 0x7a, 0x44, +0x38, 0x48, 0x2f, 0x69, 0x74, 0x7a, 0x44, 0x4e, 0x57, 0x54, 0x70, 0x4b, 0x62, 0x4c, 0x78, 0x68, +0x74, 0x76, 0x35, 0x31, 0x49, 0x55, 0x52, 0x54, 0x62, 0x69, 0x44, 0x45, 0x65, 0x4c, 0x59, 0x6b, +0x61, 0x2f, 0x4c, 0x79, 0x59, 0x39, 0x55, 0x6e, 0x50, 0x30, 0x46, 0x73, 0x4c, 0x59, 0x41, 0x2b, +0x70, 0x44, 0x48, 0x2b, 0x37, 0x36, 0x46, 0x74, 0x62, 0x67, 0x73, 0x2f, 0x4e, 0x55, 0x48, 0x55, +0x31, 0x47, 0x70, 0x77, 0x7a, 0x44, 0x31, 0x72, 0x69, 0x4b, 0x65, 0x76, 0x37, 0x48, 0x31, 0x48, +0x43, 0x61, 0x64, 0x73, 0x4a, 0x6a, 0x4c, 0x62, 0x58, 0x39, 0x73, 0x74, 0x6e, 0x77, 0x4d, 0x34, +0x77, 0x39, 0x64, 0x49, 0x30, 0x79, 0x6e, 0x6e, 0x51, 0x32, 0x49, 0x4f, 0x6f, 0x4b, 0x4b, 0x30, +0x67, 0x34, 0x6b, 0x56, 0x70, 0x54, 0x37, 0x57, 0x52, 0x6b, 0x41, 0x6c, 0x71, 0x53, 0x6d, 0x73, +0x6f, 0x56, 0x41, 0x55, 0x63, 0x4e, 0x75, 0x59, 0x77, 0x54, 0x72, 0x6e, 0x6a, 0x56, 0x32, 0x6b, +0x55, 0x38, 0x74, 0x49, 0x63, 0x46, 0x4e, 0x67, 0x5a, 0x53, 0x2f, 0x70, 0x56, 0x39, 0x69, 0x4d, +0x2f, 0x55, 0x6b, 0x41, 0x6d, 0x79, 0x70, 0x6b, 0x76, 0x38, 0x6a, 0x6e, 0x74, 0x2b, 0x4e, 0x4d, +0x73, 0x55, 0x70, 0x75, 0x4a, 0x55, 0x68, 0x62, 0x42, 0x54, 0x53, 0x65, 0x35, 0x78, 0x44, 0x49, +0x47, 0x62, 0x5a, 0x77, 0x48, 0x6e, 0x73, 0x47, 0x39, 0x75, 0x34, 0x66, 0x55, 0x55, 0x59, 0x53, +0x4b, 0x75, 0x45, 0x30, 0x64, 0x30, 0x32, 0x36, 0x35, 0x72, 0x39, 0x7a, 0x71, 0x71, 0x75, 0x2f, +0x55, 0x50, 0x36, 0x58, 0x66, 0x58, 0x7a, 0x74, 0x74, 0x4f, 0x36, 0x6d, 0x64, 0x4b, 0x71, 0x78, +0x79, 0x71, 0x72, 0x44, 0x4f, 0x73, 0x55, 0x6d, 0x49, 0x38, 0x4e, 0x6f, 0x2b, 0x34, 0x78, 0x6b, +0x41, 0x65, 0x74, 0x33, 0x67, 0x30, 0x73, 0x38, 0x59, 0x37, 0x6a, 0x75, 0x7a, 0x42, 0x73, 0x2f, +0x7a, 0x71, 0x50, 0x72, 0x44, 0x46, 0x57, 0x6d, 0x46, 0x4a, 0x42, 0x6e, 0x49, 0x5a, 0x47, 0x58, +0x49, 0x6e, 0x41, 0x6e, 0x42, 0x71, 0x6a, 0x64, 0x6d, 0x34, 0x4b, 0x48, 0x34, 0x62, 0x76, 0x35, +0x59, 0x45, 0x70, 0x34, 0x58, 0x47, 0x62, 0x7a, 0x62, 0x6c, 0x32, 0x32, 0x31, 0x43, 0x2f, 0x62, +0x70, 0x58, 0x72, 0x69, 0x67, 0x70, 0x30, 0x50, 0x43, 0x6a, 0x58, 0x65, 0x66, 0x5a, 0x74, 0x39, +0x66, 0x61, 0x61, 0x76, 0x33, 0x71, 0x4a, 0x52, 0x62, 0x47, 0x6e, 0x4f, 0x41, 0x6a, 0x46, 0x73, +0x70, 0x43, 0x51, 0x79, 0x6c, 0x51, 0x6c, 0x6e, 0x37, 0x77, 0x6d, 0x74, 0x33, 0x58, 0x63, 0x75, +0x57, 0x6f, 0x68, 0x70, 0x57, 0x6e, 0x76, 0x74, 0x6e, 0x72, 0x75, 0x2f, 0x38, 0x6e, 0x76, 0x72, +0x43, 0x76, 0x6e, 0x69, 0x58, 0x37, 0x63, 0x76, 0x35, 0x79, 0x36, 0x76, 0x59, 0x71, 0x57, 0x30, +0x68, 0x73, 0x32, 0x4a, 0x76, 0x63, 0x2b, 0x43, 0x2f, 0x4e, 0x64, 0x47, 0x2b, 0x4c, 0x78, 0x4c, +0x4e, 0x6a, 0x78, 0x44, 0x52, 0x31, 0x73, 0x48, 0x47, 0x43, 0x52, 0x34, 0x6a, 0x36, 0x6c, 0x4e, +0x63, 0x39, 0x47, 0x49, 0x44, 0x37, 0x37, 0x33, 0x38, 0x55, 0x38, 0x36, 0x39, 0x34, 0x6d, 0x69, +0x53, 0x53, 0x78, 0x5a, 0x44, 0x6f, 0x70, 0x4d, 0x54, 0x71, 0x77, 0x64, 0x51, 0x31, 0x71, 0x65, +0x53, 0x74, 0x37, 0x2f, 0x64, 0x77, 0x6b, 0x55, 0x44, 0x57, 0x6b, 0x4d, 0x33, 0x33, 0x38, 0x4f, +0x4c, 0x4e, 0x76, 0x4e, 0x68, 0x57, 0x78, 0x56, 0x74, 0x43, 0x59, 0x6d, 0x51, 0x68, 0x68, 0x6c, +0x50, 0x57, 0x7a, 0x2b, 0x4f, 0x69, 0x63, 0x33, 0x4e, 0x64, 0x4d, 0x36, 0x64, 0x53, 0x39, 0x48, +0x2b, 0x2b, 0x37, 0x50, 0x78, 0x35, 0x70, 0x73, 0x70, 0x4c, 0x79, 0x38, 0x6c, 0x38, 0x50, 0x72, +0x63, 0x6e, 0x70, 0x74, 0x78, 0x66, 0x58, 0x30, 0x39, 0x41, 0x47, 0x56, 0x6c, 0x64, 0x67, 0x43, +0x37, 0x72, 0x64, 0x50, 0x47, 0x72, 0x36, 0x71, 0x55, 0x38, 0x48, 0x6e, 0x2f, 0x38, 0x73, 0x76, +0x52, 0x48, 0x52, 0x31, 0x5a, 0x43, 0x48, 0x52, 0x77, 0x62, 0x65, 0x78, 0x4a, 0x31, 0x62, 0x68, +0x66, 0x76, 0x2f, 0x42, 0x35, 0x7a, 0x78, 0x69, 0x69, 0x59, 0x4c, 0x65, 0x39, 0x4f, 0x36, 0x30, +0x72, 0x79, 0x69, 0x36, 0x42, 0x2f, 0x68, 0x6b, 0x6f, 0x64, 0x4b, 0x44, 0x71, 0x48, 0x4b, 0x44, +0x51, 0x34, 0x55, 0x35, 0x4d, 0x4f, 0x65, 0x46, 0x72, 0x49, 0x56, 0x67, 0x30, 0x59, 0x77, 0x5a, +0x76, 0x41, 0x53, 0x39, 0x4f, 0x6e, 0x63, 0x6f, 0x78, 0x77, 0x47, 0x6a, 0x64, 0x67, 0x36, 0x70, +0x79, 0x6b, 0x53, 0x52, 0x79, 0x67, 0x4d, 0x43, 0x38, 0x4b, 0x7a, 0x48, 0x74, 0x32, 0x65, 0x48, +0x48, 0x57, 0x72, 0x41, 0x56, 0x5a, 0x63, 0x2b, 0x42, 0x72, 0x7a, 0x4b, 0x77, 0x36, 0x6e, 0x75, +0x71, 0x79, 0x68, 0x73, 0x6f, 0x4c, 0x76, 0x5a, 0x70, 0x62, 0x73, 0x33, 0x6e, 0x72, 0x62, 0x6b, +0x2f, 0x34, 0x39, 0x4e, 0x6c, 0x2b, 0x37, 0x67, 0x43, 0x59, 0x43, 0x33, 0x6c, 0x77, 0x69, 0x6d, +0x56, 0x56, 0x76, 0x66, 0x4b, 0x73, 0x36, 0x57, 0x6e, 0x45, 0x32, 0x75, 0x67, 0x61, 0x39, 0x6f, +0x41, 0x32, 0x67, 0x6c, 0x37, 0x4b, 0x75, 0x63, 0x57, 0x71, 0x34, 0x57, 0x74, 0x38, 0x49, 0x47, +0x76, 0x76, 0x2f, 0x4b, 0x74, 0x34, 0x49, 0x63, 0x51, 0x65, 0x4c, 0x30, 0x48, 0x4f, 0x5a, 0x64, +0x69, 0x6d, 0x31, 0x42, 0x31, 0x54, 0x52, 0x5a, 0x46, 0x54, 0x71, 0x51, 0x53, 0x42, 0x43, 0x6a, +0x6d, 0x6e, 0x39, 0x2f, 0x39, 0x4d, 0x77, 0x6b, 0x2f, 0x77, 0x52, 0x30, 0x6e, 0x33, 0x59, 0x48, +0x57, 0x68, 0x72, 0x5a, 0x6b, 0x47, 0x38, 0x73, 0x33, 0x72, 0x37, 0x41, 0x67, 0x52, 0x4a, 0x56, +0x44, 0x4f, 0x62, 0x74, 0x42, 0x6d, 0x53, 0x33, 0x63, 0x6b, 0x70, 0x33, 0x5a, 0x53, 0x69, 0x75, +0x2b, 0x62, 0x2f, 0x6b, 0x2b, 0x56, 0x4f, 0x59, 0x4a, 0x55, 0x57, 0x43, 0x4a, 0x52, 0x58, 0x6c, +0x62, 0x41, 0x37, 0x6c, 0x7a, 0x58, 0x45, 0x57, 0x33, 0x6d, 0x6d, 0x2b, 0x5a, 0x66, 0x76, 0x6c, +0x43, 0x47, 0x6e, 0x7a, 0x6e, 0x71, 0x7a, 0x2b, 0x77, 0x33, 0x49, 0x50, 0x4f, 0x6f, 0x4c, 0x32, +0x56, 0x6d, 0x4c, 0x71, 0x4e, 0x62, 0x6d, 0x35, 0x73, 0x55, 0x56, 0x61, 0x63, 0x38, 0x45, 0x65, +0x49, 0x73, 0x66, 0x6f, 0x79, 0x76, 0x54, 0x51, 0x6c, 0x66, 0x4c, 0x78, 0x42, 0x41, 0x7a, 0x4a, +0x61, 0x61, 0x34, 0x4f, 0x75, 0x32, 0x77, 0x44, 0x41, 0x35, 0x69, 0x59, 0x4c, 0x6f, 0x73, 0x69, +0x31, 0x61, 0x36, 0x33, 0x42, 0x4c, 0x57, 0x50, 0x35, 0x4b, 0x4e, 0x7a, 0x64, 0x32, 0x42, 0x64, +0x45, 0x48, 0x59, 0x71, 0x72, 0x64, 0x42, 0x73, 0x53, 0x71, 0x46, 0x71, 0x2f, 0x6e, 0x75, 0x56, +0x4e, 0x54, 0x53, 0x57, 0x44, 0x64, 0x6e, 0x6b, 0x2f, 0x73, 0x58, 0x37, 0x78, 0x35, 0x4d, 0x49, +0x66, 0x31, 0x51, 0x67, 0x59, 0x77, 0x34, 0x62, 0x47, 0x56, 0x69, 0x63, 0x34, 0x6f, 0x73, 0x4b, +0x56, 0x6a, 0x72, 0x53, 0x61, 0x63, 0x2f, 0x71, 0x30, 0x57, 0x32, 0x59, 0x70, 0x42, 0x76, 0x59, +0x74, 0x42, 0x33, 0x7a, 0x75, 0x72, 0x37, 0x32, 0x61, 0x73, 0x70, 0x62, 0x4c, 0x4d, 0x50, 0x31, +0x65, 0x70, 0x66, 0x72, 0x6a, 0x30, 0x62, 0x44, 0x7a, 0x56, 0x6e, 0x62, 0x36, 0x35, 0x4f, 0x2b, +0x59, 0x6f, 0x32, 0x76, 0x5a, 0x38, 0x39, 0x50, 0x31, 0x6a, 0x46, 0x6f, 0x32, 0x69, 0x34, 0x6a, +0x30, 0x38, 0x45, 0x6b, 0x35, 0x62, 0x30, 0x38, 0x72, 0x65, 0x52, 0x36, 0x4c, 0x52, 0x74, 0x46, +0x4b, 0x38, 0x56, 0x7a, 0x6b, 0x4e, 0x61, 0x4b, 0x4c, 0x78, 0x70, 0x4c, 0x66, 0x73, 0x70, 0x56, +0x34, 0x55, 0x7a, 0x4d, 0x6d, 0x6b, 0x53, 0x54, 0x65, 0x71, 0x34, 0x4b, 0x6b, 0x30, 0x45, 0x78, +0x4d, 0x2b, 0x4c, 0x79, 0x35, 0x64, 0x51, 0x38, 0x53, 0x77, 0x76, 0x43, 0x7a, 0x77, 0x6a, 0x70, +0x47, 0x64, 0x6a, 0x54, 0x51, 0x6e, 0x4b, 0x6a, 0x67, 0x73, 0x51, 0x32, 0x39, 0x47, 0x54, 0x53, +0x67, 0x67, 0x71, 0x41, 0x66, 0x56, 0x43, 0x30, 0x74, 0x6c, 0x42, 0x78, 0x30, 0x45, 0x4b, 0x6c, +0x56, 0x71, 0x2f, 0x42, 0x72, 0x61, 0x37, 0x64, 0x62, 0x36, 0x59, 0x50, 0x54, 0x63, 0x37, 0x74, +0x62, 0x42, 0x30, 0x64, 0x39, 0x71, 0x2b, 0x47, 0x56, 0x65, 0x59, 0x72, 0x32, 0x6c, 0x4f, 0x47, +0x4d, 0x66, 0x53, 0x4c, 0x55, 0x6c, 0x46, 0x6d, 0x57, 0x51, 0x36, 0x31, 0x5a, 0x69, 0x32, 0x35, +0x72, 0x44, 0x51, 0x32, 0x54, 0x6f, 0x65, 0x42, 0x4a, 0x44, 0x6f, 0x71, 0x63, 0x70, 0x57, 0x72, +0x63, 0x55, 0x2f, 0x6a, 0x66, 0x64, 0x30, 0x58, 0x5a, 0x4e, 0x58, 0x5a, 0x44, 0x62, 0x2b, 0x46, +0x55, 0x6e, 0x55, 0x4d, 0x31, 0x5a, 0x43, 0x66, 0x77, 0x6d, 0x71, 0x6b, 0x74, 0x71, 0x44, 0x4e, +0x32, 0x74, 0x34, 0x34, 0x4e, 0x47, 0x68, 0x51, 0x4f, 0x58, 0x4c, 0x64, 0x68, 0x75, 0x4c, 0x74, +0x75, 0x41, 0x77, 0x63, 0x72, 0x78, 0x63, 0x6c, 0x4b, 0x57, 0x56, 0x74, 0x4b, 0x38, 0x44, 0x74, +0x47, 0x57, 0x47, 0x6d, 0x77, 0x30, 0x51, 0x4a, 0x54, 0x37, 0x6d, 0x4e, 0x65, 0x39, 0x54, 0x47, +0x66, 0x70, 0x73, 0x4f, 0x50, 0x58, 0x62, 0x46, 0x67, 0x42, 0x69, 0x63, 0x4f, 0x47, 0x6b, 0x62, +0x56, 0x71, 0x47, 0x38, 0x6f, 0x4c, 0x45, 0x7a, 0x79, 0x34, 0x6f, 0x75, 0x43, 0x42, 0x51, 0x73, +0x55, 0x64, 0x39, 0x37, 0x5a, 0x7a, 0x4b, 0x38, 0x6e, 0x50, 0x73, 0x4e, 0x4f, 0x57, 0x31, 0x61, +0x7a, 0x2b, 0x71, 0x74, 0x52, 0x64, 0x6b, 0x4e, 0x43, 0x71, 0x63, 0x4b, 0x7a, 0x72, 0x4b, 0x4f, +0x55, 0x6a, 0x33, 0x6d, 0x51, 0x7a, 0x72, 0x39, 0x2b, 0x52, 0x57, 0x48, 0x31, 0x4d, 0x46, 0x44, +0x43, 0x76, 0x62, 0x53, 0x32, 0x79, 0x78, 0x66, 0x47, 0x2b, 0x74, 0x36, 0x48, 0x31, 0x6d, 0x53, +0x6a, 0x30, 0x73, 0x73, 0x69, 0x52, 0x6b, 0x4d, 0x30, 0x54, 0x75, 0x73, 0x75, 0x6e, 0x38, 0x42, +0x39, 0x35, 0x32, 0x53, 0x68, 0x79, 0x4e, 0x70, 0x6f, 0x50, 0x44, 0x79, 0x6b, 0x6b, 0x6d, 0x78, +0x6f, 0x33, 0x6d, 0x44, 0x4a, 0x50, 0x53, 0x57, 0x49, 0x65, 0x42, 0x47, 0x30, 0x30, 0x66, 0x67, +0x5a, 0x53, 0x69, 0x75, 0x32, 0x31, 0x61, 0x51, 0x4c, 0x79, 0x74, 0x78, 0x54, 0x70, 0x76, 0x73, +0x71, 0x44, 0x64, 0x49, 0x45, 0x4b, 0x4f, 0x33, 0x65, 0x65, 0x38, 0x47, 0x6f, 0x33, 0x6f, 0x5a, +0x65, 0x68, 0x64, 0x6a, 0x65, 0x54, 0x36, 0x66, 0x33, 0x50, 0x56, 0x41, 0x36, 0x67, 0x64, 0x49, +0x53, 0x6f, 0x59, 0x76, 0x73, 0x36, 0x43, 0x63, 0x51, 0x35, 0x39, 0x43, 0x47, 0x50, 0x6b, 0x58, +0x77, 0x35, 0x71, 0x45, 0x61, 0x33, 0x74, 0x30, 0x44, 0x4d, 0x33, 0x41, 0x49, 0x35, 0x4a, 0x64, +0x6b, 0x53, 0x48, 0x6f, 0x48, 0x63, 0x74, 0x35, 0x42, 0x37, 0x36, 0x30, 0x79, 0x6d, 0x48, 0x59, +0x6e, 0x66, 0x74, 0x6d, 0x76, 0x54, 0x37, 0x6f, 0x42, 0x55, 0x4d, 0x61, 0x32, 0x32, 0x49, 0x41, +0x4b, 0x72, 0x50, 0x4c, 0x53, 0x4d, 0x74, 0x75, 0x5a, 0x71, 0x72, 0x49, 0x42, 0x52, 0x36, 0x36, +0x46, 0x49, 0x4f, 0x4c, 0x57, 0x77, 0x62, 0x56, 0x75, 0x70, 0x61, 0x4b, 0x35, 0x47, 0x62, 0x56, +0x31, 0x4b, 0x39, 0x47, 0x43, 0x41, 0x6c, 0x5a, 0x2f, 0x75, 0x48, 0x76, 0x42, 0x67, 0x46, 0x46, +0x50, 0x71, 0x51, 0x33, 0x66, 0x6e, 0x37, 0x31, 0x6a, 0x30, 0x77, 0x48, 0x58, 0x47, 0x77, 0x65, +0x6a, 0x75, 0x34, 0x42, 0x78, 0x38, 0x44, 0x50, 0x32, 0x63, 0x45, 0x68, 0x58, 0x66, 0x6e, 0x64, +0x31, 0x4b, 0x77, 0x37, 0x67, 0x45, 0x32, 0x75, 0x6f, 0x74, 0x79, 0x53, 0x65, 0x56, 0x74, 0x44, +0x59, 0x69, 0x42, 0x6d, 0x61, 0x67, 0x4b, 0x31, 0x4e, 0x47, 0x4a, 0x48, 0x45, 0x74, 0x4c, 0x55, +0x54, 0x45, 0x36, 0x31, 0x32, 0x55, 0x30, 0x72, 0x58, 0x75, 0x42, 0x68, 0x6a, 0x66, 0x64, 0x75, +0x31, 0x42, 0x32, 0x6a, 0x4e, 0x47, 0x30, 0x58, 0x6a, 0x4f, 0x57, 0x66, 0x6b, 0x47, 0x49, 0x71, +0x61, 0x4e, 0x39, 0x47, 0x78, 0x59, 0x6a, 0x57, 0x52, 0x71, 0x6a, 0x67, 0x46, 0x6f, 0x34, 0x61, +0x79, 0x5a, 0x64, 0x55, 0x6d, 0x46, 0x6a, 0x59, 0x59, 0x55, 0x74, 0x4c, 0x67, 0x43, 0x38, 0x58, +0x30, 0x7a, 0x6a, 0x36, 0x6b, 0x69, 0x6c, 0x4b, 0x38, 0x73, 0x4c, 0x55, 0x76, 0x70, 0x2f, 0x65, +0x71, 0x35, 0x62, 0x2b, 0x71, 0x6c, 0x47, 0x44, 0x75, 0x46, 0x75, 0x33, 0x62, 0x6c, 0x2b, 0x5a, +0x33, 0x33, 0x36, 0x58, 0x38, 0x71, 0x4b, 0x50, 0x43, 0x58, 0x59, 0x75, 0x33, 0x56, 0x2f, 0x6d, +0x44, 0x43, 0x70, 0x71, 0x35, 0x41, 0x6c, 0x4a, 0x64, 0x43, 0x72, 0x76, 0x57, 0x51, 0x48, 0x76, +0x4b, 0x43, 0x79, 0x75, 0x2f, 0x63, 0x66, 0x69, 0x76, 0x54, 0x66, 0x4e, 0x73, 0x72, 0x6b, 0x42, +0x6e, 0x6f, 0x4d, 0x68, 0x64, 0x56, 0x49, 0x31, 0x37, 0x43, 0x72, 0x38, 0x62, 0x6c, 0x4c, 0x31, +0x6d, 0x38, 0x32, 0x59, 0x71, 0x2b, 0x2f, 0x51, 0x4a, 0x47, 0x32, 0x49, 0x62, 0x4e, 0x77, 0x2f, +0x44, 0x51, 0x6c, 0x71, 0x58, 0x2f, 0x51, 0x75, 0x76, 0x4c, 0x4a, 0x2b, 0x69, 0x66, 0x6b, 0x64, +0x69, 0x7a, 0x50, 0x69, 0x4d, 0x35, 0x55, 0x56, 0x74, 0x46, 0x61, 0x31, 0x61, 0x57, 0x36, 0x47, +0x36, 0x32, 0x6f, 0x6e, 0x35, 0x4b, 0x44, 0x36, 0x4b, 0x78, 0x2f, 0x6b, 0x65, 0x4f, 0x44, 0x57, +0x5a, 0x5a, 0x47, 0x79, 0x67, 0x53, 0x6e, 0x79, 0x59, 0x73, 0x45, 0x49, 0x67, 0x42, 0x54, 0x35, +0x6d, 0x73, 0x4c, 0x76, 0x2f, 0x4a, 0x42, 0x31, 0x2b, 0x37, 0x4c, 0x37, 0x31, 0x39, 0x38, 0x43, +0x32, 0x36, 0x39, 0x47, 0x78, 0x42, 0x4d, 0x5a, 0x49, 0x46, 0x69, 0x79, 0x51, 0x37, 0x4c, 0x79, +0x7a, 0x62, 0x54, 0x6b, 0x38, 0x54, 0x37, 0x44, 0x48, 0x34, 0x4a, 0x6c, 0x4d, 0x75, 0x48, 0x2b, +0x68, 0x69, 0x33, 0x68, 0x51, 0x49, 0x41, 0x58, 0x65, 0x6b, 0x41, 0x48, 0x38, 0x68, 0x4b, 0x39, +0x68, 0x34, 0x44, 0x67, 0x6f, 0x4c, 0x41, 0x78, 0x66, 0x4f, 0x6b, 0x52, 0x4a, 0x6c, 0x33, 0x32, +0x4d, 0x57, 0x66, 0x30, 0x56, 0x52, 0x71, 0x59, 0x77, 0x51, 0x2f, 0x62, 0x43, 0x6a, 0x4a, 0x32, +0x55, 0x6e, 0x51, 0x47, 0x65, 0x68, 0x78, 0x78, 0x2b, 0x67, 0x41, 0x56, 0x35, 0x6a, 0x46, 0x55, +0x46, 0x6b, 0x73, 0x6f, 0x5a, 0x54, 0x44, 0x7a, 0x34, 0x66, 0x4d, 0x58, 0x6e, 0x62, 0x4e, 0x79, +0x32, 0x6b, 0x5a, 0x52, 0x4d, 0x38, 0x65, 0x44, 0x37, 0x44, 0x2f, 0x4b, 0x48, 0x79, 0x58, 0x39, +0x41, 0x61, 0x52, 0x55, 0x32, 0x43, 0x47, 0x45, 0x44, 0x51, 0x48, 0x63, 0x6f, 0x63, 0x39, 0x66, +0x45, 0x31, 0x31, 0x6f, 0x37, 0x63, 0x63, 0x35, 0x73, 0x46, 0x50, 0x6a, 0x4c, 0x73, 0x33, 0x56, +0x6f, 0x37, 0x63, 0x32, 0x4b, 0x66, 0x2f, 0x76, 0x66, 0x45, 0x65, 0x32, 0x74, 0x61, 0x43, 0x32, +0x49, 0x46, 0x52, 0x56, 0x69, 0x69, 0x69, 0x2f, 0x49, 0x36, 0x55, 0x48, 0x67, 0x67, 0x6c, 0x32, +0x68, 0x39, 0x65, 0x46, 0x5a, 0x6c, 0x4a, 0x61, 0x57, 0x64, 0x6e, 0x33, 0x2b, 0x68, 0x77, 0x71, +0x67, 0x35, 0x37, 0x48, 0x74, 0x67, 0x6c, 0x2b, 0x79, 0x38, 0x38, 0x34, 0x37, 0x5a, 0x34, 0x55, +0x76, 0x6c, 0x66, 0x33, 0x2f, 0x69, 0x6c, 0x66, 0x66, 0x2b, 0x4d, 0x45, 0x65, 0x62, 0x4f, 0x66, +0x57, 0x56, 0x75, 0x53, 0x42, 0x4d, 0x2b, 0x69, 0x63, 0x4f, 0x5a, 0x50, 0x43, 0x69, 0x52, 0x50, +0x42, 0x47, 0x47, 0x72, 0x37, 0x39, 0x75, 0x56, 0x64, 0x69, 0x46, 0x51, 0x50, 0x71, 0x54, 0x55, +0x62, 0x31, 0x39, 0x33, 0x63, 0x73, 0x79, 0x4e, 0x32, 0x63, 0x42, 0x52, 0x4a, 0x6f, 0x68, 0x46, +0x4a, 0x46, 0x49, 0x48, 0x78, 0x6c, 0x49, 0x75, 0x37, 0x56, 0x5a, 0x79, 0x78, 0x55, 0x77, 0x47, +0x37, 0x49, 0x61, 0x56, 0x55, 0x56, 0x70, 0x39, 0x42, 0x42, 0x51, 0x34, 0x2f, 0x52, 0x67, 0x4b, +0x64, 0x6e, 0x44, 0x66, 0x75, 0x4b, 0x57, 0x34, 0x73, 0x72, 0x32, 0x44, 0x4d, 0x73, 0x6f, 0x4e, +0x5a, 0x65, 0x2b, 0x42, 0x59, 0x68, 0x67, 0x79, 0x66, 0x79, 0x5a, 0x79, 0x47, 0x4d, 0x39, 0x6c, +0x72, 0x78, 0x57, 0x4a, 0x65, 0x36, 0x33, 0x30, 0x67, 0x58, 0x77, 0x37, 0x5a, 0x6a, 0x31, 0x74, +0x53, 0x56, 0x31, 0x48, 0x6f, 0x78, 0x63, 0x50, 0x4b, 0x62, 0x33, 0x66, 0x71, 0x74, 0x5a, 0x4a, +0x79, 0x57, 0x77, 0x34, 0x2b, 0x48, 0x71, 0x2b, 0x6b, 0x6a, 0x42, 0x66, 0x6e, 0x74, 0x54, 0x44, +0x57, 0x36, 0x30, 0x56, 0x45, 0x61, 0x4f, 0x59, 0x33, 0x44, 0x2b, 0x4c, 0x49, 0x4d, 0x62, 0x31, +0x6f, 0x62, 0x71, 0x34, 0x6a, 0x36, 0x53, 0x75, 0x75, 0x36, 0x37, 0x57, 0x45, 0x76, 0x37, 0x53, +0x4e, 0x35, 0x76, 0x6e, 0x47, 0x76, 0x70, 0x78, 0x63, 0x73, 0x70, 0x5a, 0x52, 0x70, 0x6f, 0x6d, +0x43, 0x2f, 0x44, 0x72, 0x65, 0x64, 0x77, 0x33, 0x41, 0x78, 0x70, 0x74, 0x75, 0x49, 0x6c, 0x56, +0x62, 0x79, 0x39, 0x59, 0x58, 0x58, 0x73, 0x41, 0x49, 0x79, 0x59, 0x72, 0x6a, 0x6a, 0x6b, 0x74, +0x58, 0x55, 0x6a, 0x38, 0x39, 0x63, 0x73, 0x70, 0x73, 0x51, 0x50, 0x4f, 0x48, 0x44, 0x47, 0x48, +0x57, 0x78, 0x78, 0x39, 0x7a, 0x5a, 0x6b, 0x74, 0x61, 0x36, 0x2f, 0x43, 0x51, 0x45, 0x5a, 0x47, +0x75, 0x49, 0x46, 0x52, 0x4c, 0x61, 0x31, 0x62, 0x50, 0x47, 0x7a, 0x77, 0x66, 0x44, 0x52, 0x70, +0x67, 0x75, 0x6c, 0x45, 0x31, 0x37, 0x69, 0x6e, 0x66, 0x63, 0x68, 0x6f, 0x41, 0x31, 0x2f, 0x36, +0x47, 0x68, 0x78, 0x4f, 0x72, 0x77, 0x39, 0x42, 0x41, 0x57, 0x38, 0x73, 0x7a, 0x64, 0x44, 0x79, +0x36, 0x6a, 0x50, 0x69, 0x65, 0x68, 0x63, 0x6a, 0x6a, 0x61, 0x69, 0x6b, 0x70, 0x6d, 0x34, 0x6f, +0x78, 0x2f, 0x63, 0x4c, 0x56, 0x68, 0x4d, 0x7a, 0x44, 0x4c, 0x6b, 0x31, 0x4c, 0x66, 0x6e, 0x66, +0x57, 0x57, 0x61, 0x78, 0x5a, 0x75, 0x35, 0x5a, 0x72, 0x58, 0x33, 0x75, 0x4e, 0x34, 0x34, 0x58, +0x67, 0x56, 0x31, 0x4b, 0x51, 0x76, 0x31, 0x5a, 0x67, 0x48, 0x76, 0x55, 0x78, 0x45, 0x33, 0x7a, +0x4d, 0x4f, 0x49, 0x48, 0x35, 0x78, 0x72, 0x66, 0x71, 0x51, 0x61, 0x2f, 0x5a, 0x38, 0x47, 0x4d, +0x51, 0x77, 0x34, 0x78, 0x76, 0x4a, 0x52, 0x49, 0x54, 0x50, 0x50, 0x2b, 0x38, 0x52, 0x41, 0x72, +0x4a, 0x76, 0x48, 0x6b, 0x57, 0x50, 0x7a, 0x7a, 0x72, 0x4c, 0x49, 0x47, 0x33, 0x69, 0x38, 0x54, +0x34, 0x66, 0x65, 0x7a, 0x4b, 0x68, 0x47, 0x38, 0x63, 0x6b, 0x34, 0x2b, 0x31, 0x56, 0x4f, 0x61, +0x30, 0x6f, 0x6c, 0x6c, 0x44, 0x6e, 0x38, 0x33, 0x66, 0x59, 0x2b, 0x61, 0x38, 0x67, 0x30, 0x6b, +0x4a, 0x54, 0x44, 0x51, 0x66, 0x4d, 0x2b, 0x62, 0x77, 0x4c, 0x68, 0x58, 0x41, 0x57, 0x6b, 0x64, +0x78, 0x36, 0x4b, 0x67, 0x49, 0x48, 0x54, 0x45, 0x77, 0x38, 0x4a, 0x2b, 0x46, 0x2f, 0x79, 0x45, +0x68, 0x45, 0x71, 0x54, 0x38, 0x46, 0x42, 0x75, 0x61, 0x4e, 0x36, 0x51, 0x72, 0x73, 0x62, 0x53, +0x41, 0x52, 0x7a, 0x68, 0x38, 0x6b, 0x33, 0x52, 0x46, 0x6d, 0x58, 0x75, 0x6f, 0x67, 0x4c, 0x37, +0x30, 0x77, 0x79, 0x6c, 0x41, 0x69, 0x41, 0x49, 0x48, 0x69, 0x5a, 0x38, 0x62, 0x66, 0x2b, 0x58, +0x7a, 0x33, 0x70, 0x72, 0x52, 0x44, 0x4a, 0x76, 0x37, 0x4f, 0x57, 0x4e, 0x4f, 0x69, 0x58, 0x56, +0x62, 0x67, 0x54, 0x50, 0x46, 0x4b, 0x37, 0x6f, 0x38, 0x76, 0x77, 0x4d, 0x4e, 0x67, 0x4a, 0x53, +0x53, 0x76, 0x46, 0x38, 0x75, 0x34, 0x49, 0x46, 0x7a, 0x42, 0x72, 0x43, 0x70, 0x53, 0x56, 0x67, +0x64, 0x51, 0x47, 0x6d, 0x59, 0x38, 0x75, 0x77, 0x47, 0x4f, 0x2b, 0x31, 0x51, 0x36, 0x61, 0x6d, +0x58, 0x56, 0x4e, 0x70, 0x4f, 0x52, 0x35, 0x7a, 0x71, 0x54, 0x55, 0x32, 0x76, 0x4f, 0x4e, 0x4d, +0x75, 0x2b, 0x5a, 0x71, 0x64, 0x68, 0x6a, 0x53, 0x77, 0x35, 0x52, 0x66, 0x6e, 0x6f, 0x34, 0x48, +0x6a, 0x4a, 0x37, 0x31, 0x4e, 0x79, 0x36, 0x35, 0x2f, 0x70, 0x62, 0x4e, 0x35, 0x4d, 0x30, 0x61, +0x6e, 0x71, 0x42, 0x77, 0x77, 0x78, 0x57, 0x7a, 0x62, 0x38, 0x4f, 0x66, 0x74, 0x4e, 0x67, 0x4a, +0x72, 0x48, 0x76, 0x75, 0x45, 0x79, 0x70, 0x30, 0x50, 0x51, 0x61, 0x51, 0x61, 0x62, 0x4a, 0x70, +0x6f, 0x68, 0x59, 0x63, 0x56, 0x5a, 0x37, 0x47, 0x6e, 0x73, 0x4d, 0x49, 0x73, 0x32, 0x75, 0x31, +0x31, 0x6f, 0x43, 0x56, 0x61, 0x53, 0x32, 0x49, 0x46, 0x2f, 0x56, 0x6c, 0x65, 0x71, 0x5a, 0x69, +0x32, 0x65, 0x41, 0x31, 0x6a, 0x5a, 0x69, 0x2f, 0x68, 0x34, 0x59, 0x33, 0x37, 0x30, 0x31, 0x6f, +0x59, 0x5a, 0x63, 0x70, 0x4e, 0x50, 0x75, 0x2f, 0x76, 0x44, 0x52, 0x39, 0x32, 0x39, 0x4f, 0x57, +0x30, 0x4e, 0x52, 0x66, 0x79, 0x58, 0x66, 0x48, 0x70, 0x46, 0x4d, 0x59, 0x79, 0x4b, 0x37, 0x39, +0x74, 0x58, 0x43, 0x49, 0x52, 0x30, 0x45, 0x72, 0x52, 0x2b, 0x73, 0x6c, 0x6e, 0x2f, 0x47, 0x4e, +0x41, 0x42, 0x56, 0x38, 0x76, 0x62, 0x61, 0x47, 0x68, 0x33, 0x4d, 0x35, 0x50, 0x50, 0x2f, 0x2f, +0x73, 0x53, 0x2b, 0x59, 0x4e, 0x72, 0x6d, 0x4a, 0x38, 0x70, 0x64, 0x31, 0x4c, 0x6f, 0x6c, 0x52, +0x33, 0x63, 0x46, 0x35, 0x73, 0x41, 0x56, 0x65, 0x4b, 0x55, 0x54, 0x7a, 0x64, 0x30, 0x4a, 0x39, +0x66, 0x46, 0x79, 0x66, 0x35, 0x52, 0x50, 0x63, 0x44, 0x4c, 0x41, 0x79, 0x55, 0x74, 0x71, 0x31, +0x59, 0x52, 0x74, 0x2f, 0x71, 0x30, 0x46, 0x74, 0x61, 0x6b, 0x42, 0x35, 0x51, 0x59, 0x4f, 0x50, +0x4b, 0x7a, 0x39, 0x6a, 0x37, 0x59, 0x39, 0x78, 0x36, 0x6c, 0x4b, 0x53, 0x68, 0x7a, 0x64, 0x6d, +0x35, 0x33, 0x50, 0x52, 0x50, 0x61, 0x67, 0x4e, 0x53, 0x63, 0x74, 0x31, 0x68, 0x68, 0x78, 0x45, +0x52, 0x50, 0x70, 0x35, 0x62, 0x67, 0x67, 0x77, 0x32, 0x47, 0x2f, 0x58, 0x36, 0x39, 0x69, 0x58, +0x32, 0x38, 0x63, 0x65, 0x75, 0x44, 0x4f, 0x61, 0x6f, 0x49, 0x75, 0x39, 0x49, 0x41, 0x2b, 0x42, +0x41, 0x70, 0x6b, 0x43, 0x46, 0x49, 0x62, 0x50, 0x38, 0x4a, 0x42, 0x4a, 0x76, 0x49, 0x62, 0x65, +0x32, 0x73, 0x74, 0x57, 0x72, 0x5a, 0x6d, 0x76, 0x6e, 0x4d, 0x48, 0x62, 0x70, 0x57, 0x45, 0x6f, +0x79, 0x2f, 0x69, 0x2f, 0x79, 0x38, 0x69, 0x2f, 0x75, 0x57, 0x6e, 0x2b, 0x41, 0x57, 0x43, 0x7a, +0x47, 0x68, 0x52, 0x64, 0x65, 0x79, 0x43, 0x4f, 0x50, 0x50, 0x45, 0x4b, 0x69, 0x4d, 0x38, 0x46, +0x35, 0x35, 0x35, 0x2f, 0x48, 0x58, 0x35, 0x35, 0x34, 0x67, 0x74, 0x6b, 0x64, 0x48, 0x56, 0x7a, +0x32, 0x72, 0x57, 0x42, 0x6e, 0x33, 0x38, 0x64, 0x38, 0x4b, 0x7a, 0x43, 0x6e, 0x2b, 0x70, 0x68, +0x44, 0x66, 0x63, 0x78, 0x39, 0x36, 0x66, 0x42, 0x6a, 0x34, 0x4d, 0x50, 0x58, 0x65, 0x65, 0x68, +0x44, 0x4a, 0x62, 0x38, 0x35, 0x7a, 0x55, 0x63, 0x49, 0x71, 0x38, 0x70, 0x7a, 0x31, 0x6c, 0x6b, +0x57, 0x4f, 0x6c, 0x44, 0x7a, 0x34, 0x33, 0x68, 0x2b, 0x4d, 0x49, 0x65, 0x56, 0x34, 0x64, 0x56, +0x7a, 0x7a, 0x68, 0x41, 0x39, 0x6f, 0x71, 0x53, 0x56, 0x51, 0x7a, 0x43, 0x37, 0x54, 0x73, 0x53, +0x49, 0x46, 0x4b, 0x62, 0x66, 0x36, 0x4b, 0x34, 0x39, 0x6d, 0x4b, 0x76, 0x51, 0x2b, 0x42, 0x6b, +0x6f, 0x72, 0x2f, 0x52, 0x52, 0x57, 0x76, 0x48, 0x69, 0x35, 0x79, 0x2f, 0x53, 0x6c, 0x6d, 0x77, +0x4c, 0x4a, 0x62, 0x61, 0x62, 0x4f, 0x70, 0x70, 0x34, 0x34, 0x71, 0x4d, 0x6e, 0x47, 0x44, 0x31, +0x77, 0x64, 0x4e, 0x71, 0x5a, 0x4a, 0x78, 0x67, 0x42, 0x79, 0x4f, 0x35, 0x51, 0x35, 0x68, 0x2b, +0x59, 0x41, 0x6d, 0x53, 0x69, 0x77, 0x4a, 0x6b, 0x56, 0x4e, 0x67, 0x75, 0x46, 0x39, 0x66, 0x6a, +0x4a, 0x6b, 0x50, 0x6d, 0x6f, 0x51, 0x51, 0x58, 0x64, 0x4e, 0x69, 0x68, 0x42, 0x2f, 0x48, 0x57, +0x50, 0x7a, 0x32, 0x2f, 0x2f, 0x39, 0x46, 0x78, 0x6d, 0x2b, 0x2f, 0x2f, 0x63, 0x4c, 0x52, 0x30, +0x48, 0x44, 0x46, 0x63, 0x2b, 0x55, 0x38, 0x2b, 0x39, 0x5a, 0x31, 0x54, 0x2f, 0x34, 0x50, 0x4f, +0x52, 0x53, 0x49, 0x51, 0x62, 0x66, 0x33, 0x34, 0x77, 0x68, 0x2b, 0x7a, 0x2f, 0x68, 0x5a, 0x56, +0x37, 0x75, 0x50, 0x74, 0x75, 0x5a, 0x76, 0x70, 0x7a, 0x32, 0x65, 0x6e, 0x78, 0x4e, 0x72, 0x62, +0x56, 0x33, 0x66, 0x50, 0x44, 0x50, 0x62, 0x38, 0x37, 0x68, 0x68, 0x32, 0x2f, 0x46, 0x31, 0x4d, +0x65, 0x71, 0x47, 0x62, 0x39, 0x70, 0x67, 0x4c, 0x32, 0x48, 0x7a, 0x65, 0x49, 0x32, 0x51, 0x76, +0x58, 0x30, 0x64, 0x71, 0x52, 0x63, 0x67, 0x43, 0x52, 0x74, 0x48, 0x73, 0x37, 0x43, 0x44, 0x76, +0x73, 0x6c, 0x31, 0x4b, 0x47, 0x67, 0x4e, 0x48, 0x51, 0x36, 0x6c, 0x35, 0x38, 0x39, 0x67, 0x53, +0x30, 0x66, 0x66, 0x38, 0x51, 0x65, 0x6b, 0x67, 0x42, 0x46, 0x38, 0x69, 0x5a, 0x4b, 0x4b, 0x58, +0x67, 0x6a, 0x46, 0x4b, 0x75, 0x30, 0x74, 0x65, 0x36, 0x68, 0x6b, 0x4a, 0x7a, 0x69, 0x33, 0x37, +0x63, 0x72, 0x70, 0x75, 0x48, 0x6c, 0x64, 0x39, 0x4f, 0x38, 0x2b, 0x77, 0x4f, 0x78, 0x49, 0x72, +0x6e, 0x56, 0x38, 0x57, 0x34, 0x4c, 0x46, 0x71, 0x42, 0x4c, 0x49, 0x4d, 0x76, 0x5a, 0x61, 0x6c, +0x46, 0x6d, 0x63, 0x73, 0x6c, 0x79, 0x78, 0x73, 0x46, 0x43, 0x2b, 0x73, 0x56, 0x76, 0x6a, 0x43, +0x63, 0x76, 0x33, 0x61, 0x73, 0x74, 0x54, 0x30, 0x49, 0x69, 0x53, 0x38, 0x55, 0x30, 0x78, 0x49, +0x44, 0x47, 0x46, 0x35, 0x6f, 0x70, 0x79, 0x43, 0x53, 0x4e, 0x41, 0x71, 0x73, 0x6e, 0x51, 0x35, +0x6b, 0x78, 0x4e, 0x6c, 0x4c, 0x38, 0x41, 0x57, 0x65, 0x37, 0x2b, 0x4f, 0x4a, 0x39, 0x4e, 0x55, +0x45, 0x66, 0x77, 0x74, 0x42, 0x42, 0x4e, 0x69, 0x77, 0x55, 0x6c, 0x50, 0x66, 0x62, 0x4b, 0x68, +0x72, 0x64, 0x76, 0x61, 0x65, 0x44, 0x45, 0x31, 0x47, 0x49, 0x54, 0x33, 0x69, 0x31, 0x31, 0x33, +0x62, 0x59, 0x2f, 0x72, 0x4c, 0x45, 0x30, 0x2b, 0x45, 0x33, 0x58, 0x66, 0x76, 0x69, 0x69, 0x4c, +0x76, 0x51, 0x41, 0x50, 0x67, 0x5a, 0x55, 0x34, 0x68, 0x63, 0x73, 0x70, 0x50, 0x4b, 0x6e, 0x49, +0x4b, 0x62, 0x79, 0x38, 0x64, 0x68, 0x54, 0x2f, 0x6f, 0x65, 0x31, 0x53, 0x4c, 0x5a, 0x50, 0x46, +0x33, 0x46, 0x33, 0x4c, 0x69, 0x6f, 0x57, 0x4f, 0x4a, 0x64, 0x31, 0x64, 0x2f, 0x41, 0x4e, 0x2f, +0x33, 0x57, 0x62, 0x35, 0x38, 0x4f, 0x63, 0x6c, 0x6b, 0x45, 0x69, 0x45, 0x46, 0x73, 0x32, 0x66, +0x50, 0x78, 0x75, 0x2f, 0x6f, 0x59, 0x4c, 0x48, 0x76, 0x63, 0x35, 0x48, 0x76, 0x38, 0x31, 0x73, +0x68, 0x4f, 0x4e, 0x58, 0x33, 0x69, 0x55, 0x34, 0x54, 0x6d, 0x4e, 0x2f, 0x34, 0x6d, 0x4d, 0x55, +0x43, 0x62, 0x34, 0x69, 0x62, 0x41, 0x6b, 0x54, 0x33, 0x46, 0x62, 0x77, 0x33, 0x51, 0x44, 0x4e, +0x77, 0x74, 0x63, 0x65, 0x58, 0x6e, 0x30, 0x6e, 0x65, 0x66, 0x38, 0x38, 0x36, 0x48, 0x71, 0x52, +0x53, 0x50, 0x72, 0x2f, 0x37, 0x6e, 0x65, 0x43, 0x57, 0x78, 0x6a, 0x4a, 0x65, 0x4f, 0x39, 0x48, +0x32, 0x75, 0x72, 0x34, 0x4d, 0x48, 0x43, 0x59, 0x6b, 0x49, 0x2f, 0x6f, 0x6f, 0x76, 0x70, 0x30, +0x44, 0x73, 0x37, 0x63, 0x74, 0x59, 0x6b, 0x52, 0x30, 0x42, 0x4c, 0x37, 0x79, 0x62, 0x63, 0x62, +0x69, 0x33, 0x42, 0x61, 0x48, 0x6a, 0x45, 0x59, 0x50, 0x48, 0x75, 0x30, 0x6b, 0x71, 0x53, 0x57, +0x36, 0x62, 0x61, 0x33, 0x74, 0x78, 0x59, 0x33, 0x74, 0x4e, 0x66, 0x4e, 0x6a, 0x2b, 0x63, 0x78, +0x74, 0x6e, 0x32, 0x74, 0x42, 0x44, 0x47, 0x57, 0x39, 0x39, 0x49, 0x49, 0x70, 0x67, 0x43, 0x39, +0x38, 0x31, 0x6d, 0x39, 0x62, 0x54, 0x32, 0x74, 0x37, 0x4b, 0x30, 0x49, 0x4b, 0x56, 0x6a, 0x61, +0x73, 0x5a, 0x4e, 0x65, 0x61, 0x58, 0x61, 0x33, 0x4f, 0x6d, 0x72, 0x61, 0x39, 0x76, 0x31, 0x4c, +0x70, 0x45, 0x55, 0x41, 0x75, 0x79, 0x6d, 0x79, 0x30, 0x77, 0x65, 0x51, 0x59, 0x41, 0x62, 0x57, +0x78, 0x55, 0x34, 0x42, 0x41, 0x70, 0x79, 0x31, 0x41, 0x49, 0x53, 0x63, 0x38, 0x6f, 0x62, 0x6c, +0x69, 0x50, 0x34, 0x2f, 0x47, 0x44, 0x70, 0x4e, 0x68, 0x41, 0x44, 0x52, 0x49, 0x66, 0x51, 0x36, +0x65, 0x61, 0x45, 0x59, 0x5a, 0x54, 0x55, 0x4b, 0x58, 0x68, 0x39, 0x74, 0x7a, 0x53, 0x32, 0x4e, +0x46, 0x55, 0x66, 0x75, 0x56, 0x47, 0x4f, 0x35, 0x38, 0x56, 0x73, 0x4b, 0x63, 0x5a, 0x37, 0x6a, +0x6d, 0x68, 0x6b, 0x4f, 0x6f, 0x62, 0x65, 0x77, 0x49, 0x65, 0x32, 0x6f, 0x2f, 0x79, 0x34, 0x43, +0x57, 0x76, 0x53, 0x32, 0x61, 0x33, 0x58, 0x4a, 0x63, 0x4d, 0x62, 0x52, 0x66, 0x43, 0x52, 0x2f, +0x39, 0x36, 0x54, 0x47, 0x2b, 0x35, 0x79, 0x31, 0x36, 0x58, 0x33, 0x6f, 0x52, 0x63, 0x76, 0x55, +0x61, 0x4b, 0x74, 0x36, 0x59, 0x67, 0x58, 0x42, 0x54, 0x67, 0x4b, 0x30, 0x48, 0x48, 0x78, 0x68, +0x36, 0x76, 0x53, 0x48, 0x38, 0x39, 0x46, 0x42, 0x57, 0x57, 0x4f, 0x4e, 0x69, 0x62, 0x4d, 0x52, +0x77, 0x46, 0x6e, 0x38, 0x39, 0x46, 0x39, 0x6e, 0x2f, 0x5a, 0x43, 0x70, 0x76, 0x75, 0x49, 0x48, +0x53, 0x55, 0x30, 0x34, 0x42, 0x59, 0x35, 0x6a, 0x37, 0x31, 0x53, 0x57, 0x55, 0x39, 0x7a, 0x76, +0x44, 0x74, 0x47, 0x78, 0x2b, 0x62, 0x73, 0x63, 0x61, 0x41, 0x65, 0x64, 0x37, 0x4d, 0x58, 0x48, +0x33, 0x34, 0x56, 0x78, 0x77, 0x2f, 0x4c, 0x34, 0x63, 0x65, 0x2b, 0x43, 0x75, 0x58, 0x48, 0x44, +0x76, 0x61, 0x79, 0x53, 0x53, 0x30, 0x68, 0x6f, 0x2b, 0x68, 0x55, 0x35, 0x6a, 0x78, 0x61, 0x46, +0x4e, 0x51, 0x4f, 0x4f, 0x48, 0x6f, 0x79, 0x63, 0x54, 0x39, 0x75, 0x36, 0x59, 0x59, 0x41, 0x4f, +0x53, 0x74, 0x4c, 0x48, 0x50, 0x44, 0x76, 0x63, 0x7a, 0x35, 0x76, 0x35, 0x61, 0x4f, 0x63, 0x51, +0x56, 0x68, 0x4c, 0x42, 0x44, 0x53, 0x53, 0x47, 0x63, 0x7a, 0x53, 0x45, 0x6b, 0x47, 0x54, 0x57, +0x2b, 0x63, 0x47, 0x47, 0x48, 0x5a, 0x4b, 0x4f, 0x4e, 0x77, 0x32, 0x6b, 0x6c, 0x61, 0x35, 0x69, +0x32, 0x5a, 0x53, 0x44, 0x4b, 0x2b, 0x57, 0x4a, 0x59, 0x6b, 0x4d, 0x69, 0x52, 0x64, 0x39, 0x4b, +0x69, 0x35, 0x47, 0x64, 0x66, 0x6d, 0x56, 0x62, 0x67, 0x44, 0x59, 0x55, 0x35, 0x4d, 0x36, 0x54, +0x5a, 0x70, 0x5a, 0x4b, 0x4d, 0x4b, 0x4a, 0x4e, 0x38, 0x65, 0x78, 0x66, 0x67, 0x61, 0x36, 0x51, +0x6d, 0x57, 0x34, 0x68, 0x56, 0x47, 0x5a, 0x4b, 0x2b, 0x51, 0x5a, 0x4d, 0x74, 0x34, 0x4f, 0x45, +0x2f, 0x39, 0x68, 0x67, 0x6d, 0x6b, 0x53, 0x42, 0x2b, 0x32, 0x57, 0x58, 0x68, 0x69, 0x46, 0x54, +0x54, 0x6a, 0x53, 0x72, 0x79, 0x39, 0x68, 0x71, 0x41, 0x48, 0x4a, 0x51, 0x36, 0x73, 0x31, 0x49, +0x48, 0x6a, 0x55, 0x46, 0x70, 0x4c, 0x4a, 0x38, 0x4a, 0x65, 0x2b, 0x7a, 0x4f, 0x4a, 0x2f, 0x46, +0x79, 0x6c, 0x4e, 0x59, 0x63, 0x4d, 0x47, 0x59, 0x49, 0x35, 0x66, 0x47, 0x43, 0x4c, 0x74, 0x38, +0x4c, 0x52, 0x73, 0x47, 0x64, 0x6e, 0x5a, 0x32, 0x38, 0x2f, 0x76, 0x72, 0x72, 0x34, 0x64, 0x2b, +0x6a, 0x52, 0x34, 0x39, 0x6d, 0x35, 0x73, 0x79, 0x5a, 0x43, 0x43, 0x48, 0x6f, 0x45, 0x49, 0x4c, +0x37, 0x66, 0x4a, 0x38, 0x50, 0x68, 0x65, 0x42, 0x61, 0x33, 0x32, 0x66, 0x55, 0x45, 0x39, 0x6e, +0x68, 0x78, 0x2f, 0x44, 0x68, 0x39, 0x51, 0x58, 0x46, 0x48, 0x44, 0x59, 0x73, 0x79, 0x73, 0x65, +0x66, 0x43, 0x6a, 0x6f, 0x36, 0x4c, 0x66, 0x37, 0x37, 0x36, 0x57, 0x65, 0x43, 0x54, 0x66, 0x31, +0x36, 0x38, 0x65, 0x71, 0x69, 0x59, 0x6c, 0x64, 0x42, 0x5a, 0x63, 0x59, 0x77, 0x57, 0x7a, 0x6c, +0x76, 0x4f, 0x44, 0x6a, 0x77, 0x77, 0x51, 0x4d, 0x35, 0x37, 0x37, 0x6a, 0x7a, 0x57, 0x4e, 0x32, +0x79, 0x4f, 0x6f, 0x31, 0x69, 0x5a, 0x73, 0x79, 0x31, 0x66, 0x63, 0x64, 0x6b, 0x2b, 0x38, 0x71, +0x68, 0x72, 0x49, 0x34, 0x57, 0x47, 0x31, 0x6b, 0x78, 0x6b, 0x75, 0x39, 0x75, 0x2f, 0x51, 0x37, +0x79, 0x43, 0x48, 0x74, 0x36, 0x49, 0x51, 0x58, 0x61, 0x61, 0x49, 0x36, 0x62, 0x63, 0x42, 0x78, +0x37, 0x6a, 0x74, 0x69, 0x54, 0x2b, 0x39, 0x2b, 0x2b, 0x48, 0x32, 0x30, 0x30, 0x46, 0x30, 0x32, +0x36, 0x69, 0x44, 0x36, 0x6c, 0x66, 0x56, 0x69, 0x2b, 0x61, 0x54, 0x6c, 0x43, 0x2b, 0x6f, 0x34, +0x32, 0x36, 0x77, 0x59, 0x46, 0x44, 0x6c, 0x48, 0x6d, 0x6e, 0x6b, 0x63, 0x41, 0x30, 0x67, 0x6a, +0x72, 0x2b, 0x75, 0x6c, 0x51, 0x79, 0x4f, 0x2f, 0x2b, 0x72, 0x66, 0x6c, 0x36, 0x51, 0x4a, 0x51, +0x31, 0x32, 0x36, 0x77, 0x71, 0x72, 0x36, 0x38, 0x43, 0x61, 0x7a, 0x38, 0x49, 0x58, 0x65, 0x37, +0x6b, 0x70, 0x67, 0x32, 0x2b, 0x54, 0x68, 0x63, 0x4f, 0x71, 0x57, 0x42, 0x6b, 0x46, 0x66, 0x41, +0x79, 0x6b, 0x4e, 0x39, 0x4b, 0x55, 0x34, 0x64, 0x50, 0x59, 0x30, 0x73, 0x79, 0x58, 0x43, 0x58, +0x78, 0x77, 0x77, 0x71, 0x6a, 0x37, 0x4a, 0x5a, 0x6f, 0x47, 0x56, 0x66, 0x70, 0x74, 0x73, 0x73, +0x75, 0x4b, 0x59, 0x77, 0x44, 0x32, 0x2b, 0x77, 0x49, 0x49, 0x6c, 0x67, 0x70, 0x4d, 0x48, 0x5a, +0x34, 0x62, 0x34, 0x78, 0x42, 0x70, 0x34, 0x4c, 0x4b, 0x48, 0x67, 0x78, 0x66, 0x30, 0x77, 0x72, +0x4c, 0x32, 0x6c, 0x72, 0x74, 0x37, 0x4d, 0x71, 0x34, 0x32, 0x6f, 0x78, 0x71, 0x37, 0x6d, 0x2f, +0x58, 0x37, 0x59, 0x30, 0x68, 0x58, 0x6c, 0x6e, 0x4a, 0x50, 0x78, 0x71, 0x65, 0x70, 0x36, 0x52, +0x58, 0x67, 0x32, 0x6c, 0x76, 0x65, 0x6e, 0x38, 0x48, 0x47, 0x67, 0x45, 0x66, 0x4b, 0x52, 0x58, +0x7a, 0x6c, 0x6d, 0x39, 0x67, 0x38, 0x39, 0x59, 0x32, 0x56, 0x74, 0x55, 0x31, 0x6b, 0x45, 0x79, +0x6d, 0x33, 0x4a, 0x5a, 0x75, 0x79, 0x73, 0x56, 0x5a, 0x4f, 0x6d, 0x63, 0x70, 0x6d, 0x2b, 0x2f, +0x4b, 0x72, 0x65, 0x47, 0x44, 0x48, 0x58, 0x31, 0x68, 0x38, 0x6a, 0x49, 0x71, 0x64, 0x6c, 0x44, +0x35, 0x30, 0x2b, 0x76, 0x39, 0x55, 0x67, 0x70, 0x48, 0x77, 0x47, 0x6b, 0x6e, 0x4d, 0x47, 0x71, +0x73, 0x34, 0x63, 0x78, 0x59, 0x47, 0x6c, 0x46, 0x4b, 0x68, 0x58, 0x41, 0x36, 0x41, 0x55, 0x45, +0x76, 0x37, 0x77, 0x76, 0x37, 0x57, 0x59, 0x41, 0x79, 0x2b, 0x31, 0x4c, 0x79, 0x59, 0x4c, 0x2f, +0x76, 0x36, 0x4b, 0x55, 0x37, 0x53, 0x4a, 0x57, 0x6d, 0x2b, 0x46, 0x6a, 0x74, 0x51, 0x54, 0x43, +0x45, 0x43, 0x31, 0x78, 0x74, 0x41, 0x36, 0x74, 0x35, 0x57, 0x50, 0x36, 0x79, 0x4a, 0x4c, 0x6b, +0x7a, 0x79, 0x6c, 0x39, 0x51, 0x66, 0x68, 0x30, 0x50, 0x45, 0x76, 0x62, 0x34, 0x47, 0x59, 0x32, +0x41, 0x4d, 0x6a, 0x71, 0x30, 0x78, 0x78, 0x68, 0x6a, 0x55, 0x45, 0x75, 0x58, 0x49, 0x6a, 0x37, +0x36, 0x43, 0x4c, 0x4e, 0x35, 0x45, 0x35, 0x46, 0x4a, 0x6b, 0x34, 0x6a, 0x75, 0x73, 0x6f, 0x76, +0x54, 0x4b, 0x61, 0x53, 0x72, 0x4b, 0x76, 0x4c, 0x32, 0x47, 0x6f, 0x41, 0x63, 0x6c, 0x48, 0x70, +0x4e, 0x2f, 0x2f, 0x36, 0x59, 0x38, 0x38, 0x34, 0x6a, 0x74, 0x58, 0x70, 0x31, 0x32, 0x6d, 0x48, +0x49, 0x39, 0x79, 0x6e, 0x30, 0x66, 0x59, 0x37, 0x49, 0x73, 0x44, 0x6d, 0x73, 0x43, 0x65, 0x36, +0x64, 0x71, 0x6e, 0x50, 0x2b, 0x79, 0x4a, 0x48, 0x4d, 0x2f, 0x75, 0x34, 0x37, 0x57, 0x77, 0x57, +0x63, 0x77, 0x74, 0x45, 0x6c, 0x6c, 0x31, 0x7a, 0x43, 0x79, 0x70, 0x55, 0x72, 0x65, 0x65, 0x79, +0x78, 0x78, 0x30, 0x4b, 0x76, 0x77, 0x65, 0x44, 0x36, 0x6d, 0x52, 0x43, 0x63, 0x35, 0x50, 0x74, +0x63, 0x4c, 0x51, 0x57, 0x6e, 0x53, 0x69, 0x66, 0x4d, 0x53, 0x34, 0x41, 0x43, 0x4b, 0x38, 0x6b, +0x37, 0x79, 0x38, 0x63, 0x69, 0x39, 0x78, 0x53, 0x55, 0x74, 0x48, 0x55, 0x69, 0x68, 0x53, 0x52, +0x52, 0x48, 0x4f, 0x48, 0x62, 0x7a, 0x59, 0x6f, 0x68, 0x6c, 0x64, 0x4c, 0x36, 0x76, 0x32, 0x74, +0x62, 0x45, 0x4a, 0x52, 0x57, 0x34, 0x51, 0x6c, 0x41, 0x42, 0x49, 0x51, 0x6e, 0x71, 0x53, 0x37, +0x37, 0x6b, 0x53, 0x69, 0x6d, 0x56, 0x6c, 0x42, 0x41, 0x47, 0x75, 0x55, 0x73, 0x72, 0x30, 0x5a, +0x49, 0x51, 0x56, 0x34, 0x38, 0x6e, 0x35, 0x4b, 0x43, 0x45, 0x73, 0x59, 0x55, 0x6a, 0x6d, 0x46, +0x6b, 0x76, 0x35, 0x45, 0x49, 0x4a, 0x64, 0x68, 0x6a, 0x79, 0x42, 0x34, 0x49, 0x4a, 0x56, 0x6a, +0x66, 0x74, 0x4a, 0x34, 0x52, 0x66, 0x55, 0x61, 0x47, 0x78, 0x69, 0x6d, 0x67, 0x4b, 0x77, 0x6f, +0x73, 0x56, 0x62, 0x63, 0x6f, 0x5a, 0x7a, 0x51, 0x53, 0x5a, 0x58, 0x6a, 0x35, 0x63, 0x42, 0x74, +0x32, 0x4a, 0x67, 0x6f, 0x73, 0x4e, 0x59, 0x49, 0x49, 0x2f, 0x63, 0x74, 0x78, 0x46, 0x52, 0x7a, +0x58, 0x49, 0x39, 0x69, 0x74, 0x7a, 0x4f, 0x78, 0x79, 0x6f, 0x44, 0x56, 0x79, 0x43, 0x77, 0x4e, +0x53, 0x65, 0x57, 0x68, 0x6a, 0x6e, 0x41, 0x75, 0x41, 0x42, 0x59, 0x4b, 0x45, 0x30, 0x6c, 0x52, +0x58, 0x46, 0x59, 0x59, 0x39, 0x76, 0x4a, 0x32, 0x76, 0x61, 0x79, 0x66, 0x68, 0x48, 0x46, 0x79, +0x56, 0x34, 0x77, 0x72, 0x73, 0x32, 0x72, 0x70, 0x53, 0x7a, 0x68, 0x4b, 0x4e, 0x5a, 0x65, 0x45, +0x6a, 0x31, 0x58, 0x62, 0x59, 0x33, 0x36, 0x66, 0x4d, 0x36, 0x74, 0x4e, 0x46, 0x42, 0x77, 0x34, +0x69, 0x6f, 0x6b, 0x51, 0x34, 0x70, 0x39, 0x58, 0x43, 0x37, 0x6a, 0x49, 0x62, 0x4b, 0x74, 0x71, +0x36, 0x44, 0x4a, 0x51, 0x71, 0x79, 0x64, 0x70, 0x48, 0x48, 0x6b, 0x45, 0x31, 0x4e, 0x47, 0x43, +0x45, 0x59, 0x4d, 0x31, 0x72, 0x72, 0x31, 0x45, 0x47, 0x50, 0x4e, 0x50, 0x38, 0x41, 0x59, 0x56, +0x6c, 0x42, 0x35, 0x70, 0x45, 0x36, 0x2b, 0x77, 0x66, 0x61, 0x41, 0x52, 0x73, 0x77, 0x32, 0x55, +0x38, 0x65, 0x50, 0x69, 0x56, 0x32, 0x54, 0x53, 0x31, 0x4a, 0x65, 0x68, 0x66, 0x56, 0x55, 0x71, +0x77, 0x4d, 0x57, 0x57, 0x36, 0x34, 0x67, 0x64, 0x65, 0x6b, 0x33, 0x59, 0x45, 0x70, 0x77, 0x49, +0x57, 0x48, 0x39, 0x42, 0x61, 0x75, 0x57, 0x55, 0x39, 0x43, 0x64, 0x45, 0x49, 0x6e, 0x67, 0x64, +0x61, 0x47, 0x61, 0x49, 0x65, 0x4b, 0x47, 0x6d, 0x49, 0x78, 0x47, 0x4e, 0x6f, 0x72, 0x58, 0x41, +0x4c, 0x52, 0x4d, 0x37, 0x61, 0x37, 0x59, 0x41, 0x41, 0x4f, 0x68, 0x48, 0x53, 0x55, 0x4e, 0x32, +0x76, 0x4a, 0x4e, 0x78, 0x42, 0x53, 0x6d, 0x61, 0x73, 0x50, 0x45, 0x69, 0x52, 0x35, 0x67, 0x2b, +0x6d, 0x78, 0x51, 0x2f, 0x6d, 0x6d, 0x50, 0x77, 0x36, 0x50, 0x74, 0x62, 0x39, 0x58, 0x50, 0x71, +0x70, 0x45, 0x43, 0x57, 0x4f, 0x4f, 0x31, 0x56, 0x69, 0x4c, 0x52, 0x55, 0x44, 0x69, 0x39, 0x4a, +0x2b, 0x49, 0x57, 0x48, 0x35, 0x30, 0x78, 0x6e, 0x6c, 0x54, 0x79, 0x73, 0x55, 0x4b, 0x67, 0x53, +0x39, 0x6c, 0x44, 0x62, 0x30, 0x4c, 0x55, 0x6e, 0x6e, 0x74, 0x52, 0x30, 0x42, 0x65, 0x6b, 0x6a, +0x6c, 0x68, 0x57, 0x55, 0x6f, 0x4f, 0x6d, 0x59, 0x4d, 0x68, 0x66, 0x66, 0x64, 0x5a, 0x77, 0x47, +0x66, 0x49, 0x55, 0x50, 0x53, 0x37, 0x77, 0x35, 0x64, 0x56, 0x5a, 0x48, 0x64, 0x30, 0x55, 0x58, +0x56, 0x65, 0x48, 0x68, 0x58, 0x6c, 0x46, 0x31, 0x6a, 0x56, 0x61, 0x55, 0x6a, 0x31, 0x64, 0x56, +0x4f, 0x50, 0x64, 0x71, 0x69, 0x30, 0x4a, 0x34, 0x7a, 0x4e, 0x49, 0x59, 0x36, 0x41, 0x68, 0x6b, +0x6f, 0x74, 0x46, 0x46, 0x75, 0x75, 0x64, 0x76, 0x39, 0x72, 0x42, 0x43, 0x53, 0x36, 0x75, 0x70, +0x71, 0x31, 0x71, 0x35, 0x64, 0x79, 0x39, 0x4b, 0x6c, 0x53, 0x78, 0x6b, 0x34, 0x63, 0x4b, 0x44, +0x56, 0x45, 0x52, 0x41, 0x69, 0x62, 0x42, 0x77, 0x43, 0x30, 0x64, 0x56, 0x70, 0x53, 0x72, 0x46, +0x49, 0x4b, 0x53, 0x35, 0x56, 0x69, 0x6a, 0x6a, 0x67, 0x4d, 0x63, 0x4b, 0x4a, 0x67, 0x67, 0x5a, +0x77, 0x56, 0x30, 0x44, 0x59, 0x37, 0x65, 0x68, 0x78, 0x46, 0x5a, 0x5a, 0x38, 0x64, 0x61, 0x33, +0x70, 0x44, 0x71, 0x4f, 0x59, 0x50, 0x68, 0x59, 0x67, 0x72, 0x73, 0x76, 0x34, 0x58, 0x68, 0x4b, +0x75, 0x66, 0x65, 0x46, 0x61, 0x7a, 0x68, 0x68, 0x2f, 0x47, 0x6e, 0x6d, 0x78, 0x41, 0x72, 0x61, +0x31, 0x62, 0x79, 0x50, 0x70, 0x4a, 0x2b, 0x6c, 0x64, 0x30, 0x70, 0x76, 0x32, 0x5a, 0x44, 0x73, +0x50, 0x66, 0x2f, 0x49, 0x77, 0x7a, 0x31, 0x2f, 0x32, 0x66, 0x4e, 0x66, 0x77, 0x63, 0x31, 0x44, +0x6d, 0x4c, 0x32, 0x37, 0x2b, 0x67, 0x73, 0x71, 0x38, 0x79, 0x6e, 0x43, 0x4f, 0x4a, 0x4b, 0x57, +0x6b, 0x6f, 0x62, 0x32, 0x42, 0x77, 0x79, 0x38, 0x34, 0x50, 0x47, 0x31, 0x32, 0x44, 0x56, 0x44, +0x67, 0x6d, 0x67, 0x35, 0x6f, 0x7a, 0x36, 0x44, 0x37, 0x70, 0x48, 0x61, 0x77, 0x6d, 0x65, 0x35, +0x36, 0x42, 0x6c, 0x53, 0x67, 0x63, 0x44, 0x38, 0x53, 0x42, 0x38, 0x52, 0x54, 0x4f, 0x2f, 0x6a, +0x53, 0x75, 0x52, 0x79, 0x6d, 0x4e, 0x51, 0x45, 0x74, 0x35, 0x74, 0x50, 0x77, 0x72, 0x36, 0x46, +0x4e, 0x54, 0x66, 0x54, 0x61, 0x37, 0x55, 0x75, 0x32, 0x7a, 0x74, 0x2b, 0x48, 0x4a, 0x56, 0x56, +0x56, 0x58, 0x61, 0x69, 0x7a, 0x54, 0x42, 0x6f, 0x73, 0x4f, 0x48, 0x37, 0x64, 0x36, 0x79, 0x68, +0x4d, 0x73, 0x50, 0x4f, 0x77, 0x30, 0x57, 0x48, 0x46, 0x53, 0x6c, 0x63, 0x30, 0x51, 0x36, 0x72, +0x7a, 0x71, 0x78, 0x34, 0x62, 0x41, 0x63, 0x38, 0x37, 0x77, 0x48, 0x53, 0x50, 0x44, 0x69, 0x64, +0x7a, 0x2f, 0x75, 0x35, 0x65, 0x31, 0x4c, 0x46, 0x70, 0x79, 0x55, 0x6c, 0x45, 0x38, 0x37, 0x78, +0x51, 0x73, 0x56, 0x6b, 0x5a, 0x6c, 0x56, 0x5a, 0x31, 0x64, 0x74, 0x4f, 0x43, 0x59, 0x4f, 0x68, +0x76, 0x56, 0x78, 0x44, 0x43, 0x56, 0x67, 0x43, 0x4d, 0x59, 0x64, 0x69, 0x68, 0x51, 0x37, 0x45, +0x30, 0x57, 0x57, 0x35, 0x34, 0x50, 0x65, 0x48, 0x4e, 0x6d, 0x64, 0x42, 0x77, 0x45, 0x61, 0x2f, +0x53, 0x6b, 0x66, 0x57, 0x4a, 0x42, 0x4d, 0x34, 0x36, 0x4f, 0x65, 0x4f, 0x72, 0x6e, 0x52, 0x6b, +0x4a, 0x6d, 0x4a, 0x73, 0x46, 0x41, 0x50, 0x32, 0x33, 0x32, 0x72, 0x77, 0x4e, 0x43, 0x4e, 0x63, +0x67, 0x72, 0x35, 0x50, 0x32, 0x75, 0x6e, 0x53, 0x57, 0x6e, 0x36, 0x31, 0x57, 0x72, 0x4f, 0x30, +0x49, 0x4c, 0x6a, 0x6a, 0x47, 0x37, 0x72, 0x31, 0x33, 0x56, 0x30, 0x78, 0x36, 0x33, 0x72, 0x77, +0x30, 0x2f, 0x5a, 0x65, 0x4a, 0x57, 0x55, 0x2b, 0x63, 0x32, 0x41, 0x57, 0x6c, 0x62, 0x69, 0x41, +0x62, 0x7a, 0x70, 0x59, 0x35, 0x39, 0x39, 0x32, 0x56, 0x67, 0x5a, 0x44, 0x69, 0x41, 0x38, 0x37, +0x71, 0x4b, 0x57, 0x4e, 0x33, 0x34, 0x4c, 0x67, 0x4d, 0x38, 0x46, 0x35, 0x39, 0x39, 0x57, 0x2f, +0x6d, 0x78, 0x42, 0x4d, 0x37, 0x53, 0x55, 0x4f, 0x70, 0x6d, 0x55, 0x46, 0x6c, 0x31, 0x74, 0x62, +0x63, 0x77, 0x6d, 0x33, 0x76, 0x57, 0x31, 0x4c, 0x70, 0x44, 0x54, 0x50, 0x61, 0x2f, 0x58, 0x59, +0x47, 0x2f, 0x48, 0x57, 0x41, 0x2f, 0x61, 0x6b, 0x64, 0x2b, 0x59, 0x6b, 0x59, 0x6d, 0x4c, 0x39, +0x6d, 0x62, 0x7a, 0x6d, 0x6c, 0x4d, 0x2f, 0x39, 0x78, 0x63, 0x36, 0x7a, 0x74, 0x6f, 0x5a, 0x7a, +0x37, 0x33, 0x54, 0x36, 0x4d, 0x62, 0x77, 0x5a, 0x66, 0x69, 0x69, 0x38, 0x31, 0x59, 0x78, 0x63, +0x38, 0x52, 0x2b, 0x4f, 0x62, 0x4e, 0x35, 0x4d, 0x47, 0x75, 0x39, 0x74, 0x64, 0x4d, 0x6d, 0x30, +0x68, 0x4b, 0x44, 0x42, 0x70, 0x62, 0x74, 0x6c, 0x47, 0x37, 0x4a, 0x79, 0x7a, 0x66, 0x73, 0x2b, +0x6a, 0x2b, 0x38, 0x33, 0x6c, 0x67, 0x6d, 0x56, 0x48, 0x4d, 0x6a, 0x43, 0x35, 0x6c, 0x6a, 0x2f, +0x49, 0x36, 0x52, 0x79, 0x58, 0x76, 0x4a, 0x4a, 0x4a, 0x7a, 0x47, 0x64, 0x53, 0x33, 0x6b, 0x70, +0x4f, 0x57, 0x58, 0x49, 0x6f, 0x47, 0x37, 0x35, 0x34, 0x41, 0x31, 0x75, 0x53, 0x75, 0x6e, 0x75, +0x4a, 0x4f, 0x33, 0x6d, 0x65, 0x38, 0x59, 0x77, 0x6a, 0x6b, 0x65, 0x56, 0x36, 0x6b, 0x4a, 0x74, +0x70, 0x6d, 0x5a, 0x55, 0x33, 0x4f, 0x43, 0x4d, 0x75, 0x68, 0x75, 0x66, 0x2b, 0x69, 0x45, 0x7a, +0x72, 0x63, 0x70, 0x78, 0x4b, 0x4e, 0x6b, 0x2f, 0x73, 0x53, 0x6f, 0x5a, 0x36, 0x4d, 0x2f, 0x33, +0x6e, 0x39, 0x73, 0x36, 0x71, 0x52, 0x30, 0x79, 0x67, 0x54, 0x4a, 0x62, 0x2b, 0x67, 0x61, 0x77, +0x53, 0x71, 0x62, 0x50, 0x50, 0x54, 0x4c, 0x6e, 0x79, 0x47, 0x4a, 0x69, 0x6e, 0x2f, 0x7a, 0x63, +0x55, 0x75, 0x71, 0x53, 0x6a, 0x49, 0x2b, 0x73, 0x5a, 0x6a, 0x65, 0x62, 0x73, 0x2f, 0x70, 0x58, +0x4d, 0x62, 0x52, 0x4e, 0x68, 0x53, 0x6d, 0x66, 0x32, 0x54, 0x37, 0x6c, 0x39, 0x30, 0x35, 0x53, +0x2f, 0x4c, 0x4d, 0x77, 0x4f, 0x54, 0x32, 0x70, 0x2b, 0x66, 0x31, 0x77, 0x5a, 0x53, 0x69, 0x6c, +0x53, 0x71, 0x56, 0x53, 0x34, 0x52, 0x4f, 0x5a, 0x35, 0x48, 0x73, 0x4d, 0x6e, 0x37, 0x59, 0x46, +0x75, 0x42, 0x35, 0x6c, 0x4b, 0x46, 0x38, 0x73, 0x42, 0x75, 0x33, 0x77, 0x42, 0x72, 0x55, 0x48, +0x75, 0x52, 0x49, 0x41, 0x59, 0x54, 0x62, 0x50, 0x32, 0x70, 0x63, 0x43, 0x35, 0x62, 0x41, 0x51, +0x63, 0x66, 0x69, 0x77, 0x4a, 0x65, 0x70, 0x65, 0x75, 0x38, 0x55, 0x39, 0x6b, 0x33, 0x43, 0x75, +0x36, 0x2f, 0x6e, 0x2f, 0x77, 0x47, 0x54, 0x33, 0x38, 0x2f, 0x2f, 0x69, 0x4f, 0x33, 0x49, 0x5a, +0x56, 0x68, 0x2b, 0x34, 0x79, 0x4e, 0x6d, 0x7a, 0x74, 0x50, 0x75, 0x74, 0x36, 0x53, 0x67, 0x33, +0x6a, 0x6e, 0x71, 0x73, 0x49, 0x71, 0x48, 0x51, 0x41, 0x70, 0x4e, 0x62, 0x57, 0x74, 0x53, 0x55, +0x7a, 0x2f, 0x33, 0x52, 0x4f, 0x76, 0x6f, 0x55, 0x53, 0x38, 0x78, 0x44, 0x37, 0x78, 0x53, 0x2b, +0x65, 0x59, 0x65, 0x76, 0x57, 0x4a, 0x35, 0x6b, 0x78, 0x49, 0x35, 0x38, 0x56, 0x4b, 0x35, 0x6f, +0x73, 0x56, 0x4b, 0x4e, 0x4d, 0x68, 0x71, 0x71, 0x6f, 0x76, 0x5a, 0x66, 0x4f, 0x33, 0x31, 0x77, +0x36, 0x6f, 0x35, 0x41, 0x51, 0x69, 0x68, 0x6b, 0x7a, 0x72, 0x4f, 0x42, 0x79, 0x57, 0x5a, 0x35, +0x46, 0x4b, 0x66, 0x4f, 0x69, 0x65, 0x64, 0x78, 0x30, 0x79, 0x45, 0x31, 0x30, 0x69, 0x41, 0x34, +0x6b, 0x4b, 0x68, 0x53, 0x36, 0x6b, 0x45, 0x67, 0x33, 0x4c, 0x58, 0x42, 0x58, 0x35, 0x79, 0x45, +0x32, 0x34, 0x7a, 0x47, 0x48, 0x55, 0x6a, 0x6f, 0x55, 0x30, 0x35, 0x6a, 0x4d, 0x2f, 0x64, 0x61, +0x68, 0x43, 0x30, 0x71, 0x5a, 0x63, 0x37, 0x62, 0x58, 0x31, 0x2f, 0x50, 0x4e, 0x34, 0x45, 0x74, +0x4a, 0x6e, 0x44, 0x63, 0x56, 0x67, 0x32, 0x48, 0x74, 0x6d, 0x6c, 0x39, 0x79, 0x36, 0x35, 0x68, +0x38, 0x74, 0x44, 0x45, 0x55, 0x46, 0x53, 0x59, 0x34, 0x35, 0x2b, 0x51, 0x50, 0x65, 0x65, 0x53, +0x5a, 0x51, 0x37, 0x6a, 0x77, 0x74, 0x41, 0x39, 0x34, 0x34, 0x71, 0x55, 0x44, 0x69, 0x55, 0x5a, +0x38, 0x66, 0x76, 0x61, 0x54, 0x4f, 0x54, 0x7a, 0x77, 0x7a, 0x45, 0x39, 0x49, 0x4a, 0x75, 0x4f, +0x38, 0x2b, 0x65, 0x70, 0x66, 0x32, 0x46, 0x59, 0x32, 0x6b, 0x4b, 0x55, 0x48, 0x6a, 0x2b, 0x4f, +0x5a, 0x6b, 0x78, 0x4d, 0x73, 0x57, 0x7a, 0x75, 0x47, 0x38, 0x71, 0x4c, 0x66, 0x4d, 0x79, 0x31, +0x52, 0x53, 0x6b, 0x32, 0x76, 0x69, 0x63, 0x78, 0x63, 0x63, 0x7a, 0x51, 0x33, 0x62, 0x6d, 0x68, +0x6a, 0x38, 0x56, 0x48, 0x48, 0x75, 0x4f, 0x33, 0x51, 0x4f, 0x70, 0x44, 0x43, 0x34, 0x4d, 0x73, +0x34, 0x55, 0x6b, 0x71, 0x6d, 0x50, 0x2f, 0x77, 0x6f, 0x4d, 0x4a, 0x72, 0x61, 0x71, 0x56, 0x76, +0x6f, 0x7a, 0x61, 0x65, 0x4d, 0x69, 0x33, 0x78, 0x4a, 0x33, 0x45, 0x73, 0x68, 0x55, 0x68, 0x59, +0x46, 0x44, 0x6e, 0x5a, 0x42, 0x53, 0x67, 0x4e, 0x42, 0x47, 0x58, 0x4e, 0x56, 0x4b, 0x66, 0x6e, +0x79, 0x74, 0x64, 0x66, 0x34, 0x48, 0x58, 0x44, 0x38, 0x31, 0x4b, 0x6c, 0x38, 0x41, 0x43, 0x7a, +0x57, 0x36, 0x65, 0x47, 0x31, 0x6c, 0x47, 0x37, 0x39, 0x33, 0x51, 0x33, 0x64, 0x70, 0x4c, 0x42, +0x71, 0x74, 0x73, 0x45, 0x31, 0x56, 0x4c, 0x56, 0x74, 0x68, 0x61, 0x6e, 0x6e, 0x5a, 0x71, 0x50, +0x51, 0x79, 0x6c, 0x4d, 0x77, 0x4c, 0x41, 0x4d, 0x46, 0x64, 0x55, 0x74, 0x58, 0x33, 0x61, 0x6e, +0x36, 0x30, 0x67, 0x35, 0x54, 0x44, 0x33, 0x63, 0x46, 0x7a, 0x6a, 0x67, 0x55, 0x32, 0x71, 0x32, +0x51, 0x4b, 0x75, 0x4e, 0x55, 0x6d, 0x62, 0x30, 0x6f, 0x55, 0x6b, 0x66, 0x53, 0x56, 0x6e, 0x4a, +0x6e, 0x4b, 0x5a, 0x38, 0x78, 0x4c, 0x55, 0x43, 0x68, 0x63, 0x31, 0x44, 0x59, 0x58, 0x42, 0x52, +0x31, 0x65, 0x2b, 0x45, 0x44, 0x42, 0x55, 0x56, 0x46, 0x59, 0x66, 0x34, 0x44, 0x76, 0x4e, 0x53, +0x53, 0x34, 0x76, 0x6d, 0x70, 0x31, 0x36, 0x43, 0x55, 0x54, 0x54, 0x38, 0x6c, 0x6c, 0x52, 0x55, +0x57, 0x64, 0x65, 0x2b, 0x76, 0x70, 0x4e, 0x31, 0x73, 0x35, 0x75, 0x71, 0x58, 0x58, 0x67, 0x58, +0x67, 0x68, 0x49, 0x4e, 0x72, 0x58, 0x50, 0x68, 0x32, 0x68, 0x36, 0x76, 0x71, 0x36, 0x74, 0x49, +0x73, 0x59, 0x31, 0x6d, 0x77, 0x55, 0x68, 0x57, 0x2f, 0x2f, 0x58, 0x36, 0x62, 0x4a, 0x38, 0x34, +0x59, 0x74, 0x2f, 0x57, 0x50, 0x74, 0x38, 0x49, 0x32, 0x79, 0x64, 0x52, 0x62, 0x68, 0x37, 0x6e, +0x30, 0x38, 0x39, 0x41, 0x6d, 0x51, 0x75, 0x47, 0x41, 0x50, 0x78, 0x4b, 0x50, 0x70, 0x77, 0x43, +0x72, 0x57, 0x77, 0x41, 0x4f, 0x6f, 0x54, 0x32, 0x74, 0x61, 0x2f, 0x77, 0x56, 0x30, 0x50, 0x75, +0x38, 0x58, 0x39, 0x73, 0x43, 0x61, 0x2b, 0x78, 0x2b, 0x41, 0x73, 0x72, 0x59, 0x74, 0x41, 0x76, +0x32, 0x33, 0x4d, 0x77, 0x38, 0x4d, 0x7a, 0x2f, 0x66, 0x2b, 0x4e, 0x49, 0x62, 0x41, 0x4c, 0x6a, +0x58, 0x64, 0x33, 0x45, 0x4f, 0x6d, 0x42, 0x42, 0x62, 0x2f, 0x6f, 0x33, 0x78, 0x67, 0x43, 0x6a, +0x47, 0x52, 0x4c, 0x71, 0x55, 0x2f, 0x30, 0x32, 0x62, 0x32, 0x76, 0x45, 0x31, 0x33, 0x50, 0x2f, +0x54, 0x39, 0x50, 0x50, 0x4b, 0x65, 0x47, 0x34, 0x66, 0x41, 0x77, 0x65, 0x7a, 0x47, 0x51, 0x2b, +0x6c, 0x6f, 0x77, 0x67, 0x64, 0x77, 0x57, 0x6a, 0x4a, 0x79, 0x62, 0x30, 0x66, 0x78, 0x6a, 0x4d, +0x2b, 0x4c, 0x32, 0x36, 0x38, 0x68, 0x44, 0x73, 0x66, 0x30, 0x63, 0x53, 0x53, 0x79, 0x52, 0x6c, +0x55, 0x56, 0x76, 0x62, 0x6c, 0x39, 0x4e, 0x4d, 0x4e, 0x37, 0x37, 0x35, 0x62, 0x78, 0x79, 0x75, +0x76, 0x66, 0x45, 0x39, 0x6e, 0x70, 0x32, 0x39, 0x5a, 0x37, 0x51, 0x78, 0x4c, 0x62, 0x47, 0x43, +0x51, 0x73, 0x56, 0x4a, 0x48, 0x69, 0x6b, 0x47, 0x44, 0x69, 0x73, 0x6e, 0x30, 0x6f, 0x67, 0x6b, +0x53, 0x65, 0x6e, 0x33, 0x48, 0x65, 0x6c, 0x70, 0x54, 0x72, 0x53, 0x68, 0x74, 0x6f, 0x5a, 0x49, +0x42, 0x78, 0x51, 0x4e, 0x5a, 0x31, 0x37, 0x53, 0x4b, 0x68, 0x45, 0x72, 0x67, 0x43, 0x7a, 0x38, +0x62, 0x78, 0x63, 0x31, 0x77, 0x77, 0x67, 0x6b, 0x79, 0x4c, 0x50, 0x4e, 0x2b, 0x75, 0x38, 0x74, +0x6f, 0x6e, 0x68, 0x63, 0x4f, 0x72, 0x77, 0x77, 0x47, 0x50, 0x35, 0x56, 0x43, 0x74, 0x62, 0x56, +0x53, 0x57, 0x31, 0x75, 0x4d, 0x30, 0x4a, 0x70, 0x62, 0x4c, 0x35, 0x75, 0x4f, 0x45, 0x52, 0x32, +0x73, 0x71, 0x39, 0x32, 0x64, 0x6c, 0x6d, 0x30, 0x62, 0x61, 0x4e, 0x6c, 0x57, 0x79, 0x34, 0x62, +0x36, 0x4d, 0x69, 0x62, 0x74, 0x76, 0x5a, 0x72, 0x4e, 0x39, 0x61, 0x4d, 0x70, 0x4b, 0x68, 0x34, +0x4b, 0x53, 0x4a, 0x35, 0x4d, 0x33, 0x6b, 0x4e, 0x70, 0x38, 0x52, 0x54, 0x30, 0x32, 0x67, 0x5a, +0x32, 0x57, 0x6a, 0x67, 0x66, 0x4e, 0x6d, 0x31, 0x69, 0x70, 0x36, 0x47, 0x44, 0x53, 0x52, 0x5a, +0x56, 0x63, 0x6c, 0x68, 0x54, 0x42, 0x39, 0x39, 0x39, 0x73, 0x6f, 0x53, 0x33, 0x49, 0x33, 0x75, +0x51, 0x37, 0x33, 0x55, 0x67, 0x76, 0x46, 0x62, 0x32, 0x47, 0x78, 0x56, 0x6e, 0x78, 0x70, 0x64, +0x52, 0x42, 0x6c, 0x53, 0x6e, 0x53, 0x62, 0x51, 0x6b, 0x52, 0x55, 0x79, 0x76, 0x4f, 0x35, 0x4b, +0x68, 0x4a, 0x65, 0x4f, 0x35, 0x59, 0x6d, 0x6f, 0x52, 0x66, 0x58, 0x72, 0x6e, 0x32, 0x35, 0x57, +0x49, 0x34, 0x46, 0x30, 0x79, 0x34, 0x78, 0x36, 0x78, 0x47, 0x59, 0x6e, 0x57, 0x56, 0x67, 0x35, +0x37, 0x7a, 0x7a, 0x33, 0x70, 0x6a, 0x65, 0x48, 0x58, 0x64, 0x52, 0x75, 0x59, 0x71, 0x52, 0x51, +0x76, 0x4b, 0x55, 0x57, 0x4c, 0x45, 0x48, 0x62, 0x6e, 0x59, 0x7a, 0x65, 0x50, 0x73, 0x37, 0x70, +0x77, 0x77, 0x71, 0x5a, 0x66, 0x72, 0x71, 0x70, 0x74, 0x78, 0x42, 0x61, 0x55, 0x75, 0x71, 0x59, +0x4e, 0x46, 0x45, 0x55, 0x56, 0x45, 0x36, 0x6f, 0x55, 0x34, 0x36, 0x6f, 0x45, 0x38, 0x67, 0x53, +0x46, 0x62, 0x42, 0x54, 0x6b, 0x76, 0x53, 0x51, 0x77, 0x54, 0x61, 0x4a, 0x48, 0x56, 0x64, 0x39, +0x67, 0x49, 0x62, 0x71, 0x75, 0x77, 0x78, 0x56, 0x63, 0x43, 0x52, 0x50, 0x36, 0x66, 0x4d, 0x58, +0x42, 0x4e, 0x52, 0x2f, 0x69, 0x47, 0x63, 0x6c, 0x2f, 0x36, 0x67, 0x37, 0x6d, 0x6f, 0x39, 0x71, +0x4a, 0x43, 0x47, 0x4d, 0x4e, 0x6f, 0x62, 0x36, 0x72, 0x2f, 0x49, 0x4e, 0x4b, 0x50, 0x4e, 0x4b, +0x65, 0x6e, 0x53, 0x59, 0x62, 0x68, 0x63, 0x31, 0x45, 0x55, 0x54, 0x4e, 0x51, 0x31, 0x75, 0x37, +0x43, 0x44, 0x33, 0x38, 0x68, 0x49, 0x2f, 0x2b, 0x6e, 0x33, 0x33, 0x6f, 0x6a, 0x6a, 0x62, 0x56, +0x72, 0x58, 0x59, 0x57, 0x58, 0x53, 0x47, 0x48, 0x33, 0x4e, 0x70, 0x52, 0x43, 0x49, 0x49, 0x57, +0x50, 0x46, 0x49, 0x4c, 0x4b, 0x41, 0x51, 0x4d, 0x7a, 0x43, 0x67, 0x2b, 0x30, 0x64, 0x51, 0x71, +0x33, 0x62, 0x36, 0x4b, 0x6d, 0x6f, 0x79, 0x4f, 0x74, 0x78, 0x61, 0x41, 0x64, 0x4e, 0x61, 0x65, +0x55, 0x6f, 0x71, 0x79, 0x2b, 0x44, 0x75, 0x32, 0x6e, 0x4d, 0x48, 0x34, 0x4b, 0x71, 0x6e, 0x72, +0x62, 0x55, 0x5a, 0x6d, 0x54, 0x72, 0x4b, 0x39, 0x72, 0x46, 0x49, 0x37, 0x2b, 0x6a, 0x4b, 0x42, +0x31, 0x4c, 0x5a, 0x41, 0x67, 0x53, 0x78, 0x64, 0x54, 0x69, 0x6d, 0x35, 0x56, 0x73, 0x61, 0x56, +0x74, 0x4f, 0x65, 0x6c, 0x63, 0x75, 0x42, 0x6f, 0x4e, 0x62, 0x4e, 0x59, 0x78, 0x2b, 0x68, 0x35, +0x54, 0x67, 0x39, 0x4b, 0x47, 0x78, 0x6f, 0x39, 0x62, 0x4b, 0x4f, 0x31, 0x6f, 0x73, 0x69, 0x4f, +0x42, 0x49, 0x44, 0x37, 0x75, 0x6e, 0x66, 0x4e, 0x47, 0x44, 0x38, 0x71, 0x47, 0x67, 0x50, 0x34, +0x2f, 0x35, 0x54, 0x39, 0x6a, 0x4b, 0x74, 0x4c, 0x67, 0x38, 0x6b, 0x2f, 0x72, 0x77, 0x49, 0x63, +0x46, 0x70, 0x33, 0x56, 0x70, 0x47, 0x2b, 0x32, 0x6b, 0x4d, 0x4a, 0x78, 0x62, 0x66, 0x53, 0x73, +0x6c, 0x2f, 0x6e, 0x49, 0x69, 0x75, 0x70, 0x4f, 0x54, 0x65, 0x2f, 0x76, 0x63, 0x79, 0x65, 0x2b, +0x4a, 0x51, 0x52, 0x6e, 0x47, 0x64, 0x42, 0x4b, 0x4a, 0x62, 0x4f, 0x54, 0x59, 0x59, 0x34, 0x73, +0x5a, 0x4f, 0x6e, 0x51, 0x73, 0x54, 0x7a, 0x2b, 0x39, 0x69, 0x68, 0x55, 0x72, 0x57, 0x6b, 0x50, +0x72, 0x72, 0x42, 0x38, 0x73, 0x78, 0x2f, 0x68, 0x4f, 0x31, 0x64, 0x55, 0x74, 0x79, 0x77, 0x51, +0x56, 0x49, 0x47, 0x74, 0x70, 0x51, 0x73, 0x75, 0x51, 0x32, 0x4c, 0x74, 0x38, 0x39, 0x38, 0x76, +0x5a, 0x6b, 0x74, 0x6a, 0x43, 0x67, 0x6b, 0x33, 0x66, 0x45, 0x59, 0x76, 0x48, 0x75, 0x47, 0x7a, +0x38, 0x5a, 0x54, 0x79, 0x31, 0x39, 0x43, 0x6c, 0x57, 0x74, 0x71, 0x79, 0x30, 0x36, 0x2f, 0x44, +0x79, 0x2f, 0x2f, 0x66, 0x79, 0x77, 0x58, 0x65, 0x30, 0x31, 0x68, 0x79, 0x36, 0x37, 0x54, 0x47, +0x2b, 0x58, 0x76, 0x39, 0x4c, 0x56, 0x46, 0x73, 0x72, 0x39, 0x32, 0x32, 0x65, 0x69, 0x78, 0x41, +0x48, 0x6f, 0x71, 0x52, 0x48, 0x52, 0x56, 0x6b, 0x7a, 0x47, 0x4d, 0x47, 0x6b, 0x41, 0x37, 0x36, +0x6c, 0x54, 0x2b, 0x55, 0x57, 0x54, 0x76, 0x76, 0x35, 0x78, 0x7a, 0x7a, 0x35, 0x30, 0x76, 0x35, +0x55, 0x39, 0x39, 0x6e, 0x45, 0x6d, 0x42, 0x47, 0x72, 0x61, 0x65, 0x6b, 0x73, 0x41, 0x54, 0x53, +0x62, 0x4b, 0x4b, 0x4d, 0x6f, 0x47, 0x69, 0x63, 0x57, 0x69, 0x55, 0x49, 0x69, 0x68, 0x57, 0x6e, +0x59, 0x43, 0x74, 0x58, 0x56, 0x64, 0x42, 0x54, 0x45, 0x61, 0x61, 0x4f, 0x51, 0x72, 0x53, 0x71, +0x47, 0x52, 0x34, 0x49, 0x52, 0x6b, 0x39, 0x39, 0x6a, 0x2f, 0x5a, 0x79, 0x2b, 0x35, 0x4f, 0x63, +0x4e, 0x34, 0x61, 0x42, 0x64, 0x76, 0x79, 0x47, 0x2b, 0x55, 0x31, 0x39, 0x34, 0x32, 0x4c, 0x36, +0x41, 0x31, 0x49, 0x62, 0x53, 0x51, 0x6c, 0x69, 0x2b, 0x72, 0x53, 0x2b, 0x58, 0x58, 0x6d, 0x65, +0x34, 0x39, 0x53, 0x61, 0x6f, 0x47, 0x57, 0x43, 0x73, 0x7a, 0x33, 0x39, 0x33, 0x38, 0x63, 0x66, +0x36, 0x32, 0x75, 0x75, 0x59, 0x4e, 0x66, 0x67, 0x46, 0x4b, 0x4f, 0x6c, 0x68, 0x53, 0x6a, 0x46, +0x4d, 0x43, 0x49, 0x5a, 0x4f, 0x50, 0x67, 0x5a, 0x7a, 0x35, 0x75, 0x6b, 0x2f, 0x57, 0x41, 0x44, +0x57, 0x72, 0x56, 0x76, 0x48, 0x6d, 0x4b, 0x76, 0x48, 0x68, 0x43, 0x6a, 0x30, 0x46, 0x58, 0x73, +0x70, 0x79, 0x6c, 0x4f, 0x53, 0x76, 0x42, 0x63, 0x55, 0x49, 0x69, 0x45, 0x77, 0x6b, 0x77, 0x54, +0x74, 0x5a, 0x77, 0x69, 0x4b, 0x37, 0x76, 0x57, 0x37, 0x53, 0x47, 0x53, 0x46, 0x71, 0x73, 0x72, +0x67, 0x6e, 0x72, 0x63, 0x4c, 0x43, 0x54, 0x38, 0x66, 0x4e, 0x6f, 0x31, 0x66, 0x44, 0x62, 0x38, +0x44, 0x6a, 0x33, 0x6f, 0x4d, 0x66, 0x64, 0x6d, 0x6a, 0x38, 0x68, 0x32, 0x4d, 0x76, 0x70, 0x47, +0x33, 0x56, 0x68, 0x2b, 0x4a, 0x54, 0x39, 0x6f, 0x58, 0x77, 0x70, 0x4c, 0x41, 0x47, 0x6a, 0x6f, +0x36, 0x4d, 0x48, 0x6c, 0x35, 0x59, 0x57, 0x50, 0x51, 0x70, 0x63, 0x48, 0x4c, 0x4a, 0x53, 0x4e, +0x64, 0x62, 0x30, 0x77, 0x6b, 0x67, 0x74, 0x36, 0x79, 0x70, 0x55, 0x76, 0x2b, 0x61, 0x36, 0x33, +0x35, 0x31, 0x51, 0x32, 0x33, 0x63, 0x4f, 0x2b, 0x76, 0x54, 0x33, 0x53, 0x56, 0x58, 0x6f, 0x59, +0x56, 0x58, 0x77, 0x6d, 0x72, 0x69, 0x79, 0x65, 0x46, 0x33, 0x65, 0x2f, 0x52, 0x50, 0x6b, 0x43, +0x6f, 0x36, 0x68, 0x77, 0x59, 0x56, 0x79, 0x4f, 0x52, 0x53, 0x44, 0x6a, 0x73, 0x44, 0x33, 0x59, +0x51, 0x30, 0x6c, 0x71, 0x6a, 0x2f, 0x53, 0x51, 0x36, 0x35, 0x57, 0x4e, 0x6b, 0x43, 0x73, 0x2f, +0x33, 0x30, 0x2b, 0x2f, 0x76, 0x45, 0x50, 0x42, 0x67, 0x44, 0x30, 0x61, 0x72, 0x68, 0x75, 0x32, +0x7a, 0x49, 0x36, 0x72, 0x59, 0x43, 0x74, 0x44, 0x47, 0x43, 0x73, 0x74, 0x71, 0x49, 0x46, 0x70, +0x53, 0x52, 0x4f, 0x6c, 0x56, 0x77, 0x77, 0x48, 0x44, 0x35, 0x6c, 0x6e, 0x66, 0x68, 0x70, 0x2b, +0x48, 0x6c, 0x54, 0x2f, 0x6e, 0x37, 0x35, 0x4e, 0x4f, 0x67, 0x67, 0x73, 0x75, 0x4d, 0x44, 0x51, +0x31, 0x75, 0x56, 0x35, 0x62, 0x42, 0x58, 0x74, 0x76, 0x42, 0x69, 0x50, 0x78, 0x72, 0x6c, 0x63, +0x70, 0x44, 0x5a, 0x57, 0x56, 0x63, 0x4d, 0x55, 0x56, 0x6d, 0x76, 0x68, 0x74, 0x37, 0x76, 0x32, +0x31, 0x64, 0x57, 0x42, 0x54, 0x41, 0x63, 0x6a, 0x6b, 0x4b, 0x72, 0x2f, 0x4b, 0x63, 0x46, 0x35, +0x37, 0x61, 0x64, 0x4d, 0x46, 0x58, 0x46, 0x77, 0x39, 0x68, 0x58, 0x62, 0x5a, 0x68, 0x31, 0x6b, +0x64, 0x4a, 0x34, 0x43, 0x76, 0x69, 0x64, 0x6c, 0x57, 0x5a, 0x44, 0x30, 0x77, 0x44, 0x57, 0x4f, +0x4b, 0x32, 0x57, 0x58, 0x73, 0x4a, 0x64, 0x78, 0x30, 0x30, 0x31, 0x37, 0x63, 0x64, 0x64, 0x66, +0x58, 0x7a, 0x4a, 0x6d, 0x7a, 0x4e, 0x65, 0x7a, 0x78, 0x67, 0x34, 0x72, 0x66, 0x58, 0x51, 0x4f, +0x51, 0x62, 0x6f, 0x68, 0x4e, 0x43, 0x50, 0x51, 0x63, 0x55, 0x48, 0x30, 0x41, 0x6f, 0x79, 0x74, +0x47, 0x38, 0x38, 0x4b, 0x4b, 0x66, 0x35, 0x44, 0x53, 0x4b, 0x59, 0x59, 0x57, 0x44, 0x32, 0x56, +0x4d, 0x35, 0x52, 0x68, 0x4f, 0x32, 0x2b, 0x6b, 0x30, 0x72, 0x76, 0x76, 0x38, 0x75, 0x70, 0x44, +0x46, 0x31, 0x35, 0x41, 0x78, 0x37, 0x50, 0x38, 0x52, 0x4b, 0x4b, 0x30, 0x74, 0x4c, 0x55, 0x77, +0x2f, 0x62, 0x7a, 0x35, 0x62, 0x4b, 0x36, 0x76, 0x49, 0x6a, 0x33, 0x76, 0x38, 0x65, 0x76, 0x54, +0x65, 0x66, 0x50, 0x76, 0x71, 0x50, 0x4b, 0x54, 0x6e, 0x63, 0x64, 0x66, 0x66, 0x4a, 0x6a, 0x4f, +0x77, 0x33, 0x77, 0x62, 0x4f, 0x4f, 0x48, 0x34, 0x6d, 0x34, 0x43, 0x4e, 0x6b, 0x49, 0x58, 0x2b, +0x2b, 0x2f, 0x6c, 0x6e, 0x6d, 0x4c, 0x2b, 0x6c, 0x48, 0x52, 0x50, 0x75, 0x63, 0x65, 0x39, 0x49, +0x4d, 0x58, 0x6e, 0x77, 0x78, 0x77, 0x6e, 0x56, 0x46, 0x46, 0x33, 0x44, 0x54, 0x74, 0x69, 0x4c, +0x47, 0x39, 0x79, 0x72, 0x6e, 0x6d, 0x30, 0x47, 0x48, 0x73, 0x70, 0x75, 0x43, 0x6a, 0x33, 0x70, +0x4e, 0x59, 0x6e, 0x54, 0x6a, 0x6c, 0x38, 0x79, 0x71, 0x50, 0x49, 0x79, 0x56, 0x77, 0x32, 0x70, +0x6f, 0x58, 0x62, 0x6d, 0x59, 0x42, 0x52, 0x2f, 0x74, 0x7a, 0x4c, 0x43, 0x69, 0x72, 0x31, 0x6d, +0x34, 0x64, 0x68, 0x48, 0x78, 0x73, 0x6b, 0x6f, 0x53, 0x73, 0x38, 0x63, 0x43, 0x6e, 0x77, 0x4f, +0x61, 0x76, 0x6e, 0x30, 0x39, 0x54, 0x6a, 0x30, 0x46, 0x2f, 0x76, 0x75, 0x68, 0x59, 0x65, 0x35, +0x38, 0x75, 0x4f, 0x51, 0x53, 0x77, 0x32, 0x38, 0x48, 0x76, 0x63, 0x62, 0x77, 0x31, 0x6b, 0x38, +0x70, 0x46, 0x51, 0x32, 0x68, 0x6d, 0x6b, 0x32, 0x6d, 0x4a, 0x6c, 0x7a, 0x65, 0x77, 0x49, 0x46, +0x38, 0x50, 0x6e, 0x30, 0x36, 0x5a, 0x77, 0x4a, 0x30, 0x64, 0x74, 0x6f, 0x64, 0x37, 0x37, 0x52, +0x6d, 0x71, 0x4a, 0x43, 0x59, 0x44, 0x39, 0x36, 0x31, 0x48, 0x4d, 0x4e, 0x70, 0x70, 0x2f, 0x31, +0x67, 0x41, 0x34, 0x68, 0x32, 0x4b, 0x4c, 0x57, 0x55, 0x4e, 0x48, 0x64, 0x49, 0x2b, 0x6e, 0x32, +0x67, 0x69, 0x46, 0x31, 0x38, 0x47, 0x79, 0x30, 0x64, 0x6b, 0x50, 0x2f, 0x69, 0x58, 0x55, 0x51, +0x50, 0x71, 0x30, 0x58, 0x69, 0x45, 0x38, 0x6e, 0x5a, 0x6e, 0x6a, 0x74, 0x55, 0x39, 0x64, 0x55, +0x61, 0x68, 0x57, 0x64, 0x58, 0x4e, 0x53, 0x4b, 0x43, 0x59, 0x77, 0x59, 0x2f, 0x68, 0x45, 0x63, +0x74, 0x41, 0x42, 0x37, 0x31, 0x52, 0x44, 0x7a, 0x4a, 0x71, 0x53, 0x4f, 0x65, 0x35, 0x61, 0x31, +0x31, 0x68, 0x2b, 0x4b, 0x6e, 0x59, 0x75, 0x45, 0x49, 0x49, 0x4d, 0x6a, 0x2b, 0x5a, 0x70, 0x31, +0x48, 0x65, 0x54, 0x51, 0x4b, 0x30, 0x57, 0x68, 0x57, 0x2f, 0x75, 0x6e, 0x61, 0x57, 0x6c, 0x4a, +0x76, 0x76, 0x32, 0x62, 0x66, 0x39, 0x64, 0x68, 0x66, 0x77, 0x4f, 0x44, 0x42, 0x32, 0x66, 0x48, +0x33, 0x50, 0x4c, 0x62, 0x34, 0x65, 0x56, 0x52, 0x6b, 0x6c, 0x68, 0x2f, 0x33, 0x58, 0x73, 0x39, +0x66, 0x64, 0x37, 0x57, 0x74, 0x2f, 0x4c, 0x36, 0x66, 0x31, 0x51, 0x44, 0x49, 0x38, 0x44, 0x4f, +0x42, 0x45, 0x71, 0x37, 0x78, 0x6c, 0x63, 0x47, 0x71, 0x69, 0x6e, 0x59, 0x6b, 0x6e, 0x33, 0x58, +0x47, 0x69, 0x55, 0x51, 0x69, 0x7a, 0x75, 0x55, 0x34, 0x49, 0x37, 0x31, 0x53, 0x74, 0x76, 0x66, +0x58, 0x44, 0x68, 0x44, 0x79, 0x62, 0x65, 0x76, 0x74, 0x4b, 0x6f, 0x32, 0x32, 0x6d, 0x69, 0x66, +0x4b, 0x6b, 0x43, 0x31, 0x6e, 0x6c, 0x71, 0x47, 0x51, 0x31, 0x59, 0x30, 0x71, 0x39, 0x75, 0x6a, +0x42, 0x31, 0x37, 0x48, 0x50, 0x6b, 0x49, 0x4f, 0x5a, 0x34, 0x7a, 0x65, 0x42, 0x55, 0x57, 0x7a, +0x39, 0x4b, 0x58, 0x78, 0x2f, 0x39, 0x4e, 0x4d, 0x6f, 0x59, 0x78, 0x68, 0x32, 0x33, 0x64, 0x56, +0x55, 0x50, 0x6c, 0x33, 0x76, 0x57, 0x71, 0x6e, 0x41, 0x38, 0x47, 0x6d, 0x62, 0x6e, 0x66, 0x45, +0x44, 0x53, 0x35, 0x6c, 0x66, 0x4d, 0x78, 0x6a, 0x65, 0x30, 0x2b, 0x79, 0x36, 0x71, 0x30, 0x64, +0x74, 0x4c, 0x62, 0x5a, 0x79, 0x43, 0x2b, 0x7a, 0x53, 0x63, 0x34, 0x34, 0x71, 0x64, 0x75, 0x34, +0x31, 0x57, 0x49, 0x67, 0x51, 0x76, 0x6b, 0x59, 0x61, 0x44, 0x31, 0x2b, 0x6c, 0x2f, 0x56, 0x68, +0x6b, 0x78, 0x6b, 0x37, 0x53, 0x79, 0x51, 0x79, 0x32, 0x59, 0x59, 0x50, 0x66, 0x68, 0x36, 0x6e, +0x66, 0x50, 0x34, 0x33, 0x55, 0x68, 0x74, 0x34, 0x6c, 0x55, 0x57, 0x68, 0x74, 0x4a, 0x51, 0x5a, +0x74, 0x77, 0x44, 0x71, 0x4d, 0x57, 0x59, 0x73, 0x78, 0x52, 0x63, 0x41, 0x61, 0x69, 0x6f, 0x76, +0x48, 0x63, 0x39, 0x74, 0x74, 0x30, 0x33, 0x6e, 0x6c, 0x6b, 0x56, 0x32, 0x59, 0x2b, 0x33, 0x49, +0x54, 0x30, 0x6c, 0x64, 0x49, 0x49, 0x52, 0x47, 0x2b, 0x73, 0x68, 0x4c, 0x54, 0x51, 0x74, 0x4a, +0x58, 0x39, 0x75, 0x46, 0x6a, 0x76, 0x75, 0x36, 0x43, 0x77, 0x67, 0x70, 0x6c, 0x68, 0x36, 0x79, +0x6c, 0x38, 0x56, 0x49, 0x4b, 0x6f, 0x34, 0x58, 0x55, 0x74, 0x32, 0x2f, 0x41, 0x56, 0x7a, 0x37, +0x66, 0x4e, 0x73, 0x7a, 0x6c, 0x72, 0x6d, 0x2f, 0x75, 0x6f, 0x72, 0x61, 0x74, 0x46, 0x74, 0x2f, +0x34, 0x53, 0x43, 0x4e, 0x74, 0x2b, 0x31, 0x46, 0x65, 0x44, 0x76, 0x66, 0x66, 0x6a, 0x36, 0x6d, +0x76, 0x74, 0x79, 0x68, 0x6c, 0x78, 0x6e, 0x77, 0x35, 0x6e, 0x44, 0x4d, 0x47, 0x75, 0x37, 0x6f, +0x47, 0x77, 0x30, 0x6b, 0x70, 0x59, 0x63, 0x41, 0x41, 0x39, 0x4c, 0x50, 0x50, 0x55, 0x72, 0x52, +0x2b, 0x50, 0x53, 0x6b, 0x68, 0x38, 0x4b, 0x49, 0x78, 0x30, 0x42, 0x47, 0x55, 0x54, 0x6e, 0x48, +0x6b, 0x77, 0x66, 0x50, 0x34, 0x63, 0x74, 0x35, 0x77, 0x39, 0x74, 0x32, 0x31, 0x6e, 0x71, 0x4b, +0x43, 0x42, 0x4b, 0x31, 0x74, 0x64, 0x73, 0x2f, 0x34, 0x6a, 0x6e, 0x61, 0x4a, 0x6b, 0x6f, 0x4b, +0x2b, 0x76, 0x54, 0x61, 0x68, 0x6a, 0x5a, 0x58, 0x45, 0x4b, 0x71, 0x70, 0x64, 0x77, 0x4d, 0x41, +0x4e, 0x63, 0x65, 0x37, 0x35, 0x59, 0x6d, 0x64, 0x71, 0x64, 0x42, 0x4f, 0x52, 0x35, 0x56, 0x75, +0x5a, 0x70, 0x7a, 0x54, 0x31, 0x63, 0x67, 0x68, 0x6a, 0x76, 0x72, 0x6d, 0x50, 0x31, 0x53, 0x57, +0x48, 0x49, 0x70, 0x4e, 0x35, 0x4a, 0x47, 0x55, 0x6c, 0x54, 0x66, 0x33, 0x4b, 0x4b, 0x65, 0x6d, +0x39, 0x4e, 0x77, 0x30, 0x62, 0x46, 0x71, 0x41, 0x36, 0x49, 0x32, 0x45, 0x44, 0x75, 0x4d, 0x39, +0x65, 0x4d, 0x47, 0x61, 0x73, 0x6f, 0x62, 0x6a, 0x49, 0x38, 0x4f, 0x6c, 0x6e, 0x6f, 0x49, 0x58, +0x68, 0x72, 0x38, 0x75, 0x4f, 0x35, 0x7a, 0x53, 0x31, 0x6e, 0x41, 0x6d, 0x70, 0x62, 0x34, 0x6a, +0x36, 0x43, 0x5a, 0x49, 0x42, 0x72, 0x4f, 0x4c, 0x57, 0x64, 0x51, 0x75, 0x4d, 0x6f, 0x5a, 0x36, +0x63, 0x49, 0x35, 0x6d, 0x79, 0x37, 0x35, 0x66, 0x6f, 0x78, 0x44, 0x7a, 0x33, 0x48, 0x4b, 0x61, +0x68, 0x45, 0x58, 0x50, 0x35, 0x5a, 0x64, 0x30, 0x33, 0x41, 0x49, 0x45, 0x33, 0x6d, 0x35, 0x39, +0x47, 0x71, 0x57, 0x4e, 0x49, 0x45, 0x68, 0x32, 0x53, 0x76, 0x45, 0x67, 0x68, 0x7a, 0x66, 0x30, +0x48, 0x55, 0x52, 0x47, 0x4a, 0x55, 0x78, 0x42, 0x4a, 0x49, 0x65, 0x49, 0x2b, 0x65, 0x54, 0x6b, +0x6f, 0x62, 0x4c, 0x61, 0x71, 0x73, 0x6c, 0x30, 0x4c, 0x7a, 0x34, 0x75, 0x6d, 0x4b, 0x49, 0x6c, +0x39, 0x6e, 0x78, 0x57, 0x6c, 0x69, 0x4c, 0x65, 0x56, 0x33, 0x67, 0x58, 0x72, 0x69, 0x58, 0x74, +0x74, 0x2b, 0x4c, 0x49, 0x43, 0x33, 0x77, 0x52, 0x72, 0x35, 0x56, 0x35, 0x6f, 0x53, 0x4d, 0x72, +0x4d, 0x2f, 0x77, 0x77, 0x4c, 0x46, 0x57, 0x63, 0x41, 0x41, 0x43, 0x41, 0x41, 0x53, 0x55, 0x52, +0x42, 0x56, 0x50, 0x43, 0x2b, 0x76, 0x5a, 0x57, 0x58, 0x64, 0x74, 0x6e, 0x47, 0x6b, 0x73, 0x2b, +0x4f, 0x35, 0x38, 0x36, 0x32, 0x4a, 0x6a, 0x43, 0x44, 0x75, 0x6f, 0x6c, 0x2f, 0x39, 0x79, 0x6a, +0x31, 0x62, 0x32, 0x36, 0x2f, 0x6d, 0x7a, 0x74, 0x50, 0x4f, 0x44, 0x70, 0x64, 0x38, 0x58, 0x31, +0x72, 0x38, 0x31, 0x43, 0x75, 0x45, 0x51, 0x68, 0x47, 0x41, 0x51, 0x43, 0x2b, 0x4c, 0x31, 0x31, +0x76, 0x71, 0x52, 0x46, 0x61, 0x6f, 0x36, 0x51, 0x68, 0x47, 0x6f, 0x32, 0x47, 0x6b, 0x45, 0x34, +0x73, 0x59, 0x75, 0x66, 0x32, 0x6e, 0x75, 0x66, 0x5a, 0x42, 0x73, 0x42, 0x78, 0x2f, 0x56, 0x37, +0x77, 0x2f, 0x6e, 0x36, 0x41, 0x57, 0x35, 0x75, 0x4d, 0x42, 0x6b, 0x43, 0x77, 0x6f, 0x36, 0x72, +0x59, 0x47, 0x49, 0x31, 0x52, 0x47, 0x72, 0x52, 0x64, 0x38, 0x59, 0x6a, 0x31, 0x36, 0x38, 0x2b, +0x6f, 0x64, 0x32, 0x65, 0x41, 0x6c, 0x49, 0x67, 0x6c, 0x53, 0x38, 0x41, 0x45, 0x79, 0x68, 0x77, +0x6d, 0x6f, 0x78, 0x47, 0x77, 0x33, 0x57, 0x56, 0x77, 0x57, 0x4e, 0x55, 0x72, 0x6b, 0x39, 0x55, +0x41, 0x35, 0x4b, 0x70, 0x69, 0x2b, 0x38, 0x4c, 0x74, 0x6b, 0x65, 0x45, 0x2b, 0x6c, 0x39, 0x4a, +0x75, 0x76, 0x64, 0x56, 0x32, 0x66, 0x5a, 0x52, 0x34, 0x39, 0x46, 0x71, 0x4d, 0x72, 0x73, 0x55, +0x51, 0x6a, 0x46, 0x6a, 0x53, 0x32, 0x6f, 0x79, 0x34, 0x64, 0x39, 0x42, 0x5a, 0x4d, 0x6e, 0x38, +0x53, 0x4c, 0x7a, 0x4b, 0x45, 0x4b, 0x79, 0x64, 0x38, 0x52, 0x41, 0x79, 0x4b, 0x4d, 0x57, 0x59, +0x67, 0x78, 0x6f, 0x7a, 0x45, 0x30, 0x42, 0x66, 0x4d, 0x43, 0x45, 0x77, 0x69, 0x68, 0x58, 0x6c, +0x2b, 0x4f, 0x4c, 0x2b, 0x59, 0x2f, 0x6a, 0x51, 0x6e, 0x39, 0x4b, 0x43, 0x71, 0x47, 0x68, 0x48, +0x44, 0x2b, 0x62, 0x33, 0x74, 0x51, 0x4c, 0x49, 0x79, 0x56, 0x69, 0x69, 0x42, 0x62, 0x33, 0x77, +0x61, 0x4f, 0x6a, 0x65, 0x54, 0x46, 0x38, 0x33, 0x6a, 0x6a, 0x4e, 0x46, 0x6e, 0x63, 0x4e, 0x65, +0x58, 0x64, 0x2b, 0x45, 0x62, 0x6e, 0x30, 0x2f, 0x72, 0x50, 0x73, 0x56, 0x45, 0x54, 0x42, 0x72, +0x6c, 0x44, 0x61, 0x59, 0x41, 0x36, 0x39, 0x62, 0x5a, 0x48, 0x57, 0x68, 0x2b, 0x6a, 0x4b, 0x70, +0x72, 0x61, 0x79, 0x73, 0x61, 0x32, 0x4e, 0x54, 0x63, 0x54, 0x6e, 0x56, 0x5a, 0x47, 0x51, 0x59, +0x76, 0x4e, 0x4d, 0x43, 0x4d, 0x33, 0x32, 0x6b, 0x35, 0x75, 0x34, 0x39, 0x63, 0x53, 0x48, 0x46, +0x68, 0x47, 0x77, 0x38, 0x39, 0x63, 0x77, 0x44, 0x56, 0x76, 0x52, 0x75, 0x59, 0x74, 0x37, 0x69, +0x47, 0x52, 0x48, 0x49, 0x73, 0x66, 0x58, 0x74, 0x74, 0x34, 0x59, 0x6a, 0x39, 0x76, 0x2b, 0x48, +0x2b, 0x70, 0x2f, 0x38, 0x41, 0x50, 0x4d, 0x64, 0x4c, 0x72, 0x33, 0x35, 0x4a, 0x7a, 0x54, 0x35, +0x48, 0x55, 0x6c, 0x2b, 0x2f, 0x67, 0x4e, 0x6e, 0x43, 0x51, 0x38, 0x6f, 0x4a, 0x52, 0x4c, 0x2b, +0x62, 0x54, 0x33, 0x74, 0x43, 0x30, 0x75, 0x6e, 0x76, 0x53, 0x61, 0x79, 0x78, 0x46, 0x61, 0x4d, +0x54, 0x46, 0x4a, 0x51, 0x32, 0x49, 0x4b, 0x53, 0x6b, 0x6f, 0x4b, 0x51, 0x45, 0x49, 0x52, 0x56, +0x78, 0x4c, 0x31, 0x67, 0x56, 0x67, 0x41, 0x2f, 0x65, 0x73, 0x36, 0x33, 0x74, 0x75, 0x32, 0x38, +0x62, 0x4f, 0x6a, 0x73, 0x67, 0x34, 0x52, 0x74, 0x2b, 0x4e, 0x2b, 0x52, 0x6c, 0x39, 0x69, 0x70, +0x70, 0x4a, 0x69, 0x70, 0x33, 0x78, 0x30, 0x68, 0x42, 0x76, 0x67, 0x69, 0x32, 0x4a, 0x72, 0x64, +0x72, 0x2b, 0x66, 0x48, 0x2b, 0x2f, 0x52, 0x6b, 0x38, 0x65, 0x33, 0x61, 0x36, 0x39, 0x32, 0x74, +0x72, 0x74, 0x38, 0x4b, 0x50, 0x77, 0x73, 0x65, 0x59, 0x47, 0x4f, 0x61, 0x34, 0x45, 0x7a, 0x41, +0x58, 0x6e, 0x64, 0x2f, 0x7a, 0x46, 0x43, 0x41, 0x59, 0x42, 0x57, 0x57, 0x67, 0x31, 0x4e, 0x38, +0x30, 0x2b, 0x6f, 0x77, 0x36, 0x58, 0x4c, 0x48, 0x7a, 0x74, 0x4b, 0x6e, 0x30, 0x4c, 0x68, 0x35, +0x4d, 0x34, 0x6f, 0x54, 0x6c, 0x2b, 0x4d, 0x61, 0x6e, 0x61, 0x70, 0x74, 0x76, 0x56, 0x57, 0x49, +0x7a, 0x30, 0x79, 0x2b, 0x59, 0x41, 0x6a, 0x68, 0x6a, 0x6b, 0x54, 0x58, 0x75, 0x78, 0x57, 0x6b, +0x58, 0x77, 0x79, 0x69, 0x4e, 0x72, 0x77, 0x6a, 0x6a, 0x70, 0x58, 0x51, 0x35, 0x44, 0x5a, 0x33, +0x6c, 0x4e, 0x43, 0x55, 0x4c, 0x30, 0x7a, 0x59, 0x41, 0x64, 0x2b, 0x4a, 0x72, 0x5a, 0x32, 0x42, +0x7a, 0x42, 0x71, 0x6f, 0x4d, 0x46, 0x4a, 0x72, 0x43, 0x41, 0x6f, 0x37, 0x2f, 0x31, 0x48, 0x42, +0x38, 0x36, 0x6d, 0x55, 0x6f, 0x4f, 0x4b, 0x50, 0x37, 0x2b, 0x4f, 0x76, 0x67, 0x65, 0x52, 0x4d, +0x2b, 0x62, 0x37, 0x54, 0x68, 0x36, 0x53, 0x73, 0x76, 0x52, 0x77, 0x67, 0x66, 0x36, 0x57, 0x66, +0x50, 0x2b, 0x2b, 0x30, 0x49, 0x51, 0x4c, 0x6a, 0x74, 0x77, 0x56, 0x77, 0x44, 0x45, 0x4c, 0x69, +0x71, 0x42, 0x7a, 0x6f, 0x56, 0x55, 0x6e, 0x63, 0x4a, 0x53, 0x7a, 0x6b, 0x58, 0x58, 0x65, 0x4f, +0x6e, 0x55, 0x4d, 0x36, 0x64, 0x4f, 0x68, 0x4b, 0x4d, 0x41, 0x50, 0x79, 0x30, 0x73, 0x64, 0x76, +0x4b, 0x70, 0x30, 0x4e, 0x33, 0x51, 0x71, 0x59, 0x39, 0x71, 0x57, 0x4b, 0x44, 0x39, 0x58, 0x54, +0x46, 0x32, 0x41, 0x5a, 0x67, 0x79, 0x36, 0x78, 0x50, 0x36, 0x48, 0x6a, 0x68, 0x4a, 0x59, 0x77, +0x78, 0x35, 0x4e, 0x56, 0x55, 0x41, 0x38, 0x50, 0x43, 0x58, 0x6a, 0x39, 0x73, 0x41, 0x48, 0x4b, +0x4f, 0x59, 0x47, 0x6a, 0x76, 0x43, 0x39, 0x63, 0x41, 0x5a, 0x46, 0x62, 0x38, 0x48, 0x6b, 0x59, +0x41, 0x51, 0x68, 0x68, 0x41, 0x55, 0x78, 0x51, 0x44, 0x36, 0x4d, 0x52, 0x45, 0x32, 0x6e, 0x2b, +0x6b, 0x4b, 0x6e, 0x4d, 0x6c, 0x5a, 0x58, 0x6b, 0x51, 0x73, 0x78, 0x56, 0x34, 0x49, 0x4d, 0x61, +0x63, 0x42, 0x6c, 0x52, 0x67, 0x6c, 0x71, 0x7a, 0x42, 0x50, 0x44, 0x6f, 0x4e, 0x4d, 0x32, 0x39, +0x75, 0x68, 0x67, 0x47, 0x6e, 0x5a, 0x31, 0x56, 0x59, 0x64, 0x48, 0x61, 0x43, 0x43, 0x38, 0x66, +0x62, 0x76, 0x37, 0x2f, 0x32, 0x41, 0x38, 0x5a, 0x58, 0x37, 0x63, 0x47, 0x78, 0x77, 0x34, 0x36, +0x6c, 0x4a, 0x64, 0x56, 0x43, 0x6d, 0x39, 0x2f, 0x47, 0x30, 0x4e, 0x4b, 0x68, 0x76, 0x4c, 0x48, +0x79, 0x44, 0x54, 0x36, 0x73, 0x2b, 0x7a, 0x42, 0x45, 0x63, 0x54, 0x58, 0x64, 0x6f, 0x4a, 0x53, +0x5a, 0x59, 0x66, 0x35, 0x41, 0x2b, 0x45, 0x4e, 0x33, 0x48, 0x55, 0x50, 0x68, 0x33, 0x54, 0x64, +0x68, 0x31, 0x74, 0x58, 0x53, 0x75, 0x44, 0x56, 0x4b, 0x5a, 0x2b, 0x66, 0x78, 0x50, 0x50, 0x6a, +0x4d, 0x54, 0x37, 0x6e, 0x76, 0x6a, 0x39, 0x4f, 0x49, 0x52, 0x35, 0x4c, 0x38, 0x2f, 0x4c, 0x41, +0x76, 0x36, 0x65, 0x69, 0x45, 0x55, 0x55, 0x4e, 0x58, 0x55, 0x6c, 0x7a, 0x51, 0x53, 0x72, 0x4a, +0x44, 0x38, 0x4e, 0x53, 0x72, 0x45, 0x39, 0x6c, 0x55, 0x58, 0x34, 0x56, 0x64, 0x50, 0x37, 0x4e, +0x62, 0x4f, 0x51, 0x6c, 0x6c, 0x69, 0x43, 0x68, 0x4a, 0x56, 0x46, 0x6d, 0x62, 0x68, 0x34, 0x63, +0x68, 0x7a, 0x37, 0x4d, 0x4d, 0x66, 0x44, 0x4b, 0x56, 0x78, 0x32, 0x32, 0x58, 0x7a, 0x4f, 0x53, +0x52, 0x44, 0x2f, 0x71, 0x78, 0x65, 0x76, 0x48, 0x48, 0x53, 0x4b, 0x55, 0x34, 0x38, 0x2b, 0x64, +0x66, 0x38, 0x63, 0x59, 0x30, 0x75, 0x39, 0x37, 0x53, 0x32, 0x75, 0x78, 0x78, 0x31, 0x35, 0x39, +0x73, 0x44, 0x31, 0x4a, 0x51, 0x61, 0x48, 0x6a, 0x73, 0x45, 0x63, 0x4f, 0x67, 0x77, 0x53, 0x63, +0x54, 0x34, 0x61, 0x51, 0x65, 0x68, 0x2b, 0x2b, 0x65, 0x35, 0x37, 0x48, 0x66, 0x47, 0x57, 0x65, +0x67, 0x39, 0x39, 0x33, 0x58, 0x76, 0x58, 0x38, 0x4b, 0x70, 0x47, 0x52, 0x64, 0x69, 0x63, 0x2b, +0x67, 0x69, 0x63, 0x64, 0x75, 0x74, 0x2f, 0x49, 0x48, 0x50, 0x61, 0x62, 0x57, 0x32, 0x71, 0x4c, +0x51, 0x6a, 0x72, 0x37, 0x38, 0x59, 0x4c, 0x57, 0x6b, 0x61, 0x71, 0x79, 0x67, 0x39, 0x65, 0x67, +0x36, 0x4b, 0x72, 0x61, 0x75, 0x49, 0x57, 0x2b, 0x46, 0x49, 0x50, 0x71, 0x35, 0x54, 0x36, 0x52, +0x6a, 0x4f, 0x2f, 0x6e, 0x6e, 0x61, 0x34, 0x54, 0x78, 0x4c, 0x4f, 0x6b, 0x6f, 0x59, 0x37, 0x79, +0x79, 0x2b, 0x67, 0x4a, 0x2b, 0x4f, 0x2f, 0x70, 0x75, 0x49, 0x74, 0x35, 0x57, 0x6c, 0x43, 0x35, +0x48, 0x71, 0x6e, 0x4c, 0x2b, 0x76, 0x75, 0x77, 0x30, 0x32, 0x68, 0x4e, 0x35, 0x2b, 0x46, 0x37, +0x41, 0x79, 0x39, 0x74, 0x47, 0x41, 0x79, 0x6b, 0x68, 0x6f, 0x76, 0x46, 0x39, 0x4f, 0x2f, 0x38, +0x32, 0x72, 0x76, 0x4a, 0x72, 0x59, 0x7a, 0x42, 0x39, 0x68, 0x78, 0x43, 0x2f, 0x2f, 0x45, 0x59, +0x77, 0x6d, 0x6b, 0x35, 0x6a, 0x4d, 0x45, 0x6c, 0x58, 0x43, 0x62, 0x57, 0x31, 0x67, 0x73, 0x65, +0x69, 0x51, 0x45, 0x53, 0x47, 0x38, 0x2b, 0x48, 0x4d, 0x39, 0x7a, 0x72, 0x7a, 0x33, 0x67, 0x65, +0x34, 0x61, 0x66, 0x4b, 0x68, 0x59, 0x59, 0x57, 0x33, 0x44, 0x59, 0x41, 0x4d, 0x72, 0x31, 0x71, +0x49, 0x45, 0x41, 0x56, 0x50, 0x2b, 0x6a, 0x49, 0x55, 0x4c, 0x52, 0x45, 0x4f, 0x4a, 0x39, 0x59, +0x5a, 0x44, 0x55, 0x75, 0x67, 0x44, 0x36, 0x47, 0x31, 0x64, 0x70, 0x58, 0x66, 0x54, 0x73, 0x64, +0x77, 0x6d, 0x6e, 0x34, 0x57, 0x35, 0x48, 0x49, 0x4e, 0x69, 0x54, 0x51, 0x49, 0x43, 0x64, 0x6d, +0x69, 0x75, 0x44, 0x6b, 0x6a, 0x67, 0x4a, 0x7a, 0x30, 0x36, 0x31, 0x68, 0x32, 0x55, 0x31, 0x5a, +0x6c, 0x58, 0x6a, 0x6a, 0x35, 0x57, 0x45, 0x62, 0x64, 0x65, 0x52, 0x76, 0x61, 0x47, 0x4a, 0x5a, +0x66, 0x64, 0x7a, 0x33, 0x74, 0x37, 0x30, 0x2f, 0x74, 0x64, 0x75, 0x71, 0x57, 0x6c, 0x35, 0x64, +0x48, 0x38, 0x78, 0x39, 0x2b, 0x77, 0x74, 0x77, 0x42, 0x55, 0x63, 0x61, 0x49, 0x2b, 0x30, 0x6a, +0x34, 0x39, 0x51, 0x35, 0x6c, 0x64, 0x70, 0x75, 0x4f, 0x2b, 0x4d, 0x4a, 0x74, 0x51, 0x43, 0x4c, +0x53, 0x39, 0x38, 0x48, 0x32, 0x61, 0x6c, 0x4a, 0x52, 0x4c, 0x41, 0x66, 0x77, 0x46, 0x73, 0x2b, +0x68, 0x39, 0x66, 0x2b, 0x6f, 0x79, 0x71, 0x78, 0x31, 0x42, 0x39, 0x41, 0x62, 0x59, 0x33, 0x61, +0x43, 0x4e, 0x39, 0x37, 0x43, 0x50, 0x50, 0x45, 0x59, 0x70, 0x72, 0x6d, 0x70, 0x35, 0x34, 0x71, +0x59, 0x67, 0x7a, 0x4a, 0x71, 0x73, 0x6f, 0x64, 0x77, 0x76, 0x73, 0x4e, 0x2f, 0x66, 0x65, 0x4e, +0x7a, 0x30, 0x31, 0x63, 0x33, 0x55, 0x74, 0x64, 0x57, 0x78, 0x36, 0x45, 0x31, 0x68, 0x31, 0x4b, +0x53, 0x56, 0x38, 0x4a, 0x44, 0x38, 0x78, 0x35, 0x69, 0x32, 0x62, 0x5a, 0x6c, 0x56, 0x71, 0x52, +0x54, 0x71, 0x64, 0x41, 0x47, 0x30, 0x41, 0x57, 0x6c, 0x37, 0x45, 0x61, 0x48, 0x76, 0x75, 0x66, +0x77, 0x59, 0x66, 0x4f, 0x41, 0x6a, 0x63, 0x54, 0x39, 0x39, 0x5a, 0x69, 0x36, 0x2f, 0x67, 0x69, +0x6c, 0x71, 0x61, 0x73, 0x76, 0x59, 0x39, 0x6f, 0x2f, 0x39, 0x75, 0x56, 0x6e, 0x68, 0x33, 0x35, +0x4f, 0x52, 0x38, 0x49, 0x4c, 0x52, 0x53, 0x34, 0x53, 0x4c, 0x52, 0x47, 0x4b, 0x43, 0x33, 0x32, +0x4b, 0x69, 0x39, 0x6f, 0x67, 0x6b, 0x6c, 0x37, 0x58, 0x6c, 0x32, 0x35, 0x5a, 0x4d, 0x79, 0x44, +0x52, 0x41, 0x75, 0x34, 0x38, 0x4c, 0x59, 0x54, 0x68, 0x4d, 0x57, 0x76, 0x4f, 0x53, 0x4f, 0x71, +0x57, 0x39, 0x65, 0x4c, 0x61, 0x43, 0x31, 0x2f, 0x6a, 0x6a, 0x67, 0x64, 0x2f, 0x7a, 0x58, 0x63, +0x31, 0x41, 0x46, 0x38, 0x41, 0x6d, 0x71, 0x53, 0x4d, 0x49, 0x6f, 0x52, 0x68, 0x5a, 0x47, 0x6b, +0x39, 0x74, 0x39, 0x78, 0x58, 0x51, 0x76, 0x6d, 0x41, 0x34, 0x6e, 0x52, 0x68, 0x6c, 0x38, 0x34, +0x35, 0x52, 0x47, 0x73, 0x33, 0x38, 0x6b, 0x73, 0x62, 0x38, 0x65, 0x6a, 0x73, 0x7a, 0x48, 0x72, +0x2f, 0x2f, 0x34, 0x77, 0x53, 0x50, 0x44, 0x67, 0x35, 0x44, 0x36, 0x46, 0x65, 0x78, 0x33, 0x2f, +0x37, 0x35, 0x53, 0x79, 0x30, 0x4f, 0x74, 0x7a, 0x59, 0x31, 0x4e, 0x47, 0x57, 0x49, 0x38, 0x71, +0x48, 0x4d, 0x2f, 0x76, 0x32, 0x32, 0x56, 0x43, 0x51, 0x52, 0x71, 0x6d, 0x33, 0x53, 0x4d, 0x47, +0x66, 0x76, 0x78, 0x4c, 0x6b, 0x6c, 0x2f, 0x71, 0x38, 0x2b, 0x33, 0x63, 0x66, 0x6d, 0x53, 0x2b, +0x49, 0x62, 0x4e, 0x74, 0x2b, 0x2b, 0x71, 0x45, 0x31, 0x55, 0x6b, 0x58, 0x44, 0x65, 0x66, 0x32, +0x54, 0x69, 0x79, 0x39, 0x6d, 0x56, 0x63, 0x74, 0x49, 0x6a, 0x68, 0x72, 0x34, 0x4f, 0x68, 0x69, +0x66, 0x4e, 0x39, 0x64, 0x4f, 0x35, 0x75, 0x57, 0x56, 0x4a, 0x2b, 0x43, 0x54, 0x64, 0x70, 0x59, +0x4a, 0x6b, 0x41, 0x41, 0x6b, 0x56, 0x41, 0x31, 0x64, 0x77, 0x57, 0x31, 0x33, 0x31, 0x37, 0x42, +0x2b, 0x73, 0x33, 0x41, 0x45, 0x48, 0x2b, 0x35, 0x71, 0x4d, 0x76, 0x51, 0x45, 0x54, 0x50, 0x6f, +0x7a, 0x4e, 0x30, 0x77, 0x66, 0x33, 0x44, 0x2b, 0x50, 0x56, 0x78, 0x37, 0x38, 0x68, 0x70, 0x61, +0x6d, 0x79, 0x57, 0x48, 0x35, 0x43, 0x59, 0x37, 0x48, 0x4c, 0x37, 0x30, 0x67, 0x6f, 0x2b, 0x4b, +0x4c, 0x39, 0x45, 0x68, 0x41, 0x42, 0x76, 0x4c, 0x68, 0x30, 0x76, 0x6b, 0x43, 0x51, 0x44, 0x49, +0x70, 0x77, 0x33, 0x43, 0x6b, 0x38, 0x37, 0x6e, 0x6f, 0x6b, 0x52, 0x74, 0x4a, 0x70, 0x55, 0x4b, +0x39, 0x66, 0x73, 0x2b, 0x68, 0x31, 0x4b, 0x53, 0x43, 0x2f, 0x4c, 0x66, 0x78, 0x45, 0x38, 0x72, +0x6a, 0x78, 0x36, 0x68, 0x69, 0x68, 0x33, 0x6e, 0x70, 0x6a, 0x6c, 0x47, 0x50, 0x50, 0x4d, 0x6a, +0x36, 0x5a, 0x35, 0x39, 0x48, 0x4b, 0x38, 0x32, 0x6f, 0x42, 0x78, 0x38, 0x49, 0x47, 0x36, 0x4c, +0x67, 0x43, 0x4b, 0x59, 0x38, 0x41, 0x55, 0x6c, 0x35, 0x4a, 0x42, 0x43, 0x56, 0x4b, 0x39, 0x42, +0x69, 0x39, 0x59, 0x38, 0x71, 0x2f, 0x35, 0x34, 0x61, 0x53, 0x54, 0x38, 0x67, 0x66, 0x69, 0x4e, +0x63, 0x65, 0x62, 0x52, 0x6b, 0x62, 0x57, 0x75, 0x61, 0x66, 0x68, 0x52, 0x5a, 0x75, 0x68, 0x64, +0x75, 0x49, 0x78, 0x6e, 0x6a, 0x56, 0x49, 0x47, 0x56, 0x51, 0x47, 0x6a, 0x46, 0x38, 0x48, 0x4c, +0x46, 0x72, 0x4c, 0x73, 0x67, 0x70, 0x76, 0x55, 0x45, 0x7a, 0x4c, 0x61, 0x58, 0x34, 0x42, 0x2f, +0x7a, 0x4d, 0x56, 0x39, 0x39, 0x41, 0x52, 0x55, 0x56, 0x55, 0x46, 0x4a, 0x73, 0x73, 0x55, 0x54, +0x58, 0x32, 0x68, 0x46, 0x63, 0x6e, 0x64, 0x68, 0x46, 0x46, 0x73, 0x71, 0x59, 0x38, 0x59, 0x4b, +0x65, 0x35, 0x31, 0x46, 0x64, 0x58, 0x45, 0x31, 0x78, 0x74, 0x44, 0x6a, 0x63, 0x76, 0x32, 0x37, +0x47, 0x71, 0x68, 0x6d, 0x38, 0x76, 0x75, 0x5a, 0x31, 0x6c, 0x46, 0x61, 0x6b, 0x52, 0x49, 0x70, +0x6f, 0x50, 0x4d, 0x72, 0x49, 0x69, 0x70, 0x45, 0x6f, 0x6f, 0x38, 0x49, 0x52, 0x51, 0x42, 0x65, +0x55, 0x30, 0x69, 0x6e, 0x68, 0x37, 0x45, 0x6a, 0x34, 0x45, 0x6c, 0x41, 0x69, 0x51, 0x6d, 0x48, +0x52, 0x51, 0x4f, 0x4c, 0x39, 0x65, 0x7a, 0x47, 0x34, 0x49, 0x6f, 0x61, 0x57, 0x48, 0x69, 0x76, +0x71, 0x44, 0x2b, 0x61, 0x42, 0x6c, 0x2f, 0x59, 0x6c, 0x6b, 0x66, 0x4b, 0x49, 0x65, 0x44, 0x36, +0x2b, 0x44, 0x36, 0x6b, 0x55, 0x52, 0x43, 0x4d, 0x70, 0x6b, 0x72, 0x35, 0x48, 0x4a, 0x43, 0x71, +0x77, 0x55, 0x4a, 0x42, 0x56, 0x42, 0x65, 0x37, 0x58, 0x75, 0x79, 0x69, 0x4e, 0x76, 0x41, 0x72, +0x74, 0x4f, 0x48, 0x69, 0x48, 0x76, 0x77, 0x72, 0x44, 0x6e, 0x45, 0x55, 0x2f, 0x70, 0x61, 0x49, +0x34, 0x78, 0x61, 0x50, 0x50, 0x6a, 0x4b, 0x4f, 0x38, 0x4c, 0x4d, 0x4a, 0x2f, 0x50, 0x6f, 0x73, +0x51, 0x34, 0x42, 0x78, 0x78, 0x6b, 0x65, 0x44, 0x4d, 0x36, 0x76, 0x66, 0x59, 0x6d, 0x2f, 0x2f, +0x51, 0x65, 0x58, 0x4d, 0x48, 0x54, 0x5a, 0x32, 0x75, 0x35, 0x58, 0x59, 0x56, 0x4f, 0x78, 0x7a, +0x36, 0x4f, 0x33, 0x45, 0x51, 0x37, 0x57, 0x54, 0x44, 0x33, 0x70, 0x38, 0x2f, 0x6e, 0x79, 0x75, +0x42, 0x70, 0x6a, 0x7a, 0x4a, 0x4b, 0x37, 0x2b, 0x71, 0x5a, 0x75, 0x36, 0x49, 0x4f, 0x4e, 0x58, +0x4f, 0x70, 0x54, 0x6c, 0x55, 0x31, 0x58, 0x55, 0x73, 0x68, 0x54, 0x49, 0x53, 0x6f, 0x58, 0x4e, +0x51, 0x61, 0x6b, 0x65, 0x36, 0x5a, 0x61, 0x4c, 0x55, 0x55, 0x69, 0x6d, 0x6b, 0x45, 0x54, 0x42, +0x49, 0x45, 0x42, 0x4d, 0x43, 0x55, 0x37, 0x72, 0x39, 0x39, 0x43, 0x4f, 0x70, 0x45, 0x54, 0x70, +0x43, 0x64, 0x54, 0x46, 0x68, 0x37, 0x37, 0x35, 0x34, 0x36, 0x35, 0x48, 0x4d, 0x33, 0x33, 0x4b, +0x45, 0x6e, 0x52, 0x59, 0x49, 0x47, 0x46, 0x4c, 0x6d, 0x4b, 0x72, 0x30, 0x42, 0x70, 0x54, 0x79, +0x55, 0x73, 0x63, 0x61, 0x6d, 0x41, 0x43, 0x71, 0x52, 0x79, 0x74, 0x43, 0x37, 0x56, 0x77, 0x51, +0x6c, 0x49, 0x38, 0x36, 0x53, 0x48, 0x75, 0x78, 0x4f, 0x36, 0x79, 0x46, 0x56, 0x4e, 0x46, 0x53, +0x55, 0x73, 0x76, 0x4c, 0x6f, 0x6f, 0x4a, 0x56, 0x42, 0x42, 0x73, 0x4e, 0x69, 0x4d, 0x74, 0x52, +0x30, 0x33, 0x66, 0x57, 0x38, 0x68, 0x2f, 0x2f, 0x47, 0x2f, 0x61, 0x65, 0x66, 0x67, 0x70, 0x4b, +0x32, 0x30, 0x74, 0x74, 0x31, 0x66, 0x32, 0x57, 0x76, 0x4b, 0x71, 0x31, 0x4a, 0x41, 0x4e, 0x44, +0x70, 0x2b, 0x30, 0x69, 0x70, 0x4b, 0x53, 0x71, 0x4d, 0x57, 0x6e, 0x35, 0x42, 0x52, 0x6b, 0x4c, +0x72, 0x66, 0x33, 0x42, 0x34, 0x6e, 0x72, 0x55, 0x42, 0x52, 0x50, 0x74, 0x56, 0x6f, 0x36, 0x57, +0x56, 0x71, 0x54, 0x4d, 0x71, 0x47, 0x4d, 0x4a, 0x62, 0x65, 0x62, 0x48, 0x71, 0x33, 0x6e, 0x48, +0x62, 0x51, 0x4b, 0x6b, 0x6f, 0x6b, 0x63, 0x67, 0x41, 0x6f, 0x44, 0x4e, 0x62, 0x46, 0x54, 0x73, +0x6d, 0x75, 0x31, 0x58, 0x46, 0x6c, 0x6c, 0x49, 0x53, 0x6a, 0x36, 0x66, 0x33, 0x75, 0x53, 0x67, +0x59, 0x4e, 0x5a, 0x4a, 0x52, 0x74, 0x39, 0x2b, 0x53, 0x48, 0x71, 0x47, 0x52, 0x52, 0x6f, 0x4b, +0x44, 0x4a, 0x63, 0x6e, 0x4d, 0x75, 0x50, 0x32, 0x76, 0x35, 0x5a, 0x38, 0x47, 0x32, 0x4a, 0x71, +0x55, 0x46, 0x4d, 0x61, 0x71, 0x69, 0x57, 0x6c, 0x42, 0x33, 0x46, 0x50, 0x49, 0x69, 0x43, 0x42, +0x50, 0x43, 0x55, 0x52, 0x45, 0x49, 0x43, 0x4d, 0x53, 0x45, 0x58, 0x55, 0x6f, 0x66, 0x6a, 0x53, +0x74, 0x79, 0x72, 0x79, 0x6c, 0x55, 0x38, 0x45, 0x6d, 0x38, 0x44, 0x71, 0x6d, 0x48, 0x57, 0x58, +0x30, 0x75, 0x65, 0x39, 0x6c, 0x30, 0x55, 0x6c, 0x6b, 0x33, 0x50, 0x64, 0x30, 0x42, 0x6b, 0x64, +0x52, 0x30, 0x38, 0x61, 0x77, 0x68, 0x55, 0x33, 0x4b, 0x4a, 0x4b, 0x4f, 0x75, 0x48, 0x4a, 0x55, +0x47, 0x37, 0x33, 0x4c, 0x42, 0x75, 0x5a, 0x42, 0x4f, 0x63, 0x76, 0x64, 0x46, 0x30, 0x4c, 0x47, +0x77, 0x2b, 0x39, 0x2f, 0x65, 0x34, 0x66, 0x43, 0x78, 0x4a, 0x48, 0x49, 0x45, 0x6d, 0x41, 0x57, +0x63, 0x7a, 0x30, 0x2f, 0x4a, 0x35, 0x73, 0x63, 0x69, 0x70, 0x4f, 0x6b, 0x2f, 0x37, 0x62, 0x36, +0x64, 0x68, 0x78, 0x33, 0x2b, 0x46, 0x77, 0x48, 0x48, 0x35, 0x6b, 0x53, 0x79, 0x4f, 0x77, 0x52, +0x56, 0x30, 0x2f, 0x55, 0x6c, 0x67, 0x6c, 0x69, 0x38, 0x77, 0x57, 0x33, 0x73, 0x77, 0x6a, 0x34, +0x75, 0x6c, 0x45, 0x36, 0x79, 0x58, 0x7a, 0x4f, 0x54, 0x44, 0x4d, 0x77, 0x6c, 0x41, 0x76, 0x4e, +0x63, 0x72, 0x4b, 0x34, 0x35, 0x41, 0x61, 0x76, 0x77, 0x2b, 0x32, 0x4e, 0x51, 0x36, 0x75, 0x43, +0x48, 0x69, 0x72, 0x43, 0x71, 0x77, 0x70, 0x6d, 0x34, 0x58, 0x41, 0x51, 0x61, 0x32, 0x33, 0x59, +0x73, 0x2f, 0x55, 0x5a, 0x63, 0x30, 0x77, 0x47, 0x74, 0x4f, 0x70, 0x73, 0x55, 0x79, 0x30, 0x53, +0x68, 0x41, 0x35, 0x4a, 0x4d, 0x35, 0x76, 0x36, 0x4e, 0x52, 0x62, 0x6e, 0x6e, 0x4e, 0x4a, 0x4f, +0x4e, 0x6e, 0x6d, 0x56, 0x65, 0x63, 0x7a, 0x4d, 0x38, 0x38, 0x7a, 0x4e, 0x37, 0x4e, 0x47, 0x32, +0x64, 0x46, 0x42, 0x6f, 0x44, 0x41, 0x78, 0x6e, 0x33, 0x76, 0x51, 0x59, 0x4e, 0x59, 0x54, 0x4d, +0x37, 0x64, 0x68, 0x78, 0x79, 0x2f, 0x67, 0x64, 0x30, 0x4a, 0x69, 0x58, 0x4a, 0x70, 0x45, 0x39, +0x6e, 0x55, 0x74, 0x4b, 0x65, 0x39, 0x48, 0x6e, 0x70, 0x6d, 0x6d, 0x72, 0x4c, 0x53, 0x79, 0x53, +0x54, 0x2b, 0x45, 0x72, 0x68, 0x2b, 0x7a, 0x37, 0x4a, 0x5a, 0x4a, 0x4c, 0x64, 0x7a, 0x6a, 0x71, +0x72, 0x53, 0x2b, 0x34, 0x64, 0x79, 0x44, 0x73, 0x35, 0x43, 0x52, 0x74, 0x6a, 0x34, 0x30, 0x63, +0x6e, 0x45, 0x6f, 0x73, 0x52, 0x4b, 0x76, 0x42, 0x71, 0x69, 0x56, 0x58, 0x73, 0x2f, 0x56, 0x58, +0x58, 0x39, 0x4b, 0x76, 0x59, 0x75, 0x6a, 0x56, 0x4c, 0x46, 0x79, 0x4c, 0x54, 0x70, 0x72, 0x45, +0x6a, 0x52, 0x38, 0x57, 0x41, 0x41, 0x66, 0x39, 0x54, 0x2b, 0x52, 0x39, 0x78, 0x44, 0x6c, 0x30, +0x70, 0x36, 0x6c, 0x7a, 0x36, 0x50, 0x4c, 0x63, 0x59, 0x70, 0x31, 0x38, 0x56, 0x6a, 0x32, 0x4e, +0x79, 0x72, 0x42, 0x4b, 0x35, 0x70, 0x54, 0x66, 0x7a, 0x42, 0x35, 0x49, 0x35, 0x39, 0x30, 0x6d, +0x49, 0x79, 0x6d, 0x2b, 0x35, 0x2f, 0x66, 0x59, 0x61, 0x72, 0x72, 0x31, 0x32, 0x47, 0x56, 0x4f, +0x6e, 0x6a, 0x75, 0x62, 0x75, 0x75, 0x7a, 0x65, 0x68, 0x56, 0x47, 0x74, 0x47, 0x4e, 0x48, 0x4d, +0x4c, 0x52, 0x52, 0x46, 0x51, 0x78, 0x30, 0x4f, 0x2f, 0x4f, 0x6f, 0x73, 0x4a, 0x6b, 0x32, 0x44, +0x69, 0x75, 0x5a, 0x6d, 0x79, 0x76, 0x68, 0x47, 0x67, 0x6b, 0x36, 0x2b, 0x2b, 0x75, 0x6f, 0x6d, +0x39, 0x39, 0x6e, 0x4c, 0x52, 0x30, 0x61, 0x42, 0x62, 0x51, 0x64, 0x65, 0x41, 0x54, 0x6e, 0x56, +0x4e, 0x69, 0x49, 0x35, 0x61, 0x75, 0x32, 0x52, 0x31, 0x34, 0x51, 0x63, 0x4a, 0x33, 0x6e, 0x6c, +0x30, 0x41, 0x64, 0x51, 0x55, 0x51, 0x4f, 0x38, 0x69, 0x71, 0x31, 0x6f, 0x63, 0x4b, 0x68, 0x74, +0x72, 0x2b, 0x2b, 0x58, 0x56, 0x32, 0x32, 0x42, 0x56, 0x4b, 0x34, 0x4e, 0x75, 0x6d, 0x4d, 0x43, +0x73, 0x4d, 0x32, 0x76, 0x6f, 0x53, 0x43, 0x54, 0x34, 0x36, 0x62, 0x33, 0x6a, 0x71, 0x48, 0x38, +0x32, 0x2b, 0x2f, 0x56, 0x7a, 0x6b, 0x32, 0x4e, 0x37, 0x5a, 0x39, 0x58, 0x68, 0x74, 0x32, 0x52, +0x39, 0x58, 0x39, 0x31, 0x34, 0x55, 0x2f, 0x69, 0x66, 0x30, 0x61, 0x75, 0x76, 0x63, 0x68, 0x58, +0x4a, 0x74, 0x2f, 0x46, 0x49, 0x2b, 0x74, 0x6e, 0x33, 0x77, 0x6d, 0x63, 0x7a, 0x62, 0x39, 0x6d, +0x38, 0x4b, 0x43, 0x77, 0x45, 0x33, 0x33, 0x6f, 0x36, 0x37, 0x6b, 0x68, 0x42, 0x43, 0x4b, 0x70, +0x51, 0x35, 0x61, 0x37, 0x37, 0x38, 0x39, 0x64, 0x54, 0x37, 0x75, 0x48, 0x64, 0x7a, 0x37, 0x66, +0x77, 0x78, 0x6f, 0x66, 0x6e, 0x73, 0x54, 0x59, 0x46, 0x56, 0x78, 0x37, 0x7a, 0x47, 0x4a, 0x50, +0x48, 0x46, 0x54, 0x44, 0x70, 0x6d, 0x52, 0x73, 0x35, 0x5a, 0x50, 0x50, 0x78, 0x70, 0x46, 0x56, +0x31, 0x63, 0x78, 0x75, 0x7a, 0x47, 0x42, 0x30, 0x64, 0x44, 0x35, 0x4a, 0x37, 0x35, 0x4b, 0x72, +0x70, 0x5a, 0x74, 0x35, 0x6e, 0x6f, 0x36, 0x69, 0x61, 0x67, 0x5a, 0x57, 0x39, 0x75, 0x36, 0x61, +0x61, 0x73, 0x38, 0x43, 0x6a, 0x33, 0x58, 0x4d, 0x34, 0x76, 0x44, 0x58, 0x72, 0x65, 0x59, 0x6e, +0x57, 0x55, 0x4c, 0x56, 0x32, 0x51, 0x4a, 0x66, 0x77, 0x73, 0x31, 0x35, 0x77, 0x65, 0x32, 0x32, +0x4b, 0x68, 0x4a, 0x5a, 0x66, 0x6d, 0x70, 0x7a, 0x67, 0x73, 0x31, 0x46, 0x61, 0x77, 0x76, 0x43, +0x37, 0x78, 0x6c, 0x30, 0x44, 0x49, 0x35, 0x37, 0x49, 0x52, 0x70, 0x6e, 0x52, 0x49, 0x4d, 0x36, +0x45, 0x53, 0x43, 0x53, 0x49, 0x76, 0x7a, 0x73, 0x6c, 0x36, 0x44, 0x46, 0x64, 0x38, 0x32, 0x47, +0x76, 0x68, 0x77, 0x79, 0x74, 0x79, 0x66, 0x54, 0x6a, 0x55, 0x74, 0x76, 0x6c, 0x52, 0x46, 0x2f, +0x62, 0x4c, 0x62, 0x31, 0x2b, 0x43, 0x4b, 0x57, 0x6d, 0x5a, 0x45, 0x49, 0x7a, 0x6e, 0x6d, 0x64, +0x37, 0x2f, 0x63, 0x34, 0x57, 0x54, 0x76, 0x6e, 0x4a, 0x6d, 0x53, 0x79, 0x70, 0x58, 0x38, 0x48, +0x53, 0x7a, 0x61, 0x76, 0x5a, 0x62, 0x39, 0x68, 0x34, 0x53, 0x76, 0x4e, 0x4b, 0x57, 0x46, 0x43, +0x33, 0x68, 0x4d, 0x4b, 0x43, 0x51, 0x6b, 0x72, 0x7a, 0x53, 0x70, 0x69, 0x37, 0x65, 0x67, 0x35, +0x45, 0x59, 0x78, 0x44, 0x4c, 0x74, 0x30, 0x62, 0x46, 0x34, 0x57, 0x73, 0x71, 0x53, 0x47, 0x62, +0x48, 0x50, 0x79, 0x75, 0x64, 0x4d, 0x6a, 0x75, 0x51, 0x33, 0x44, 0x6f, 0x64, 0x63, 0x35, 0x4b, +0x61, 0x74, 0x31, 0x78, 0x77, 0x73, 0x36, 0x58, 0x57, 0x73, 0x4a, 0x73, 0x6b, 0x4b, 0x71, 0x33, +0x43, 0x31, 0x6c, 0x67, 0x36, 0x4f, 0x53, 0x69, 0x70, 0x72, 0x62, 0x74, 0x75, 0x34, 0x41, 0x6b, +0x6f, 0x6c, 0x4f, 0x43, 0x66, 0x46, 0x2f, 0x36, 0x4c, 0x70, 0x35, 0x34, 0x64, 0x7a, 0x43, 0x39, +0x2f, 0x57, 0x55, 0x6b, 0x38, 0x44, 0x72, 0x2f, 0x2f, 0x66, 0x56, 0x39, 0x32, 0x32, 0x36, 0x32, +0x41, 0x62, 0x37, 0x37, 0x70, 0x73, 0x4f, 0x68, 0x73, 0x46, 0x6b, 0x72, 0x73, 0x49, 0x57, 0x53, +0x4d, 0x6f, 0x77, 0x2f, 0x38, 0x6e, 0x49, 0x4d, 0x6e, 0x7a, 0x4d, 0x63, 0x55, 0x6e, 0x73, 0x50, +0x74, 0x6a, 0x2f, 0x38, 0x64, 0x61, 0x47, 0x66, 0x71, 0x31, 0x43, 0x4e, 0x63, 0x68, 0x6b, 0x55, +0x5a, 0x50, 0x33, 0x34, 0x6c, 0x65, 0x2b, 0x39, 0x39, 0x70, 0x62, 0x57, 0x73, 0x34, 0x6c, 0x44, +0x53, 0x6c, 0x79, 0x57, 0x52, 0x55, 0x37, 0x74, 0x48, 0x53, 0x61, 0x63, 0x74, 0x39, 0x62, 0x6a, +0x31, 0x79, 0x49, 0x47, 0x38, 0x2f, 0x54, 0x76, 0x6f, 0x50, 0x48, 0x4d, 0x45, 0x74, 0x37, 0x36, +0x7a, 0x48, 0x72, 0x55, 0x31, 0x69, 0x65, 0x79, 0x56, 0x68, 0x77, 0x72, 0x53, 0x58, 0x30, 0x72, +0x6b, 0x78, 0x67, 0x53, 0x69, 0x59, 0x68, 0x51, 0x50, 0x2f, 0x33, 0x49, 0x59, 0x52, 0x56, 0x47, +0x72, 0x2b, 0x58, 0x62, 0x6b, 0x58, 0x2b, 0x65, 0x79, 0x63, 0x54, 0x77, 0x38, 0x64, 0x4f, 0x59, +0x39, 0x58, 0x44, 0x4b, 0x7a, 0x68, 0x59, 0x6a, 0x38, 0x2f, 0x36, 0x47, 0x73, 0x55, 0x79, 0x38, +0x39, 0x79, 0x73, 0x58, 0x66, 0x34, 0x49, 0x32, 0x77, 0x52, 0x6b, 0x57, 0x44, 0x34, 0x74, 0x49, +0x72, 0x6a, 0x38, 0x74, 0x53, 0x55, 0x68, 0x62, 0x4f, 0x46, 0x69, 0x47, 0x30, 0x76, 0x5a, 0x39, +0x78, 0x36, 0x53, 0x4e, 0x6f, 0x6f, 0x50, 0x65, 0x63, 0x4f, 0x55, 0x54, 0x48, 0x6a, 0x63, 0x4f, +0x66, 0x4e, 0x51, 0x75, 0x39, 0x63, 0x43, 0x47, 0x52, 0x58, 0x58, 0x5a, 0x42, 0x74, 0x37, 0x51, +0x67, 0x76, 0x2f, 0x77, 0x79, 0x58, 0x41, 0x34, 0x6c, 0x59, 0x30, 0x6f, 0x52, 0x68, 0x46, 0x38, +0x33, 0x59, 0x77, 0x62, 0x6e, 0x6a, 0x62, 0x32, 0x61, 0x31, 0x30, 0x5a, 0x75, 0x34, 0x68, 0x63, +0x2f, 0x4f, 0x35, 0x69, 0x2b, 0x78, 0x39, 0x31, 0x4a, 0x68, 0x64, 0x41, 0x38, 0x74, 0x76, 0x66, +0x65, 0x6a, 0x4e, 0x72, 0x77, 0x48, 0x61, 0x2f, 0x74, 0x38, 0x79, 0x4b, 0x58, 0x4c, 0x6d, 0x69, +0x77, 0x4d, 0x49, 0x68, 0x53, 0x43, 0x4e, 0x38, 0x68, 0x33, 0x6d, 0x34, 0x6e, 0x70, 0x48, 0x2f, +0x39, 0x37, 0x65, 0x38, 0x41, 0x46, 0x42, 0x55, 0x56, 0x59, 0x51, 0x77, 0x6b, 0x6b, 0x77, 0x6f, +0x38, 0x51, 0x31, 0x46, 0x42, 0x49, 0x43, 0x65, 0x59, 0x73, 0x37, 0x53, 0x58, 0x63, 0x37, 0x61, +0x33, 0x57, 0x78, 0x51, 0x34, 0x6b, 0x6f, 0x50, 0x79, 0x41, 0x6b, 0x52, 0x79, 0x55, 0x4f, 0x35, +0x75, 0x6e, 0x32, 0x2b, 0x77, 0x49, 0x4e, 0x42, 0x74, 0x49, 0x32, 0x34, 0x44, 0x72, 0x4c, 0x53, +0x62, 0x4d, 0x5a, 0x59, 0x6c, 0x30, 0x52, 0x69, 0x6b, 0x43, 0x54, 0x59, 0x4d, 0x64, 0x64, 0x4d, +0x69, 0x37, 0x4d, 0x35, 0x44, 0x77, 0x73, 0x6d, 0x2f, 0x54, 0x66, 0x39, 0x69, 0x4f, 0x6d, 0x67, +0x6f, 0x4b, 0x79, 0x41, 0x6a, 0x2f, 0x42, 0x31, 0x48, 0x61, 0x65, 0x75, 0x33, 0x32, 0x50, 0x68, +0x50, 0x50, 0x63, 0x71, 0x68, 0x31, 0x4d, 0x61, 0x69, 0x31, 0x4e, 0x35, 0x67, 0x68, 0x55, 0x56, +0x38, 0x4a, 0x46, 0x35, 0x43, 0x45, 0x74, 0x57, 0x53, 0x53, 0x45, 0x48, 0x33, 0x4b, 0x50, 0x43, +0x32, 0x64, 0x72, 0x6a, 0x7a, 0x69, 0x48, 0x54, 0x34, 0x75, 0x53, 0x69, 0x75, 0x4e, 0x42, 0x35, +0x61, 0x57, 0x35, 0x52, 0x61, 0x4b, 0x70, 0x4e, 0x65, 0x63, 0x56, 0x47, 0x47, 0x42, 0x78, 0x39, +0x76, 0x68, 0x38, 0x71, 0x43, 0x43, 0x72, 0x77, 0x49, 0x61, 0x41, 0x47, 0x74, 0x72, 0x54, 0x78, +0x2f, 0x78, 0x6f, 0x50, 0x45, 0x38, 0x44, 0x6a, 0x37, 0x2b, 0x53, 0x75, 0x35, 0x2b, 0x64, 0x67, +0x70, 0x39, 0x43, 0x75, 0x74, 0x59, 0x74, 0x72, 0x6e, 0x30, 0x39, 0x6c, 0x6e, 0x38, 0x48, 0x6a, +0x32, 0x47, 0x62, 0x6f, 0x62, 0x33, 0x6a, 0x6d, 0x39, 0x77, 0x47, 0x2b, 0x44, 0x50, 0x69, 0x50, +0x73, 0x79, 0x4d, 0x75, 0x48, 0x36, 0x79, 0x66, 0x64, 0x34, 0x4f, 0x4b, 0x76, 0x37, 0x4a, 0x49, +0x6f, 0x31, 0x6d, 0x56, 0x66, 0x61, 0x34, 0x6b, 0x49, 0x30, 0x6b, 0x39, 0x4a, 0x5a, 0x77, 0x63, +0x49, 0x76, 0x43, 0x4d, 0x46, 0x62, 0x30, 0x78, 0x37, 0x49, 0x39, 0x44, 0x55, 0x68, 0x66, 0x71, +0x57, 0x65, 0x75, 0x78, 0x6d, 0x42, 0x52, 0x48, 0x41, 0x30, 0x4a, 0x6e, 0x71, 0x78, 0x4a, 0x63, +0x2b, 0x38, 0x56, 0x67, 0x65, 0x51, 0x76, 0x6f, 0x6b, 0x2f, 0x43, 0x51, 0x47, 0x51, 0x30, 0x65, +0x71, 0x6e, 0x66, 0x5a, 0x6b, 0x47, 0x77, 0x4d, 0x72, 0x4c, 0x59, 0x72, 0x36, 0x32, 0x39, 0x38, +0x75, 0x51, 0x36, 0x6d, 0x64, 0x4f, 0x50, 0x4c, 0x49, 0x4d, 0x71, 0x36, 0x37, 0x72, 0x70, 0x35, +0x4e, 0x6d, 0x33, 0x79, 0x53, 0x53, 0x51, 0x74, 0x6c, 0x42, 0x4a, 0x74, 0x38, 0x43, 0x68, 0x45, +0x6e, 0x53, 0x69, 0x66, 0x58, 0x2f, 0x50, 0x59, 0x66, 0x6a, 0x4e, 0x76, 0x6c, 0x43, 0x39, 0x61, +0x32, 0x78, 0x37, 0x6e, 0x6c, 0x30, 0x7a, 0x6a, 0x76, 0x2f, 0x51, 0x55, 0x43, 0x46, 0x72, 0x4f, +0x75, 0x4c, 0x6b, 0x45, 0x6b, 0x49, 0x74, 0x6c, 0x33, 0x33, 0x34, 0x38, 0x78, 0x70, 0x67, 0x46, +0x77, 0x4b, 0x4f, 0x6e, 0x39, 0x41, 0x76, 0x4e, 0x52, 0x7a, 0x79, 0x6a, 0x70, 0x62, 0x56, 0x64, +0x2f, 0x54, 0x70, 0x2b, 0x69, 0x69, 0x56, 0x78, 0x79, 0x59, 0x48, 0x38, 0x4b, 0x6f, 0x78, 0x48, +0x75, 0x4f, 0x6d, 0x34, 0x49, 0x54, 0x33, 0x2f, 0x64, 0x77, 0x4e, 0x73, 0x66, 0x31, 0x43, 0x49, +0x71, 0x38, 0x71, 0x31, 0x62, 0x37, 0x71, 0x59, 0x4f, 0x6a, 0x70, 0x30, 0x38, 0x6d, 0x49, 0x76, +0x32, 0x37, 0x78, 0x76, 0x4f, 0x7a, 0x61, 0x36, 0x59, 0x73, 0x59, 0x35, 0x50, 0x70, 0x38, 0x79, +0x41, 0x65, 0x36, 0x47, 0x78, 0x6f, 0x70, 0x6e, 0x72, 0x39, 0x30, 0x35, 0x77, 0x2b, 0x79, 0x75, +0x4e, 0x52, 0x4d, 0x53, 0x50, 0x51, 0x31, 0x6d, 0x44, 0x69, 0x6c, 0x4c, 0x58, 0x31, 0x47, 0x6b, +0x74, 0x34, 0x36, 0x6c, 0x61, 0x67, 0x75, 0x32, 0x62, 0x31, 0x6a, 0x53, 0x32, 0x70, 0x59, 0x56, +0x42, 0x6c, 0x46, 0x31, 0x52, 0x38, 0x4a, 0x56, 0x44, 0x71, 0x61, 0x76, 0x53, 0x4b, 0x48, 0x56, +0x30, 0x6c, 0x31, 0x30, 0x51, 0x58, 0x33, 0x79, 0x42, 0x2f, 0x50, 0x42, 0x44, 0x59, 0x70, 0x4d, +0x6e, 0x6b, 0x33, 0x7a, 0x6d, 0x47, 0x53, 0x4b, 0x44, 0x42, 0x2b, 0x4d, 0x4e, 0x47, 0x49, 0x6a, +0x34, 0x37, 0x38, 0x79, 0x73, 0x38, 0x41, 0x4f, 0x4f, 0x50, 0x65, 0x70, 0x55, 0x61, 0x64, 0x39, +0x2b, 0x34, 0x79, 0x54, 0x4d, 0x58, 0x6e, 0x65, 0x7a, 0x78, 0x2f, 0x77, 0x35, 0x30, 0x4e, 0x78, +0x47, 0x76, 0x6c, 0x61, 0x4d, 0x58, 0x37, 0x55, 0x45, 0x30, 0x35, 0x46, 0x67, 0x73, 0x6f, 0x6a, +0x78, 0x75, 0x6e, 0x63, 0x4d, 0x53, 0x57, 0x6d, 0x73, 0x69, 0x4b, 0x65, 0x32, 0x39, 0x6f, 0x36, +0x4f, 0x42, 0x41, 0x77, 0x65, 0x55, 0x45, 0x52, 0x6d, 0x31, 0x2f, 0x6e, 0x41, 0x6f, 0x2b, 0x76, +0x5a, 0x31, 0x4e, 0x42, 0x45, 0x56, 0x43, 0x76, 0x75, 0x75, 0x47, 0x56, 0x58, 0x75, 0x38, 0x46, +0x4c, 0x44, 0x36, 0x73, 0x51, 0x67, 0x65, 0x45, 0x72, 0x63, 0x46, 0x51, 0x42, 0x53, 0x44, 0x7a, +0x39, 0x50, 0x4c, 0x53, 0x32, 0x59, 0x34, 0x78, 0x32, 0x41, 0x71, 0x65, 0x61, 0x67, 0x69, 0x73, +0x75, 0x33, 0x65, 0x37, 0x7a, 0x6d, 0x61, 0x71, 0x38, 0x47, 0x30, 0x51, 0x39, 0x4f, 0x69, 0x69, +0x73, 0x32, 0x45, 0x35, 0x49, 0x47, 0x68, 0x6d, 0x36, 0x6c, 0x51, 0x75, 0x54, 0x46, 0x76, 0x51, +0x51, 0x57, 0x6a, 0x41, 0x67, 0x66, 0x30, 0x44, 0x6d, 0x54, 0x43, 0x4b, 0x72, 0x38, 0x55, 0x6c, +0x62, 0x32, 0x34, 0x56, 0x72, 0x41, 0x4c, 0x7a, 0x75, 0x77, 0x38, 0x39, 0x41, 0x6d, 0x65, 0x73, +0x36, 0x4e, 0x71, 0x52, 0x74, 0x4b, 0x30, 0x61, 0x41, 0x70, 0x36, 0x7a, 0x78, 0x4c, 0x31, 0x2b, +0x6b, 0x6a, 0x59, 0x44, 0x64, 0x6f, 0x4d, 0x41, 0x4f, 0x35, 0x75, 0x77, 0x57, 0x78, 0x56, 0x55, +0x6d, 0x77, 0x33, 0x41, 0x61, 0x45, 0x4a, 0x54, 0x75, 0x76, 0x6c, 0x2b, 0x41, 0x55, 0x73, 0x39, +0x5a, 0x61, 0x74, 0x73, 0x73, 0x48, 0x39, 0x67, 0x4d, 0x2b, 0x7a, 0x2f, 0x36, 0x61, 0x79, 0x37, +0x65, 0x2b, 0x30, 0x54, 0x6d, 0x31, 0x43, 0x33, 0x6d, 0x78, 0x54, 0x6d, 0x76, 0x38, 0x2b, 0x57, +0x61, 0x2b, 0x58, 0x79, 0x32, 0x62, 0x69, 0x37, 0x37, 0x44, 0x52, 0x76, 0x50, 0x68, 0x4d, 0x48, +0x6a, 0x59, 0x56, 0x32, 0x7a, 0x35, 0x66, 0x61, 0x71, 0x37, 0x64, 0x78, 0x35, 0x36, 0x34, 0x63, +0x74, 0x6c, 0x4d, 0x57, 0x64, 0x30, 0x54, 0x6d, 0x44, 0x4d, 0x62, 0x42, 0x2f, 0x64, 0x79, 0x55, +0x7a, 0x64, 0x66, 0x44, 0x2b, 0x45, 0x59, 0x39, 0x31, 0x75, 0x39, 0x63, 0x53, 0x51, 0x39, 0x73, +0x76, 0x70, 0x57, 0x53, 0x53, 0x41, 0x34, 0x59, 0x64, 0x78, 0x49, 0x69, 0x71, 0x55, 0x62, 0x51, +0x6c, 0x57, 0x2f, 0x6c, 0x36, 0x7a, 0x54, 0x65, 0x4d, 0x48, 0x37, 0x77, 0x37, 0x65, 0x5a, 0x45, +0x38, 0x6f, 0x6c, 0x36, 0x45, 0x32, 0x61, 0x74, 0x6d, 0x63, 0x2f, 0x43, 0x6f, 0x51, 0x31, 0x68, +0x59, 0x76, 0x34, 0x42, 0x6e, 0x76, 0x76, 0x67, 0x37, 0x49, 0x6b, 0x41, 0x78, 0x69, 0x64, 0x48, +0x53, 0x6f, 0x75, 0x6e, 0x56, 0x4b, 0x34, 0x70, 0x55, 0x6d, 0x76, 0x4c, 0x79, 0x43, 0x42, 0x30, +0x64, 0x45, 0x74, 0x2b, 0x33, 0x73, 0x49, 0x4c, 0x77, 0x38, 0x7a, 0x6a, 0x75, 0x34, 0x45, 0x38, +0x34, 0x36, 0x59, 0x69, 0x50, 0x6f, 0x47, 0x67, 0x4c, 0x37, 0x36, 0x32, 0x42, 0x75, 0x37, 0x36, +0x71, 0x5a, 0x58, 0x43, 0x66, 0x77, 0x65, 0x35, 0x35, 0x37, 0x52, 0x44, 0x49, 0x43, 0x42, 0x4d, +0x6d, 0x72, 0x47, 0x4c, 0x51, 0x49, 0x46, 0x66, 0x35, 0x70, 0x59, 0x39, 0x35, 0x52, 0x47, 0x49, +0x2b, 0x64, 0x42, 0x57, 0x76, 0x4a, 0x35, 0x52, 0x31, 0x66, 0x46, 0x38, 0x32, 0x31, 0x6e, 0x5a, +0x77, 0x78, 0x72, 0x78, 0x46, 0x58, 0x48, 0x76, 0x79, 0x63, 0x48, 0x62, 0x75, 0x57, 0x38, 0x69, +0x5a, 0x65, 0x2f, 0x58, 0x68, 0x5a, 0x32, 0x4d, 0x72, 0x4f, 0x50, 0x33, 0x42, 0x68, 0x51, 0x68, +0x70, 0x65, 0x4f, 0x48, 0x61, 0x50, 0x61, 0x67, 0x73, 0x73, 0x4b, 0x54, 0x61, 0x33, 0x4c, 0x70, +0x32, 0x7a, 0x6e, 0x70, 0x6f, 0x49, 0x59, 0x4e, 0x37, 0x46, 0x30, 0x4c, 0x70, 0x51, 0x47, 0x75, +0x49, 0x39, 0x41, 0x31, 0x31, 0x46, 0x59, 0x31, 0x63, 0x65, 0x55, 0x49, 0x35, 0x39, 0x78, 0x35, +0x36, 0x47, 0x78, 0x48, 0x6a, 0x6b, 0x62, 0x58, 0x4a, 0x6f, 0x7a, 0x48, 0x70, 0x76, 0x77, 0x4f, +0x79, 0x4c, 0x42, 0x70, 0x46, 0x72, 0x31, 0x6b, 0x44, 0x31, 0x37, 0x32, 0x66, 0x62, 0x75, 0x31, +0x54, 0x38, 0x62, 0x44, 0x79, 0x47, 0x2b, 0x30, 0x54, 0x38, 0x35, 0x4a, 0x30, 0x79, 0x6f, 0x69, +0x74, 0x39, 0x45, 0x35, 0x4e, 0x31, 0x35, 0x63, 0x4b, 0x6f, 0x61, 0x31, 0x69, 0x55, 0x49, 0x68, +0x53, 0x4b, 0x30, 0x56, 0x30, 0x79, 0x42, 0x43, 0x53, 0x47, 0x7a, 0x65, 0x69, 0x33, 0x33, 0x2b, +0x66, 0x67, 0x69, 0x6c, 0x54, 0x4d, 0x46, 0x4c, 0x53, 0x65, 0x65, 0x4f, 0x4e, 0x47, 0x55, 0x49, +0x67, 0x32, 0x65, 0x38, 0x66, 0x71, 0x4e, 0x4c, 0x4f, 0x30, 0x51, 0x50, 0x5a, 0x76, 0x55, 0x39, +0x2f, 0x38, 0x6c, 0x70, 0x62, 0x30, 0x4c, 0x45, 0x6b, 0x4a, 0x70, 0x70, 0x50, 0x70, 0x45, 0x38, +0x66, 0x6d, 0x6d, 0x4d, 0x4a, 0x31, 0x6e, 0x62, 0x45, 0x53, 0x62, 0x55, 0x70, 0x4f, 0x70, 0x4d, +0x52, 0x37, 0x76, 0x6a, 0x56, 0x69, 0x31, 0x51, 0x55, 0x62, 0x45, 0x55, 0x70, 0x53, 0x57, 0x4e, +0x4c, 0x45, 0x66, 0x64, 0x39, 0x65, 0x42, 0x48, 0x67, 0x55, 0x7a, 0x5a, 0x77, 0x4c, 0x67, 0x2f, +0x65, 0x50, 0x5a, 0x79, 0x55, 0x62, 0x37, 0x6a, 0x34, 0x64, 0x79, 0x4e, 0x34, 0x38, 0x76, 0x6b, +0x47, 0x70, 0x6c, 0x79, 0x2f, 0x46, 0x72, 0x76, 0x4b, 0x46, 0x7a, 0x69, 0x42, 0x5a, 0x56, 0x6a, +0x30, 0x6e, 0x55, 0x5a, 0x2f, 0x2f, 0x33, 0x37, 0x35, 0x50, 0x50, 0x37, 0x51, 0x4a, 0x78, 0x78, +0x79, 0x36, 0x6d, 0x46, 0x63, 0x65, 0x6b, 0x59, 0x66, 0x66, 0x72, 0x70, 0x6b, 0x42, 0x63, 0x56, +0x4e, 0x47, 0x7a, 0x42, 0x54, 0x62, 0x34, 0x43, 0x58, 0x58, 0x6b, 0x51, 0x74, 0x58, 0x73, 0x71, +0x6a, 0x54, 0x32, 0x30, 0x67, 0x71, 0x61, 0x4e, 0x57, 0x55, 0x64, 0x72, 0x70, 0x47, 0x77, 0x5a, +0x36, 0x43, 0x56, 0x55, 0x56, 0x4d, 0x61, 0x36, 0x35, 0x5a, 0x41, 0x6b, 0x54, 0x6c, 0x30, 0x78, +0x6b, 0x5a, 0x50, 0x35, 0x49, 0x65, 0x6b, 0x56, 0x37, 0x32, 0x51, 0x71, 0x49, 0x47, 0x33, 0x30, +0x61, 0x6d, 0x65, 0x37, 0x39, 0x58, 0x59, 0x38, 0x66, 0x47, 0x45, 0x4b, 0x6c, 0x6b, 0x66, 0x53, +0x4a, 0x39, 0x65, 0x62, 0x56, 0x6d, 0x6c, 0x64, 0x37, 0x72, 0x50, 0x78, 0x4b, 0x43, 0x5a, 0x6f, +0x57, 0x2f, 0x52, 0x47, 0x4d, 0x70, 0x6d, 0x4c, 0x63, 0x76, 0x64, 0x30, 0x75, 0x70, 0x51, 0x59, +0x6b, 0x5a, 0x61, 0x67, 0x71, 0x62, 0x65, 0x78, 0x49, 0x31, 0x36, 0x44, 0x41, 0x6f, 0x63, 0x44, +0x4b, 0x43, 0x4c, 0x77, 0x65, 0x53, 0x45, 0x41, 0x33, 0x77, 0x2b, 0x69, 0x43, 0x34, 0x67, 0x6f, +0x46, 0x72, 0x53, 0x6e, 0x44, 0x4d, 0x53, 0x4e, 0x74, 0x57, 0x4e, 0x4d, 0x58, 0x47, 0x66, 0x4b, +0x69, 0x31, 0x6c, 0x45, 0x70, 0x45, 0x42, 0x79, 0x52, 0x44, 0x71, 0x55, 0x2b, 0x2f, 0x50, 0x53, +0x7a, 0x62, 0x51, 0x50, 0x6c, 0x70, 0x30, 0x68, 0x46, 0x34, 0x5a, 0x67, 0x52, 0x2b, 0x2f, 0x50, +0x65, 0x34, 0x6b, 0x38, 0x34, 0x61, 0x4e, 0x67, 0x45, 0x76, 0x6d, 0x6c, 0x63, 0x54, 0x47, 0x73, +0x30, 0x79, 0x66, 0x47, 0x37, 0x54, 0x71, 0x49, 0x6c, 0x32, 0x63, 0x61, 0x38, 0x32, 0x75, 0x2f, +0x34, 0x2b, 0x57, 0x38, 0x75, 0x70, 0x44, 0x58, 0x52, 0x51, 0x69, 0x52, 0x65, 0x43, 0x42, 0x67, +0x71, 0x38, 0x38, 0x73, 0x78, 0x39, 0x39, 0x78, 0x6e, 0x4e, 0x79, 0x4e, 0x52, 0x4b, 0x6e, 0x73, +0x76, 0x69, 0x61, 0x4f, 0x62, 0x72, 0x53, 0x7a, 0x2f, 0x76, 0x77, 0x70, 0x43, 0x6b, 0x43, 0x37, +0x69, 0x57, 0x37, 0x38, 0x47, 0x72, 0x36, 0x61, 0x47, 0x33, 0x69, 0x38, 0x38, 0x62, 0x78, 0x73, +0x41, 0x4f, 0x30, 0x52, 0x51, 0x43, 0x43, 0x6c, 0x6f, 0x54, 0x54, 0x52, 0x54, 0x45, 0x43, 0x39, +0x6b, 0x59, 0x4d, 0x55, 0x41, 0x43, 0x71, 0x4f, 0x46, 0x72, 0x47, 0x35, 0x63, 0x54, 0x55, 0x71, +0x6d, 0x61, 0x45, 0x34, 0x30, 0x73, 0x37, 0x56, 0x39, 0x43, 0x31, 0x47, 0x69, 0x2b, 0x45, 0x36, +0x42, 0x42, 0x2b, 0x44, 0x41, 0x41, 0x79, 0x75, 0x34, 0x34, 0x49, 0x4c, 0x65, 0x6e, 0x48, 0x58, +0x32, 0x47, 0x70, 0x35, 0x2b, 0x61, 0x69, 0x69, 0x76, 0x76, 0x4e, 0x4c, 0x4d, 0x39, 0x4f, 0x6c, +0x62, 0x45, 0x43, 0x49, 0x50, 0x64, 0x4a, 0x4b, 0x72, 0x54, 0x6e, 0x75, 0x5a, 0x50, 0x58, 0x61, +0x66, 0x7a, 0x64, 0x4a, 0x57, 0x79, 0x61, 0x58, 0x76, 0x62, 0x69, 0x49, 0x6c, 0x4d, 0x7a, 0x54, +0x35, 0x33, 0x47, 0x48, 0x46, 0x48, 0x56, 0x49, 0x63, 0x66, 0x66, 0x51, 0x38, 0x43, 0x7a, 0x4a, +0x6f, 0x67, 0x58, 0x6c, 0x45, 0x59, 0x4e, 0x37, 0x74, 0x32, 0x76, 0x4d, 0x61, 0x33, 0x38, 0x66, +0x73, 0x75, 0x69, 0x75, 0x63, 0x65, 0x53, 0x62, 0x63, 0x65, 0x79, 0x2f, 0x63, 0x74, 0x77, 0x31, +0x56, 0x48, 0x6b, 0x63, 0x6d, 0x42, 0x44, 0x63, 0x39, 0x75, 0x59, 0x7a, 0x64, 0x39, 0x2b, 0x2f, +0x4c, 0x74, 0x59, 0x66, 0x57, 0x30, 0x4b, 0x73, 0x67, 0x79, 0x6c, 0x76, 0x58, 0x37, 0x4a, 0x36, +0x56, 0x36, 0x56, 0x65, 0x38, 0x74, 0x59, 0x36, 0x50, 0x33, 0x6c, 0x32, 0x48, 0x36, 0x46, 0x65, +0x41, 0x71, 0x4d, 0x71, 0x44, 0x70, 0x50, 0x57, 0x44, 0x56, 0x63, 0x59, 0x53, 0x6a, 0x6e, 0x57, +0x6c, 0x6d, 0x37, 0x6e, 0x30, 0x34, 0x2b, 0x76, 0x34, 0x34, 0x36, 0x54, 0x72, 0x47, 0x5a, 0x44, +0x66, 0x62, 0x37, 0x73, 0x39, 0x49, 0x4a, 0x37, 0x48, 0x70, 0x6f, 0x49, 0x43, 0x31, 0x4d, 0x32, +0x33, 0x34, 0x41, 0x31, 0x50, 0x67, 0x46, 0x2b, 0x4c, 0x4d, 0x54, 0x49, 0x64, 0x66, 0x79, 0x33, +0x34, 0x35, 0x2b, 0x47, 0x50, 0x5a, 0x47, 0x7a, 0x77, 0x36, 0x47, 0x64, 0x74, 0x38, 0x4f, 0x6a, +0x6c, 0x44, 0x36, 0x48, 0x31, 0x67, 0x64, 0x6e, 0x6f, 0x4b, 0x30, 0x42, 0x38, 0x2f, 0x44, 0x47, +0x78, 0x41, 0x77, 0x38, 0x6b, 0x66, 0x74, 0x52, 0x52, 0x2b, 0x4f, 0x2b, 0x39, 0x54, 0x2b, 0x4c, +0x4f, 0x4f, 0x31, 0x46, 0x74, 0x62, 0x64, 0x6c, 0x4b, 0x51, 0x44, 0x6d, 0x71, 0x74, 0x4a, 0x34, +0x51, 0x2b, 0x4d, 0x44, 0x39, 0x70, 0x7a, 0x33, 0x4b, 0x30, 0x37, 0x45, 0x45, 0x2f, 0x7a, 0x37, +0x6b, 0x48, 0x41, 0x37, 0x2b, 0x37, 0x7a, 0x4d, 0x30, 0x2b, 0x31, 0x47, 0x2b, 0x33, 0x66, 0x50, +0x58, 0x48, 0x50, 0x7a, 0x74, 0x61, 0x33, 0x7a, 0x52, 0x5a, 0x77, 0x38, 0x53, 0x33, 0x37, 0x54, +0x6a, 0x70, 0x35, 0x53, 0x56, 0x35, 0x73, 0x59, 0x6e, 0x67, 0x71, 0x53, 0x79, 0x4f, 0x49, 0x48, +0x30, 0x72, 0x61, 0x61, 0x65, 0x61, 0x6d, 0x70, 0x6e, 0x66, 0x56, 0x32, 0x53, 0x47, 0x2f, 0x64, +0x65, 0x69, 0x53, 0x71, 0x62, 0x79, 0x44, 0x58, 0x6a, 0x6c, 0x6e, 0x4c, 0x4b, 0x73, 0x2f, 0x30, +0x52, 0x52, 0x4a, 0x30, 0x55, 0x6d, 0x45, 0x62, 0x34, 0x37, 0x69, 0x70, 0x30, 0x69, 0x49, 0x59, +0x33, 0x74, 0x77, 0x70, 0x67, 0x43, 0x35, 0x2f, 0x4e, 0x61, 0x65, 0x61, 0x49, 0x77, 0x36, 0x6f, +0x34, 0x49, 0x70, 0x6e, 0x45, 0x58, 0x48, 0x51, 0x78, 0x6c, 0x4a, 0x64, 0x68, 0x54, 0x6a, 0x38, +0x64, 0x64, 0x66, 0x56, 0x31, 0x62, 0x4b, 0x31, 0x72, 0x59, 0x58, 0x6c, 0x7a, 0x67, 0x61, 0x58, +0x69, 0x70, 0x42, 0x4d, 0x31, 0x46, 0x56, 0x59, 0x78, 0x61, 0x57, 0x43, 0x2f, 0x50, 0x46, 0x43, +0x62, 0x65, 0x48, 0x2f, 0x67, 0x54, 0x41, 0x6f, 0x4c, 0x6f, 0x2b, 0x6e, 0x4b, 0x75, 0x34, 0x4d, +0x6f, 0x75, 0x4f, 0x64, 0x35, 0x6e, 0x4a, 0x77, 0x38, 0x32, 0x34, 0x31, 0x41, 0x73, 0x6c, 0x57, +0x64, 0x48, 0x2f, 0x72, 0x77, 0x64, 0x6b, 0x37, 0x71, 0x50, 0x77, 0x69, 0x31, 0x71, 0x52, 0x45, +0x68, 0x59, 0x37, 0x53, 0x4c, 0x4a, 0x33, 0x6c, 0x73, 0x78, 0x58, 0x78, 0x75, 0x4f, 0x65, 0x6d, +0x68, 0x37, 0x41, 0x62, 0x41, 0x32, 0x52, 0x56, 0x43, 0x56, 0x65, 0x6c, 0x41, 0x56, 0x4e, 0x59, +0x49, 0x32, 0x6f, 0x58, 0x67, 0x39, 0x64, 0x57, 0x43, 0x6c, 0x42, 0x49, 0x63, 0x50, 0x39, 0x79, +0x6e, 0x49, 0x74, 0x6f, 0x39, 0x43, 0x69, 0x79, 0x78, 0x4b, 0x4c, 0x55, 0x79, 0x74, 0x68, 0x7a, +0x37, 0x43, 0x76, 0x59, 0x5a, 0x59, 0x4b, 0x67, 0x73, 0x4e, 0x41, 0x77, 0x70, 0x4e, 0x33, 0x67, +0x59, 0x54, 0x74, 0x2f, 0x4e, 0x55, 0x4e, 0x39, 0x6d, 0x2b, 0x47, 0x43, 0x6c, 0x62, 0x51, 0x53, +0x6b, 0x57, 0x32, 0x33, 0x42, 0x68, 0x77, 0x2f, 0x50, 0x2f, 0x54, 0x76, 0x2f, 0x79, 0x36, 0x48, +0x50, 0x65, 0x77, 0x70, 0x76, 0x53, 0x77, 0x4e, 0x73, 0x33, 0x4a, 0x41, 0x57, 0x4a, 0x5a, 0x55, +0x43, 0x63, 0x36, 0x76, 0x41, 0x46, 0x4c, 0x76, 0x52, 0x79, 0x79, 0x41, 0x66, 0x63, 0x32, 0x45, +0x4f, 0x43, 0x2b, 0x4a, 0x57, 0x55, 0x57, 0x4b, 0x57, 0x4a, 0x4c, 0x4d, 0x71, 0x50, 0x72, 0x32, +0x4c, 0x65, 0x7a, 0x4f, 0x30, 0x39, 0x31, 0x41, 0x57, 0x62, 0x6c, 0x68, 0x4d, 0x75, 0x39, 0x2f, +0x4f, 0x6b, 0x6b, 0x31, 0x4c, 0x71, 0x43, 0x67, 0x73, 0x5a, 0x39, 0x37, 0x36, 0x65, 0x56, 0x51, +0x55, 0x39, 0x6d, 0x4a, 0x56, 0x34, 0x79, 0x6f, 0x2b, 0x57, 0x2f, 0x57, 0x5a, 0x6b, 0x34, 0x6d, +0x32, 0x50, 0x7a, 0x42, 0x37, 0x39, 0x68, 0x5a, 0x6d, 0x7a, 0x71, 0x78, 0x47, 0x2b, 0x50, 0x44, +0x50, 0x66, 0x7a, 0x62, 0x78, 0x35, 0x70, 0x75, 0x74, 0x43, 0x46, 0x48, 0x49, 0x35, 0x50, 0x30, +0x2b, 0x35, 0x2b, 0x51, 0x6a, 0x2f, 0x30, 0x4e, 0x48, 0x33, 0x68, 0x72, 0x2b, 0x58, 0x52, 0x66, +0x6c, 0x37, 0x71, 0x38, 0x32, 0x49, 0x62, 0x52, 0x62, 0x6e, 0x38, 0x78, 0x55, 0x39, 0x55, 0x55, +0x69, 0x5a, 0x59, 0x54, 0x78, 0x75, 0x36, 0x39, 0x6b, 0x32, 0x4c, 0x43, 0x4e, 0x47, 0x43, 0x4d, +0x78, 0x66, 0x78, 0x47, 0x59, 0x74, 0x33, 0x50, 0x57, 0x50, 0x35, 0x58, 0x43, 0x37, 0x4c, 0x38, +0x2f, 0x35, 0x73, 0x51, 0x54, 0x4d, 0x66, 0x73, 0x66, 0x41, 0x50, 0x45, 0x59, 0x75, 0x72, 0x6b, +0x5a, 0x5a, 0x49, 0x4d, 0x46, 0x4f, 0x4f, 0x49, 0x52, 0x35, 0x49, 0x41, 0x69, 0x76, 0x6e, 0x78, +0x39, 0x4e, 0x55, 0x66, 0x50, 0x33, 0x63, 0x4c, 0x62, 0x6c, 0x34, 0x2f, 0x4c, 0x4b, 0x6a, 0x42, +0x37, 0x33, 0x76, 0x49, 0x4e, 0x59, 0x74, 0x46, 0x57, 0x2f, 0x4c, 0x33, 0x36, 0x4f, 0x6d, 0x44, +0x45, 0x57, 0x57, 0x6b, 0x6b, 0x61, 0x56, 0x56, 0x68, 0x4c, 0x56, 0x6b, 0x66, 0x57, 0x38, 0x2f, +0x31, 0x37, 0x2f, 0x79, 0x52, 0x4a, 0x30, 0x2f, 0x34, 0x4f, 0x35, 0x37, 0x70, 0x32, 0x53, 0x6b, +0x70, 0x56, 0x47, 0x57, 0x56, 0x32, 0x42, 0x37, 0x66, 0x43, 0x49, 0x7a, 0x4f, 0x61, 0x41, 0x43, +0x43, 0x4c, 0x64, 0x57, 0x7a, 0x64, 0x6e, 0x6a, 0x31, 0x77, 0x38, 0x2f, 0x52, 0x45, 0x69, 0x33, +0x74, 0x42, 0x45, 0x67, 0x74, 0x57, 0x6f, 0x54, 0x2f, 0x33, 0x2f, 0x39, 0x69, 0x38, 0x4b, 0x43, +0x6b, 0x42, 0x47, 0x51, 0x2b, 0x6b, 0x61, 0x49, 0x69, 0x75, 0x79, 0x75, 0x4d, 0x45, 0x45, 0x37, +0x6b, 0x30, 0x75, 0x6b, 0x44, 0x53, 0x69, 0x76, 0x49, 0x36, 0x6c, 0x56, 0x58, 0x45, 0x77, 0x4f, +0x4f, 0x66, 0x2b, 0x46, 0x36, 0x76, 0x6a, 0x72, 0x7a, 0x4c, 0x5a, 0x61, 0x76, 0x62, 0x4b, 0x47, +0x69, 0x4f, 0x59, 0x39, 0x6b, 0x53, 0x76, 0x48, 0x52, 0x5a, 0x78, 0x76, 0x5a, 0x4f, 0x6d, 0x59, +0x79, 0x59, 0x32, 0x61, 0x2b, 0x78, 0x6d, 0x74, 0x69, 0x5a, 0x7a, 0x52, 0x78, 0x31, 0x69, 0x77, +0x76, 0x35, 0x39, 0x75, 0x61, 0x71, 0x7a, 0x6c, 0x30, 0x33, 0x34, 0x47, 0x38, 0x2f, 0x32, 0x6b, +0x74, 0x57, 0x74, 0x63, 0x54, 0x57, 0x4e, 0x61, 0x6b, 0x67, 0x65, 0x64, 0x65, 0x61, 0x71, 0x44, +0x33, 0x6a, 0x4a, 0x65, 0x73, 0x41, 0x6f, 0x38, 0x5a, 0x59, 0x4a, 0x48, 0x66, 0x51, 0x41, 0x37, +0x4e, 0x6e, 0x65, 0x48, 0x47, 0x4b, 0x42, 0x49, 0x6e, 0x66, 0x47, 0x4e, 0x39, 0x7a, 0x36, 0x33, +0x6f, 0x70, 0x38, 0x59, 0x38, 0x39, 0x69, 0x68, 0x63, 0x65, 0x79, 0x50, 0x6d, 0x58, 0x39, 0x4f, +0x4a, 0x52, 0x41, 0x78, 0x74, 0x76, 0x74, 0x31, 0x4e, 0x79, 0x61, 0x68, 0x67, 0x64, 0x53, 0x76, +0x39, 0x72, 0x4d, 0x6f, 0x30, 0x31, 0x4e, 0x45, 0x4e, 0x53, 0x76, 0x77, 0x44, 0x5a, 0x35, 0x44, +0x2b, 0x35, 0x62, 0x66, 0x44, 0x2f, 0x63, 0x66, 0x41, 0x70, 0x72, 0x59, 0x30, 0x6f, 0x37, 0x42, +0x33, 0x76, 0x78, 0x50, 0x34, 0x2f, 0x76, 0x75, 0x2f, 0x73, 0x71, 0x6a, 0x76, 0x71, 0x58, 0x51, +0x49, 0x77, 0x35, 0x6a, 0x46, 0x62, 0x7a, 0x4b, 0x67, 0x35, 0x43, 0x68, 0x4f, 0x66, 0x53, 0x58, +0x64, 0x41, 0x39, 0x65, 0x55, 0x65, 0x54, 0x78, 0x7a, 0x68, 0x34, 0x5a, 0x6a, 0x73, 0x2f, 0x4e, +0x66, 0x61, 0x67, 0x6c, 0x47, 0x73, 0x47, 0x69, 0x62, 0x7a, 0x33, 0x75, 0x31, 0x67, 0x6a, 0x59, +0x68, 0x71, 0x43, 0x6e, 0x31, 0x4f, 0x61, 0x4a, 0x66, 0x39, 0x79, 0x69, 0x77, 0x4c, 0x2b, 0x32, +0x37, 0x71, 0x41, 0x78, 0x47, 0x34, 0x6f, 0x74, 0x61, 0x77, 0x30, 0x6c, 0x6a, 0x44, 0x54, 0x55, +0x6c, 0x64, 0x73, 0x52, 0x59, 0x48, 0x7a, 0x66, 0x38, 0x64, 0x34, 0x31, 0x4a, 0x32, 0x77, 0x41, +0x79, 0x55, 0x65, 0x72, 0x74, 0x48, 0x46, 0x6c, 0x79, 0x39, 0x64, 0x73, 0x37, 0x63, 0x6c, 0x57, +0x4a, 0x6c, 0x63, 0x43, 0x38, 0x34, 0x32, 0x4d, 0x75, 0x46, 0x78, 0x68, 0x50, 0x59, 0x50, 0x37, +0x68, 0x32, 0x38, 0x2b, 0x36, 0x69, 0x58, 0x38, 0x4d, 0x62, 0x56, 0x46, 0x53, 0x59, 0x2b, 0x42, +0x66, 0x38, 0x31, 0x37, 0x47, 0x4d, 0x35, 0x35, 0x31, 0x36, 0x46, 0x45, 0x2b, 0x76, 0x72, 0x42, +0x71, 0x4b, 0x45, 0x6d, 0x5a, 0x49, 0x75, 0x4a, 0x46, 0x32, 0x4e, 0x4b, 0x78, 0x78, 0x65, 0x6d, +0x37, 0x6d, 0x62, 0x41, 0x42, 0x41, 0x4a, 0x39, 0x2f, 0x2f, 0x37, 0x73, 0x5a, 0x4b, 0x51, 0x33, +0x54, 0x58, 0x32, 0x35, 0x6a, 0x39, 0x31, 0x47, 0x72, 0x4f, 0x66, 0x61, 0x67, 0x4c, 0x78, 0x67, +0x31, 0x37, 0x46, 0x76, 0x57, 0x64, 0x4b, 0x62, 0x34, 0x38, 0x2b, 0x78, 0x4f, 0x46, 0x6d, 0x39, +0x70, 0x78, 0x7a, 0x64, 0x2b, 0x4b, 0x50, 0x36, 0x5a, 0x70, 0x65, 0x71, 0x4c, 0x52, 0x6d, 0x75, +0x66, 0x79, 0x63, 0x66, 0x4f, 0x74, 0x79, 0x6a, 0x6a, 0x45, 0x78, 0x4c, 0x7a, 0x5a, 0x67, 0x59, +0x4b, 0x48, 0x49, 0x39, 0x6a, 0x44, 0x6a, 0x6b, 0x45, 0x38, 0x37, 0x4f, 0x66, 0x59, 0x53, 0x5a, +0x4d, 0x53, 0x50, 0x63, 0x41, 0x77, 0x54, 0x71, 0x72, 0x31, 0x43, 0x67, 0x4d, 0x73, 0x6b, 0x50, +0x69, 0x62, 0x32, 0x78, 0x6e, 0x7a, 0x4a, 0x47, 0x44, 0x75, 0x50, 0x75, 0x6f, 0x51, 0x56, 0x30, +0x4b, 0x7a, 0x4e, 0x63, 0x33, 0x54, 0x4f, 0x44, 0x4d, 0x6c, 0x31, 0x66, 0x78, 0x32, 0x51, 0x65, +0x31, 0x69, 0x4f, 0x70, 0x69, 0x52, 0x4b, 0x2b, 0x34, 0x72, 0x51, 0x41, 0x79, 0x57, 0x31, 0x57, +0x34, 0x57, 0x6c, 0x56, 0x7a, 0x2f, 0x56, 0x48, 0x58, 0x62, 0x37, 0x66, 0x79, 0x5a, 0x34, 0x57, +0x76, 0x73, 0x59, 0x32, 0x57, 0x74, 0x68, 0x51, 0x57, 0x4f, 0x72, 0x63, 0x42, 0x79, 0x4c, 0x6d, +0x36, 0x7a, 0x7a, 0x30, 0x74, 0x30, 0x42, 0x49, 0x71, 0x57, 0x31, 0x71, 0x49, 0x6c, 0x4a, 0x52, +0x6b, 0x7a, 0x65, 0x46, 0x32, 0x70, 0x41, 0x4a, 0x45, 0x49, 0x68, 0x46, 0x71, 0x70, 0x6b, 0x35, +0x6c, 0x2f, 0x31, 0x31, 0x6e, 0x63, 0x4d, 0x57, 0x6e, 0x47, 0x36, 0x6a, 0x62, 0x30, 0x4d, 0x4a, +0x4d, 0x66, 0x79, 0x38, 0x72, 0x69, 0x62, 0x5a, 0x6d, 0x43, 0x77, 0x75, 0x57, 0x62, 0x43, 0x49, +0x6c, 0x64, 0x38, 0x45, 0x7a, 0x6c, 0x71, 0x44, 0x72, 0x53, 0x4a, 0x55, 0x52, 0x2b, 0x66, 0x34, +0x5a, 0x48, 0x75, 0x78, 0x63, 0x51, 0x4b, 0x48, 0x65, 0x42, 0x61, 0x57, 0x43, 0x35, 0x64, 0x49, +0x59, 0x53, 0x6b, 0x66, 0x34, 0x49, 0x4c, 0x6f, 0x58, 0x66, 0x72, 0x4d, 0x62, 0x38, 0x68, 0x74, +0x72, 0x76, 0x2f, 0x46, 0x6c, 0x78, 0x47, 0x6f, 0x6a, 0x4b, 0x76, 0x43, 0x56, 0x6c, 0x37, 0x35, +0x71, 0x45, 0x4e, 0x71, 0x4b, 0x5a, 0x30, 0x41, 0x65, 0x78, 0x6d, 0x6a, 0x57, 0x6e, 0x33, 0x49, +0x78, 0x62, 0x37, 0x39, 0x64, 0x7a, 0x34, 0x61, 0x2f, 0x4a, 0x53, 0x41, 0x31, 0x6d, 0x61, 0x74, +0x4f, 0x6e, 0x63, 0x6a, 0x6d, 0x57, 0x59, 0x55, 0x49, 0x5a, 0x5a, 0x31, 0x74, 0x68, 0x50, 0x59, +0x51, 0x4a, 0x6f, 0x49, 0x30, 0x47, 0x71, 0x6b, 0x39, 0x55, 0x69, 0x59, 0x4b, 0x35, 0x50, 0x57, +0x49, 0x45, 0x76, 0x2f, 0x67, 0x43, 0x4d, 0x43, 0x6b, 0x53, 0x55, 0x69, 0x6c, 0x30, 0x78, 0x35, +0x76, 0x55, 0x73, 0x47, 0x43, 0x5a, 0x59, 0x38, 0x79, 0x75, 0x45, 0x2b, 0x4d, 0x34, 0x75, 0x51, +0x73, 0x76, 0x49, 0x52, 0x69, 0x53, 0x30, 0x65, 0x63, 0x32, 0x63, 0x33, 0x54, 0x45, 0x4a, 0x55, +0x2f, 0x7a, 0x59, 0x43, 0x5a, 0x6a, 0x4c, 0x4d, 0x51, 0x64, 0x36, 0x63, 0x71, 0x4c, 0x64, 0x69, +0x6e, 0x6a, 0x38, 0x2b, 0x2b, 0x2f, 0x51, 0x57, 0x64, 0x76, 0x73, 0x2f, 0x42, 0x2f, 0x58, 0x74, +0x47, 0x67, 0x57, 0x56, 0x4f, 0x2b, 0x45, 0x70, 0x44, 0x70, 0x7a, 0x44, 0x4d, 0x32, 0x32, 0x67, +0x59, 0x56, 0x6d, 0x48, 0x6a, 0x4f, 0x72, 0x66, 0x65, 0x30, 0x4e, 0x52, 0x70, 0x69, 0x45, 0x56, +0x4d, 0x64, 0x76, 0x6a, 0x2b, 0x39, 0x68, 0x75, 0x41, 0x31, 0x34, 0x33, 0x4a, 0x63, 0x62, 0x66, +0x72, 0x2f, 0x75, 0x69, 0x69, 0x53, 0x69, 0x77, 0x45, 0x35, 0x6b, 0x67, 0x66, 0x4d, 0x39, 0x76, +0x46, 0x2b, 0x30, 0x69, 0x42, 0x6d, 0x64, 0x34, 0x39, 0x43, 0x68, 0x36, 0x7a, 0x7a, 0x69, 0x52, +0x75, 0x62, 0x33, 0x53, 0x52, 0x34, 0x75, 0x77, 0x44, 0x7a, 0x36, 0x59, 0x6f, 0x5a, 0x6f, 0x30, +0x4b, 0x6d, 0x61, 0x73, 0x42, 0x5a, 0x66, 0x6c, 0x6c, 0x43, 0x43, 0x57, 0x34, 0x65, 0x50, 0x70, +0x46, 0x70, 0x46, 0x54, 0x4b, 0x74, 0x70, 0x53, 0x75, 0x41, 0x67, 0x73, 0x42, 0x76, 0x70, 0x2f, +0x48, 0x57, 0x54, 0x2f, 0x2f, 0x67, 0x46, 0x32, 0x47, 0x4c, 0x6b, 0x52, 0x58, 0x7a, 0x4f, 0x58, +0x6a, 0x7a, 0x61, 0x58, 0x63, 0x38, 0x63, 0x55, 0x6d, 0x74, 0x7a, 0x64, 0x37, 0x6f, 0x43, 0x72, +0x73, 0x64, 0x31, 0x58, 0x31, 0x4a, 0x63, 0x5a, 0x4f, 0x59, 0x2b, 0x72, 0x59, 0x61, 0x57, 0x51, +0x74, 0x54, 0x4a, 0x4f, 0x59, 0x66, 0x37, 0x71, 0x49, 0x6c, 0x70, 0x56, 0x68, 0x44, 0x70, 0x2b, +0x45, 0x4f, 0x65, 0x59, 0x59, 0x7a, 0x4a, 0x43, 0x30, 0x4a, 0x35, 0x6c, 0x51, 0x67, 0x67, 0x33, +0x74, 0x47, 0x31, 0x6a, 0x62, 0x73, 0x5a, 0x61, 0x66, 0x2f, 0x66, 0x4e, 0x6e, 0x49, 0x4e, 0x39, +0x42, 0x62, 0x45, 0x76, 0x69, 0x62, 0x2b, 0x31, 0x6b, 0x36, 0x70, 0x6b, 0x37, 0x73, 0x38, 0x2b, +0x67, 0x49, 0x6f, 0x77, 0x78, 0x74, 0x50, 0x6d, 0x4b, 0x77, 0x32, 0x2f, 0x37, 0x46, 0x69, 0x45, +0x31, 0x4d, 0x32, 0x2b, 0x63, 0x51, 0x45, 0x6e, 0x4d, 0x34, 0x36, 0x6d, 0x54, 0x68, 0x2f, 0x48, +0x68, 0x37, 0x70, 0x57, 0x63, 0x64, 0x65, 0x39, 0x63, 0x56, 0x42, 0x77, 0x67, 0x41, 0x74, 0x4b, +0x70, 0x43, 0x68, 0x75, 0x66, 0x34, 0x69, 0x33, 0x46, 0x33, 0x48, 0x58, 0x30, 0x58, 0x55, 0x52, +0x53, 0x45, 0x5a, 0x6f, 0x54, 0x7a, 0x65, 0x47, 0x61, 0x62, 0x68, 0x61, 0x76, 0x37, 0x73, 0x35, +0x6f, 0x4e, 0x45, 0x70, 0x72, 0x61, 0x79, 0x76, 0x52, 0x4b, 0x36, 0x64, 0x77, 0x30, 0x64, 0x58, +0x48, 0x73, 0x32, 0x5a, 0x4c, 0x43, 0x31, 0x4a, 0x70, 0x33, 0x76, 0x6e, 0x70, 0x6e, 0x77, 0x6e, +0x59, 0x38, 0x58, 0x31, 0x66, 0x76, 0x52, 0x49, 0x68, 0x70, 0x62, 0x55, 0x42, 0x4a, 0x43, 0x4e, +0x57, 0x47, 0x4e, 0x54, 0x70, 0x41, 0x34, 0x37, 0x6f, 0x57, 0x38, 0x61, 0x33, 0x64, 0x7a, 0x78, +0x4d, 0x36, 0x69, 0x4c, 0x77, 0x66, 0x6d, 0x7a, 0x76, 0x35, 0x37, 0x34, 0x6e, 0x58, 0x51, 0x4e, +0x73, 0x6c, 0x45, 0x4a, 0x49, 0x69, 0x7a, 0x4a, 0x37, 0x79, 0x70, 0x4b, 0x4d, 0x78, 0x68, 0x67, +0x38, 0x48, 0x65, 0x7a, 0x69, 0x6f, 0x33, 0x6d, 0x2f, 0x2f, 0x67, 0x6a, 0x36, 0x37, 0x48, 0x6f, +0x6e, 0x36, 0x45, 0x4a, 0x57, 0x7a, 0x4a, 0x36, 0x4d, 0x56, 0x41, 0x4c, 0x77, 0x75, 0x59, 0x50, +0x54, 0x4f, 0x4c, 0x7a, 0x6a, 0x4a, 0x6c, 0x70, 0x62, 0x4e, 0x36, 0x47, 0x6c, 0x52, 0x44, 0x6b, +0x55, 0x4e, 0x62, 0x77, 0x4b, 0x67, 0x66, 0x4b, 0x6c, 0x68, 0x58, 0x42, 0x38, 0x43, 0x7a, 0x4d, +0x70, 0x6f, 0x53, 0x6a, 0x72, 0x56, 0x63, 0x30, 0x6a, 0x2f, 0x49, 0x32, 0x62, 0x31, 0x30, 0x31, +0x6c, 0x2b, 0x4a, 0x70, 0x37, 0x69, 0x47, 0x38, 0x72, 0x34, 0x6c, 0x66, 0x48, 0x54, 0x2b, 0x4b, +0x32, 0x4e, 0x2b, 0x4e, 0x63, 0x63, 0x31, 0x49, 0x4d, 0x37, 0x36, 0x4e, 0x5a, 0x58, 0x50, 0x76, +0x74, 0x31, 0x32, 0x6d, 0x63, 0x56, 0x51, 0x69, 0x30, 0x55, 0x4f, 0x48, 0x65, 0x68, 0x76, 0x6c, +0x44, 0x42, 0x37, 0x49, 0x2f, 0x2f, 0x2b, 0x43, 0x67, 0x67, 0x33, 0x5a, 0x6a, 0x79, 0x70, 0x52, +0x71, 0x47, 0x68, 0x74, 0x6c, 0x39, 0x71, 0x71, 0x52, 0x4e, 0x43, 0x69, 0x5a, 0x74, 0x68, 0x73, +0x45, 0x4f, 0x78, 0x59, 0x46, 0x62, 0x72, 0x48, 0x39, 0x2b, 0x75, 0x56, 0x78, 0x35, 0x35, 0x33, +0x66, 0x77, 0x4a, 0x53, 0x42, 0x4b, 0x4f, 0x4f, 0x46, 0x77, 0x32, 0x71, 0x70, 0x44, 0x42, 0x30, +0x46, 0x6c, 0x2f, 0x43, 0x52, 0x58, 0x38, 0x34, 0x6b, 0x66, 0x52, 0x4e, 0x4b, 0x4a, 0x6e, 0x6d, +0x78, 0x65, 0x43, 0x70, 0x74, 0x6e, 0x52, 0x45, 0x72, 0x63, 0x4a, 0x4b, 0x4c, 0x4d, 0x67, 0x66, +0x35, 0x72, 0x33, 0x77, 0x48, 0x59, 0x50, 0x6b, 0x59, 0x72, 0x4d, 0x54, 0x61, 0x78, 0x57, 0x50, +0x73, 0x45, 0x46, 0x6f, 0x46, 0x6a, 0x58, 0x6b, 0x33, 0x4b, 0x4c, 0x43, 0x53, 0x75, 0x6b, 0x76, +0x34, 0x57, 0x68, 0x73, 0x47, 0x6c, 0x78, 0x75, 0x65, 0x6e, 0x6d, 0x74, 0x49, 0x4b, 0x63, 0x4f, +0x77, 0x58, 0x6b, 0x48, 0x5a, 0x37, 0x52, 0x70, 0x2b, 0x34, 0x7a, 0x48, 0x48, 0x64, 0x46, 0x75, +0x70, 0x68, 0x65, 0x39, 0x7a, 0x2f, 0x4d, 0x53, 0x4a, 0x45, 0x49, 0x31, 0x53, 0x50, 0x32, 0x73, +0x57, 0x38, 0x62, 0x79, 0x38, 0x62, 0x72, 0x2f, 0x58, 0x43, 0x2f, 0x42, 0x4b, 0x79, 0x7a, 0x44, +0x6c, 0x46, 0x53, 0x35, 0x65, 0x77, 0x6b, 0x72, 0x33, 0x2f, 0x30, 0x6d, 0x45, 0x6a, 0x59, 0x49, +0x52, 0x41, 0x6c, 0x4f, 0x56, 0x58, 0x72, 0x31, 0x41, 0x43, 0x6b, 0x78, 0x56, 0x48, 0x79, 0x66, +0x4b, 0x46, 0x54, 0x51, 0x41, 0x62, 0x69, 0x2f, 0x36, 0x52, 0x32, 0x59, 0x2b, 0x59, 0x70, 0x63, +0x51, 0x6c, 0x4d, 0x35, 0x51, 0x39, 0x50, 0x57, 0x35, 0x2f, 0x4c, 0x44, 0x4c, 0x2b, 0x58, 0x54, +0x46, 0x70, 0x2b, 0x6d, 0x68, 0x55, 0x6b, 0x59, 0x46, 0x6e, 0x72, 0x54, 0x66, 0x59, 0x6e, 0x6f, +0x64, 0x76, 0x4a, 0x42, 0x52, 0x51, 0x37, 0x36, 0x67, 0x45, 0x63, 0x6d, 0x7a, 0x69, 0x2f, 0x4b, +0x59, 0x75, 0x58, 0x5a, 0x6a, 0x6d, 0x4c, 0x43, 0x32, 0x35, 0x78, 0x64, 0x57, 0x30, 0x54, 0x66, +0x63, 0x51, 0x7a, 0x34, 0x51, 0x54, 0x32, 0x7a, 0x6e, 0x6b, 0x4d, 0x4d, 0x57, 0x59, 0x56, 0x34, +0x51, 0x4d, 0x46, 0x31, 0x67, 0x65, 0x76, 0x66, 0x48, 0x54, 0x4a, 0x36, 0x4d, 0x4f, 0x65, 0x59, +0x34, 0x54, 0x45, 0x55, 0x68, 0x6e, 0x55, 0x61, 0x78, 0x76, 0x6d, 0x55, 0x46, 0x43, 0x37, 0x59, +0x73, 0x59, 0x48, 0x37, 0x6a, 0x66, 0x4c, 0x35, 0x75, 0x2f, 0x4a, 0x72, 0x6c, 0x54, 0x63, 0x75, +0x70, 0x4b, 0x61, 0x6d, 0x42, 0x70, 0x34, 0x44, 0x32, 0x54, 0x5a, 0x54, 0x2f, 0x62, 0x69, 0x78, +0x76, 0x6e, 0x6a, 0x59, 0x79, 0x72, 0x42, 0x69, 0x50, 0x66, 0x62, 0x47, 0x4a, 0x76, 0x2f, 0x39, +0x7a, 0x46, 0x61, 0x49, 0x73, 0x44, 0x7a, 0x2f, 0x71, 0x73, 0x63, 0x2b, 0x6c, 0x6e, 0x33, 0x48, +0x32, 0x71, 0x63, 0x50, 0x35, 0x77, 0x30, 0x48, 0x56, 0x48, 0x44, 0x61, 0x79, 0x6c, 0x48, 0x57, +0x50, 0x48, 0x38, 0x49, 0x76, 0x6e, 0x31, 0x73, 0x42, 0x72, 0x41, 0x59, 0x4e, 0x30, 0x6b, 0x69, +0x4b, 0x4e, 0x68, 0x66, 0x52, 0x2b, 0x46, 0x49, 0x6a, 0x4a, 0x7a, 0x78, 0x2b, 0x41, 0x72, 0x37, +0x76, 0x64, 0x31, 0x46, 0x56, 0x39, 0x59, 0x58, 0x7a, 0x51, 0x70, 0x4e, 0x57, 0x65, 0x48, 0x54, +0x6b, 0x79, 0x4a, 0x46, 0x38, 0x39, 0x39, 0x31, 0x33, 0x73, 0x4e, 0x4e, 0x6c, 0x62, 0x67, 0x68, +0x70, 0x79, 0x63, 0x46, 0x30, 0x4c, 0x2b, 0x2f, 0x6a, 0x53, 0x78, 0x6c, 0x4b, 0x68, 0x50, 0x76, +0x34, 0x43, 0x42, 0x54, 0x53, 0x30, 0x38, 0x69, 0x49, 0x52, 0x6b, 0x62, 0x79, 0x67, 0x54, 0x71, +0x30, 0x31, 0x75, 0x45, 0x79, 0x32, 0x59, 0x39, 0x70, 0x41, 0x41, 0x42, 0x62, 0x67, 0x44, 0x4e, +0x51, 0x35, 0x6d, 0x44, 0x4c, 0x72, 0x68, 0x42, 0x6c, 0x7a, 0x70, 0x44, 0x55, 0x58, 0x72, 0x79, +0x73, 0x45, 0x62, 0x48, 0x6f, 0x66, 0x43, 0x65, 0x36, 0x32, 0x63, 0x43, 0x49, 0x49, 0x65, 0x57, +0x41, 0x35, 0x6b, 0x6f, 0x61, 0x69, 0x53, 0x59, 0x57, 0x6f, 0x44, 0x74, 0x58, 0x2f, 0x7a, 0x67, +0x55, 0x4e, 0x54, 0x6d, 0x53, 0x50, 0x59, 0x45, 0x61, 0x49, 0x4e, 0x71, 0x30, 0x45, 0x76, 0x33, +0x74, 0x61, 0x74, 0x69, 0x32, 0x6d, 0x67, 0x66, 0x33, 0x2f, 0x77, 0x6e, 0x65, 0x42, 0x39, 0x2b, +0x51, 0x39, 0x39, 0x62, 0x72, 0x39, 0x4e, 0x6e, 0x65, 0x38, 0x79, 0x58, 0x4e, 0x39, 0x41, 0x4b, +0x6d, 0x4c, 0x46, 0x7a, 0x4e, 0x35, 0x35, 0x2b, 0x58, 0x73, 0x48, 0x70, 0x31, 0x77, 0x71, 0x30, +0x61, 0x57, 0x54, 0x75, 0x44, 0x74, 0x54, 0x55, 0x45, 0x56, 0x78, 0x50, 0x61, 0x49, 0x71, 0x51, +0x54, 0x58, 0x68, 0x30, 0x35, 0x73, 0x68, 0x42, 0x59, 0x42, 0x50, 0x49, 0x58, 0x6c, 0x6a, 0x5a, +0x30, 0x4b, 0x4c, 0x4e, 0x55, 0x68, 0x6e, 0x59, 0x31, 0x6d, 0x72, 0x46, 0x56, 0x68, 0x6a, 0x74, +0x65, 0x50, 0x59, 0x53, 0x55, 0x62, 0x7a, 0x6a, 0x36, 0x78, 0x47, 0x47, 0x73, 0x58, 0x65, 0x57, +0x38, 0x36, 0x48, 0x52, 0x51, 0x41, 0x51, 0x6e, 0x58, 0x78, 0x45, 0x4e, 0x56, 0x61, 0x52, 0x32, +0x6f, 0x53, 0x76, 0x76, 0x4f, 0x43, 0x47, 0x6a, 0x76, 0x76, 0x59, 0x43, 0x70, 0x37, 0x77, 0x36, +0x6c, 0x6c, 0x72, 0x70, 0x4c, 0x2b, 0x46, 0x6f, 0x62, 0x58, 0x6c, 0x7a, 0x6f, 0x70, 0x6b, 0x33, +0x61, 0x38, 0x4d, 0x30, 0x47, 0x61, 0x77, 0x76, 0x77, 0x56, 0x55, 0x37, 0x34, 0x45, 0x68, 0x72, +0x66, 0x66, 0x62, 0x66, 0x48, 0x6e, 0x72, 0x33, 0x78, 0x77, 0x77, 0x38, 0x42, 0x4b, 0x7a, 0x33, +0x5a, 0x30, 0x2b, 0x46, 0x31, 0x4e, 0x46, 0x4b, 0x61, 0x56, 0x32, 0x61, 0x6c, 0x2b, 0x4e, 0x30, +0x6f, 0x4b, 0x6a, 0x42, 0x57, 0x43, 0x2b, 0x6e, 0x62, 0x44, 0x69, 0x7a, 0x44, 0x70, 0x71, 0x4c, +0x52, 0x59, 0x43, 0x44, 0x71, 0x52, 0x57, 0x6c, 0x6f, 0x57, 0x4f, 0x64, 0x55, 0x67, 0x62, 0x57, +0x6b, 0x66, 0x31, 0x6c, 0x2f, 0x74, 0x39, 0x59, 0x66, 0x79, 0x48, 0x5a, 0x5a, 0x66, 0x44, 0x42, +0x51, 0x39, 0x4a, 0x33, 0x2b, 0x37, 0x55, 0x73, 0x6f, 0x71, 0x52, 0x68, 0x63, 0x4f, 0x63, 0x53, +0x75, 0x30, 0x37, 0x72, 0x4a, 0x32, 0x36, 0x6c, 0x37, 0x33, 0x30, 0x78, 0x31, 0x78, 0x59, 0x6e, +0x55, 0x44, 0x46, 0x2f, 0x4d, 0x69, 0x70, 0x5a, 0x71, 0x2f, 0x6a, 0x70, 0x33, 0x4b, 0x39, 0x4c, +0x45, 0x47, 0x64, 0x53, 0x37, 0x4f, 0x50, 0x30, 0x62, 0x4d, 0x6a, 0x32, 0x2f, 0x55, 0x6b, 0x37, +0x52, 0x4e, 0x46, 0x44, 0x31, 0x6a, 0x58, 0x76, 0x76, 0x4d, 0x6d, 0x72, 0x70, 0x66, 0x70, 0x6a, +0x56, 0x50, 0x38, 0x48, 0x38, 0x63, 0x51, 0x4b, 0x74, 0x34, 0x33, 0x64, 0x6d, 0x62, 0x58, 0x34, +0x37, 0x71, 0x37, 0x62, 0x2b, 0x6c, 0x2b, 0x39, 0x72, 0x6c, 0x37, 0x4b, 0x73, 0x65, 0x52, 0x6b, +0x62, 0x4f, 0x7a, 0x65, 0x53, 0x53, 0x43, 0x62, 0x73, 0x38, 0x79, 0x68, 0x71, 0x53, 0x6d, 0x72, +0x73, 0x38, 0x33, 0x6c, 0x77, 0x38, 0x6a, 0x33, 0x37, 0x63, 0x4f, 0x76, 0x6b, 0x67, 0x52, 0x68, +0x6a, 0x50, 0x64, 0x58, 0x4f, 0x66, 0x48, 0x45, 0x6c, 0x63, 0x6e, 0x30, 0x62, 0x67, 0x38, 0x5a, +0x56, 0x49, 0x54, 0x79, 0x37, 0x42, 0x69, 0x2b, 0x71, 0x69, 0x2f, 0x6a, 0x67, 0x33, 0x2f, 0x57, +0x38, 0x73, 0x36, 0x69, 0x5a, 0x39, 0x38, 0x34, 0x66, 0x51, 0x35, 0x34, 0x48, 0x2f, 0x2f, 0x72, +0x74, 0x54, 0x70, 0x54, 0x4e, 0x50, 0x52, 0x62, 0x61, 0x6e, 0x36, 0x61, 0x67, 0x6f, 0x5a, 0x43, +0x69, 0x54, 0x34, 0x71, 0x6f, 0x72, 0x71, 0x78, 0x47, 0x6c, 0x69, 0x6d, 0x6b, 0x54, 0x43, 0x76, +0x78, 0x35, 0x4b, 0x71, 0x71, 0x68, 0x76, 0x45, 0x50, 0x43, 0x6f, 0x42, 0x76, 0x6c, 0x39, 0x61, +0x71, 0x79, 0x34, 0x73, 0x52, 0x55, 0x6b, 0x48, 0x65, 0x41, 0x4c, 0x75, 0x4d, 0x70, 0x41, 0x57, +0x44, 0x4b, 0x6b, 0x76, 0x53, 0x36, 0x72, 0x6f, 0x36, 0x51, 0x78, 0x58, 0x59, 0x4b, 0x51, 0x4e, +0x44, 0x32, 0x6d, 0x6b, 0x6c, 0x71, 0x50, 0x78, 0x5a, 0x6d, 0x5a, 0x75, 0x72, 0x4b, 0x6d, 0x73, +0x2f, 0x4a, 0x66, 0x41, 0x6f, 0x73, 0x7a, 0x6d, 0x51, 0x52, 0x43, 0x68, 0x4e, 0x2f, 0x7a, 0x35, +0x46, 0x49, 0x51, 0x73, 0x66, 0x37, 0x45, 0x55, 0x67, 0x77, 0x36, 0x76, 0x44, 0x63, 0x4b, 0x56, +0x79, 0x53, 0x47, 0x34, 0x42, 0x53, 0x6d, 0x6b, 0x67, 0x69, 0x65, 0x5a, 0x2f, 0x51, 0x31, 0x47, +0x7a, 0x6e, 0x71, 0x2b, 0x72, 0x70, 0x2f, 0x43, 0x6c, 0x35, 0x32, 0x77, 0x76, 0x4e, 0x47, 0x6a, +0x51, 0x6a, 0x71, 0x47, 0x73, 0x32, 0x48, 0x30, 0x42, 0x71, 0x71, 0x76, 0x6a, 0x7a, 0x73, 0x33, +0x56, 0x4f, 0x66, 0x59, 0x34, 0x4e, 0x61, 0x72, 0x67, 0x50, 0x68, 0x67, 0x5a, 0x42, 0x48, 0x37, +0x2f, 0x79, 0x74, 0x6b, 0x67, 0x72, 0x4b, 0x35, 0x2f, 0x68, 0x4e, 0x37, 0x46, 0x5a, 0x50, 0x54, +0x43, 0x73, 0x47, 0x77, 0x4c, 0x44, 0x4a, 0x74, 0x34, 0x43, 0x6b, 0x6f, 0x62, 0x6c, 0x6d, 0x34, +0x78, 0x31, 0x4a, 0x54, 0x51, 0x46, 0x57, 0x58, 0x57, 0x47, 0x76, 0x77, 0x63, 0x56, 0x65, 0x6c, +0x67, 0x47, 0x52, 0x43, 0x52, 0x6a, 0x51, 0x4a, 0x37, 0x33, 0x61, 0x50, 0x41, 0x4a, 0x4c, 0x73, +0x50, 0x33, 0x33, 0x49, 0x2f, 0x58, 0x6c, 0x6a, 0x5a, 0x72, 0x55, 0x4a, 0x50, 0x56, 0x35, 0x53, +0x36, 0x65, 0x44, 0x75, 0x56, 0x65, 0x30, 0x65, 0x4f, 0x50, 0x6a, 0x66, 0x33, 0x34, 0x64, 0x78, +0x6a, 0x7a, 0x72, 0x4d, 0x37, 0x58, 0x6f, 0x66, 0x71, 0x32, 0x33, 0x61, 0x39, 0x50, 0x2b, 0x30, +0x37, 0x49, 0x75, 0x30, 0x4b, 0x68, 0x7a, 0x4e, 0x79, 0x61, 0x72, 0x66, 0x63, 0x4f, 0x66, 0x2f, +0x75, 0x65, 0x55, 0x34, 0x56, 0x4f, 0x49, 0x66, 0x75, 0x49, 0x37, 0x58, 0x6a, 0x45, 0x66, 0x6a, +0x69, 0x45, 0x64, 0x69, 0x55, 0x42, 0x34, 0x2f, 0x4f, 0x68, 0x59, 0x2b, 0x65, 0x77, 0x36, 0x6f, +0x6b, 0x2f, 0x6f, 0x6a, 0x6a, 0x6a, 0x70, 0x2b, 0x56, 0x6f, 0x34, 0x73, 0x6b, 0x30, 0x77, 0x2b, +0x75, 0x59, 0x54, 0x48, 0x66, 0x77, 0x77, 0x4b, 0x73, 0x56, 0x47, 0x6f, 0x7a, 0x61, 0x66, 0x6f, +0x72, 0x30, 0x50, 0x44, 0x4d, 0x52, 0x57, 0x46, 0x4c, 0x6f, 0x50, 0x62, 0x56, 0x57, 0x72, 0x54, +0x57, 0x48, 0x50, 0x48, 0x38, 0x65, 0x72, 0x36, 0x2f, 0x34, 0x54, 0x4f, 0x49, 0x46, 0x30, 0x42, +0x4e, 0x43, 0x62, 0x51, 0x6e, 0x72, 0x59, 0x55, 0x6d, 0x55, 0x48, 0x6f, 0x46, 0x4d, 0x46, 0x76, +0x73, 0x44, 0x35, 0x39, 0x38, 0x4b, 0x49, 0x74, 0x75, 0x32, 0x68, 0x32, 0x41, 0x63, 0x52, 0x65, +0x4f, 0x6f, 0x35, 0x73, 0x74, 0x35, 0x6e, 0x66, 0x38, 0x71, 0x44, 0x34, 0x6e, 0x69, 0x2b, 0x37, +0x62, 0x2b, 0x75, 0x53, 0x72, 0x64, 0x6d, 0x6c, 0x52, 0x51, 0x70, 0x2f, 0x7a, 0x4a, 0x32, 0x5a, +0x45, 0x76, 0x48, 0x75, 0x55, 0x75, 0x4b, 0x50, 0x78, 0x6d, 0x78, 0x78, 0x4b, 0x54, 0x61, 0x4a, +0x37, 0x63, 0x47, 0x6a, 0x42, 0x45, 0x57, 0x77, 0x68, 0x61, 0x51, 0x65, 0x4d, 0x32, 0x75, 0x4f, +0x66, 0x57, 0x4b, 0x7a, 0x35, 0x78, 0x33, 0x4b, 0x67, 0x4e, 0x67, 0x45, 0x37, 0x6d, 0x50, 0x30, +0x2f, 0x6f, 0x61, 0x6a, 0x39, 0x65, 0x2f, 0x69, 0x2f, 0x48, 0x58, 0x31, 0x2b, 0x42, 0x43, 0x2b, +0x54, 0x6a, 0x61, 0x70, 0x31, 0x64, 0x2b, 0x71, 0x63, 0x2b, 0x34, 0x78, 0x66, 0x4f, 0x65, 0x66, +0x36, 0x62, 0x4c, 0x72, 0x4f, 0x31, 0x2b, 0x36, 0x56, 0x64, 0x54, 0x5a, 0x39, 0x6c, 0x2f, 0x6c, +0x33, 0x68, 0x6f, 0x34, 0x42, 0x6b, 0x30, 0x5a, 0x30, 0x53, 0x61, 0x70, 0x47, 0x42, 0x30, 0x65, +0x47, 0x46, 0x4b, 0x41, 0x47, 0x37, 0x59, 0x50, 0x65, 0x76, 0x5a, 0x76, 0x34, 0x58, 0x2b, 0x56, +0x51, 0x36, 0x74, 0x7a, 0x77, 0x75, 0x77, 0x73, 0x33, 0x46, 0x36, 0x55, 0x75, 0x67, 0x54, 0x56, +0x66, 0x6a, 0x32, 0x6a, 0x6d, 0x66, 0x7a, 0x69, 0x47, 0x54, 0x61, 0x45, 0x69, 0x56, 0x4d, 0x58, +0x75, 0x43, 0x53, 0x58, 0x58, 0x4f, 0x5a, 0x39, 0x6e, 0x31, 0x42, 0x2b, 0x76, 0x33, 0x39, 0x45, +0x58, 0x4a, 0x78, 0x72, 0x66, 0x2f, 0x31, 0x76, 0x73, 0x2f, 0x78, 0x4f, 0x34, 0x35, 0x33, 0x6e, +0x79, 0x66, 0x61, 0x55, 0x4b, 0x6a, 0x6e, 0x69, 0x45, 0x74, 0x4c, 0x4a, 0x73, 0x5a, 0x76, 0x6e, +0x75, 0x4c, 0x69, 0x39, 0x7a, 0x55, 0x45, 0x54, 0x6d, 0x4c, 0x67, 0x32, 0x57, 0x77, 0x39, 0x33, +0x7a, 0x47, 0x51, 0x6b, 0x56, 0x5a, 0x47, 0x52, 0x51, 0x69, 0x59, 0x58, 0x75, 0x45, 0x73, 0x41, +0x62, 0x6a, 0x36, 0x31, 0x6d, 0x2f, 0x31, 0x57, 0x72, 0x6b, 0x41, 0x32, 0x62, 0x69, 0x5a, 0x64, +0x58, 0x59, 0x57, 0x57, 0x78, 0x66, 0x7a, 0x6a, 0x75, 0x73, 0x6d, 0x34, 0x44, 0x72, 0x61, 0x74, +0x57, 0x73, 0x66, 0x50, 0x43, 0x75, 0x56, 0x6d, 0x66, 0x35, 0x35, 0x70, 0x6c, 0x66, 0x71, 0x67, +0x67, 0x58, 0x2f, 0x44, 0x41, 0x31, 0x33, 0x51, 0x6d, 0x30, 0x30, 0x52, 0x4b, 0x6f, 0x4e, 0x62, +0x71, 0x4f, 0x78, 0x64, 0x56, 0x36, 0x57, 0x73, 0x33, 0x46, 0x64, 0x41, 0x6b, 0x70, 0x63, 0x54, +0x33, 0x33, 0x62, 0x30, 0x76, 0x4b, 0x59, 0x68, 0x46, 0x6d, 0x46, 0x34, 0x78, 0x6e, 0x2f, 0x63, +0x4c, 0x52, 0x76, 0x4f, 0x6e, 0x39, 0x31, 0x75, 0x5a, 0x30, 0x6a, 0x71, 0x44, 0x69, 0x70, 0x6a, +0x6b, 0x68, 0x75, 0x51, 0x6b, 0x54, 0x71, 0x39, 0x59, 0x77, 0x76, 0x45, 0x54, 0x2b, 0x6e, 0x4c, +0x69, 0x73, 0x30, 0x46, 0x4c, 0x6d, 0x4a, 0x76, 0x44, 0x4e, 0x69, 0x48, 0x37, 0x48, 0x48, 0x34, +0x64, 0x7a, 0x65, 0x32, 0x2b, 0x43, 0x7a, 0x75, 0x43, 0x53, 0x6b, 0x62, 0x34, 0x2f, 0x73, 0x6d, +0x4c, 0x36, 0x46, 0x76, 0x52, 0x59, 0x46, 0x64, 0x61, 0x74, 0x49, 0x2b, 0x4f, 0x47, 0x47, 0x51, +0x39, 0x4a, 0x49, 0x2f, 0x49, 0x62, 0x48, 0x72, 0x73, 0x64, 0x55, 0x7a, 0x68, 0x4e, 0x57, 0x48, +0x63, 0x54, 0x65, 0x66, 0x64, 0x34, 0x63, 0x69, 0x4f, 0x61, 0x44, 0x54, 0x38, 0x54, 0x70, 0x79, +0x7a, 0x75, 0x67, 0x6b, 0x2f, 0x43, 0x65, 0x52, 0x68, 0x65, 0x4b, 0x2f, 0x48, 0x39, 0x49, 0x76, +0x65, 0x52, 0x62, 0x6f, 0x68, 0x37, 0x79, 0x48, 0x2f, 0x7a, 0x62, 0x50, 0x30, 0x2b, 0x50, 0x79, +0x4f, 0x70, 0x4c, 0x2b, 0x61, 0x63, 0x52, 0x68, 0x45, 0x38, 0x79, 0x7a, 0x36, 0x5a, 0x32, 0x53, +0x41, 0x41, 0x50, 0x5a, 0x34, 0x47, 0x42, 0x52, 0x47, 0x74, 0x4b, 0x41, 0x54, 0x38, 0x35, 0x45, +0x64, 0x73, 0x4f, 0x72, 0x38, 0x37, 0x73, 0x4d, 0x6a, 0x49, 0x38, 0x71, 0x5a, 0x70, 0x53, 0x36, +0x33, 0x61, 0x4a, 0x39, 0x54, 0x50, 0x44, 0x75, 0x37, 0x2f, 0x45, 0x6f, 0x4e, 0x4a, 0x6d, 0x44, +0x6d, 0x57, 0x39, 0x32, 0x31, 0x42, 0x4e, 0x75, 0x4c, 0x35, 0x58, 0x4b, 0x35, 0x63, 0x45, 0x58, +0x31, 0x4f, 0x64, 0x7a, 0x66, 0x54, 0x4e, 0x68, 0x78, 0x2f, 0x74, 0x6a, 0x33, 0x72, 0x39, 0x72, +0x66, 0x66, 0x75, 0x38, 0x2f, 0x32, 0x36, 0x70, 0x70, 0x58, 0x72, 0x36, 0x52, 0x64, 0x75, 0x43, +0x73, 0x50, 0x65, 0x7a, 0x50, 0x46, 0x2b, 0x2b, 0x7a, 0x4b, 0x78, 0x32, 0x7a, 0x46, 0x6d, 0x5a, +0x6a, 0x2f, 0x44, 0x6b, 0x64, 0x66, 0x4b, 0x79, 0x6f, 0x70, 0x6b, 0x39, 0x42, 0x37, 0x34, 0x74, +0x57, 0x30, 0x2f, 0x44, 0x58, 0x6b, 0x57, 0x35, 0x68, 0x39, 0x45, 0x63, 0x64, 0x73, 0x51, 0x4f, +0x41, 0x62, 0x61, 0x31, 0x54, 0x2b, 0x66, 0x4e, 0x6b, 0x38, 0x49, 0x4a, 0x4e, 0x49, 0x31, 0x42, +0x75, 0x75, 0x32, 0x34, 0x4c, 0x62, 0x38, 0x68, 0x41, 0x44, 0x64, 0x69, 0x6b, 0x31, 0x59, 0x47, +0x46, 0x46, 0x72, 0x7a, 0x32, 0x74, 0x78, 0x6e, 0x67, 0x77, 0x77, 0x4e, 0x54, 0x2b, 0x39, 0x71, +0x58, 0x44, 0x56, 0x74, 0x63, 0x37, 0x5a, 0x61, 0x4b, 0x41, 0x70, 0x30, 0x33, 0x37, 0x42, 0x42, +0x51, 0x70, 0x51, 0x31, 0x45, 0x55, 0x68, 0x6b, 0x65, 0x75, 0x33, 0x45, 0x70, 0x38, 0x55, 0x45, +0x44, 0x36, 0x66, 0x58, 0x54, 0x79, 0x57, 0x79, 0x2b, 0x35, 0x50, 0x65, 0x30, 0x66, 0x50, 0x55, +0x56, 0x65, 0x62, 0x33, 0x36, 0x57, 0x6a, 0x78, 0x4c, 0x35, 0x79, 0x5a, 0x6c, 0x78, 0x6d, 0x45, +0x67, 0x74, 0x57, 0x6f, 0x56, 0x36, 0x36, 0x52, 0x67, 0x5a, 0x2f, 0x69, 0x66, 0x56, 0x47, 0x31, +0x31, 0x72, 0x4a, 0x55, 0x4c, 0x4a, 0x6f, 0x38, 0x4b, 0x66, 0x7a, 0x64, 0x51, 0x66, 0x7a, 0x58, +0x47, 0x44, 0x66, 0x65, 0x6c, 0x47, 0x79, 0x6f, 0x62, 0x37, 0x4c, 0x73, 0x45, 0x37, 0x36, 0x51, +0x31, 0x55, 0x35, 0x37, 0x37, 0x6a, 0x44, 0x4f, 0x2b, 0x7a, 0x47, 0x50, 0x57, 0x62, 0x55, 0x4d, +0x35, 0x37, 0x2f, 0x51, 0x42, 0x70, 0x4a, 0x59, 0x4e, 0x67, 0x37, 0x59, 0x32, 0x54, 0x71, 0x67, +0x5a, 0x51, 0x46, 0x6e, 0x56, 0x73, 0x62, 0x79, 0x39, 0x56, 0x6e, 0x48, 0x68, 0x4c, 0x6c, 0x74, +0x43, 0x6f, 0x59, 0x74, 0x77, 0x57, 0x4b, 0x2f, 0x74, 0x55, 0x48, 0x2f, 0x47, 0x76, 0x58, 0x39, +0x69, 0x53, 0x37, 0x50, 0x50, 0x2f, 0x58, 0x38, 0x59, 0x61, 0x39, 0x50, 0x50, 0x67, 0x42, 0x41, +0x65, 0x76, 0x59, 0x66, 0x63, 0x51, 0x48, 0x35, 0x65, 0x4a, 0x33, 0x6d, 0x75, 0x55, 0x68, 0x6a, +0x50, 0x6f, 0x45, 0x74, 0x38, 0x43, 0x69, 0x2b, 0x70, 0x52, 0x79, 0x76, 0x70, 0x35, 0x72, 0x47, +0x53, 0x2b, 0x71, 0x65, 0x66, 0x42, 0x75, 0x44, 0x50, 0x44, 0x2f, 0x77, 0x38, 0x70, 0x4d, 0x62, +0x43, 0x70, 0x61, 0x66, 0x4c, 0x72, 0x77, 0x6a, 0x66, 0x2f, 0x37, 0x4b, 0x2b, 0x78, 0x36, 0x47, +0x6c, 0x64, 0x4f, 0x6b, 0x75, 0x33, 0x64, 0x42, 0x63, 0x38, 0x63, 0x4a, 0x66, 0x58, 0x46, 0x63, +0x5a, 0x70, 0x46, 0x38, 0x30, 0x69, 0x70, 0x64, 0x4b, 0x51, 0x53, 0x79, 0x47, 0x30, 0x59, 0x62, +0x4c, 0x44, 0x6d, 0x74, 0x44, 0x70, 0x49, 0x4a, 0x64, 0x6d, 0x39, 0x4e, 0x54, 0x79, 0x6b, 0x41, +0x64, 0x2b, 0x6f, 0x33, 0x48, 0x6e, 0x53, 0x72, 0x30, 0x62, 0x62, 0x65, 0x35, 0x39, 0x46, 0x64, +0x34, 0x7a, 0x6a, 0x68, 0x6d, 0x74, 0x41, 0x45, 0x70, 0x38, 0x4a, 0x53, 0x79, 0x36, 0x52, 0x2b, +0x71, 0x51, 0x34, 0x6b, 0x51, 0x6a, 0x32, 0x36, 0x66, 0x50, 0x68, 0x32, 0x6a, 0x32, 0x6a, 0x6e, +0x7a, 0x6e, 0x6b, 0x73, 0x34, 0x56, 0x33, 0x2f, 0x47, 0x34, 0x58, 0x6d, 0x4c, 0x4b, 0x61, 0x43, +0x56, 0x56, 0x7a, 0x72, 0x33, 0x35, 0x65, 0x37, 0x6b, 0x4a, 0x46, 0x73, 0x4c, 0x69, 0x48, 0x42, +0x56, 0x34, 0x53, 0x79, 0x4f, 0x69, 0x79, 0x38, 0x69, 0x46, 0x70, 0x57, 0x73, 0x54, 0x46, 0x5a, +0x78, 0x78, 0x71, 0x61, 0x54, 0x57, 0x4c, 0x43, 0x75, 0x41, 0x76, 0x69, 0x65, 0x2f, 0x33, 0x49, +0x72, 0x6f, 0x7a, 0x4c, 0x79, 0x33, 0x32, 0x54, 0x6b, 0x76, 0x77, 0x36, 0x73, 0x36, 0x35, 0x6c, +0x65, 0x6e, 0x53, 0x35, 0x38, 0x4c, 0x51, 0x53, 0x66, 0x7a, 0x70, 0x67, 0x42, 0x53, 0x5a, 0x6a, +0x36, 0x55, 0x4b, 0x41, 0x71, 0x62, 0x4d, 0x67, 0x7a, 0x48, 0x65, 0x79, 0x31, 0x30, 0x79, 0x4c, +0x47, 0x6a, 0x31, 0x78, 0x47, 0x72, 0x35, 0x4a, 0x74, 0x47, 0x43, 0x33, 0x5a, 0x30, 0x6c, 0x62, +0x43, 0x31, 0x30, 0x74, 0x47, 0x38, 0x65, 0x6e, 0x38, 0x58, 0x57, 0x68, 0x73, 0x4c, 0x67, 0x70, +0x64, 0x70, 0x47, 0x63, 0x38, 0x50, 0x6f, 0x73, 0x48, 0x4e, 0x73, 0x4a, 0x68, 0x2f, 0x37, 0x71, +0x65, 0x6f, 0x38, 0x76, 0x42, 0x2b, 0x30, 0x4c, 0x6a, 0x64, 0x61, 0x6f, 0x66, 0x6a, 0x61, 0x4a, +0x66, 0x50, 0x2b, 0x55, 0x42, 0x68, 0x6d, 0x39, 0x4d, 0x59, 0x58, 0x51, 0x2b, 0x65, 0x52, 0x56, +0x46, 0x58, 0x4a, 0x58, 0x58, 0x54, 0x48, 0x46, 0x2b, 0x49, 0x55, 0x33, 0x74, 0x7a, 0x66, 0x78, +0x69, 0x79, 0x70, 0x4e, 0x38, 0x75, 0x32, 0x59, 0x78, 0x69, 0x2b, 0x70, 0x57, 0x70, 0x4e, 0x4e, +0x66, 0x32, 0x6d, 0x58, 0x50, 0x4e, 0x36, 0x63, 0x38, 0x54, 0x6b, 0x78, 0x32, 0x43, 0x6c, 0x6c, +0x30, 0x79, 0x49, 0x42, 0x59, 0x33, 0x37, 0x4a, 0x4e, 0x74, 0x44, 0x31, 0x31, 0x43, 0x49, 0x6c, +0x4e, 0x69, 0x33, 0x65, 0x34, 0x39, 0x6e, 0x75, 0x65, 0x4a, 0x34, 0x75, 0x4d, 0x69, 0x5a, 0x6e, +0x2f, 0x4b, 0x2b, 0x36, 0x38, 0x77, 0x36, 0x51, 0x71, 0x73, 0x72, 0x44, 0x2f, 0x75, 0x35, 0x30, +0x6d, 0x77, 0x77, 0x77, 0x7a, 0x68, 0x41, 0x47, 0x47, 0x6e, 0x45, 0x56, 0x52, 0x42, 0x4c, 0x4f, +0x69, 0x4b, 0x4b, 0x69, 0x34, 0x35, 0x68, 0x79, 0x57, 0x64, 0x63, 0x32, 0x4b, 0x45, 0x52, 0x46, +0x63, 0x46, 0x64, 0x46, 0x56, 0x58, 0x41, 0x50, 0x4c, 0x6f, 0x71, 0x75, 0x75, 0x72, 0x67, 0x6b, +0x78, 0x59, 0x6c, 0x67, 0x56, 0x4d, 0x79, 0x49, 0x43, 0x41, 0x70, 0x4a, 0x46, 0x55, 0x56, 0x54, +0x43, 0x6b, 0x47, 0x45, 0x43, 0x54, 0x47, 0x42, 0x43, 0x64, 0x31, 0x66, 0x38, 0x2f, 0x71, 0x6a, +0x62, 0x50, 0x54, 0x30, 0x7a, 0x6f, 0x4c, 0x4c, 0x73, 0x39, 0x33, 0x33, 0x31, 0x50, 0x50, 0x65, +0x35, 0x74, 0x32, 0x65, 0x36, 0x2b, 0x74, 0x61, 0x39, 0x56, 0x61, 0x66, 0x71, 0x31, 0x44, 0x6e, +0x76, 0x65, 0x59, 0x2b, 0x32, 0x33, 0x50, 0x54, 0x79, 0x4e, 0x73, 0x61, 0x64, 0x34, 0x2f, 0x62, +0x47, 0x79, 0x66, 0x52, 0x4c, 0x70, 0x73, 0x47, 0x77, 0x34, 0x6a, 0x72, 0x65, 0x70, 0x57, 0x77, +0x53, 0x53, 0x74, 0x49, 0x78, 0x75, 0x38, 0x67, 0x50, 0x30, 0x44, 0x4e, 0x6f, 0x41, 0x79, 0x55, +0x37, 0x45, 0x39, 0x52, 0x4f, 0x44, 0x65, 0x53, 0x4d, 0x4f, 0x6b, 0x6e, 0x56, 0x55, 0x76, 0x75, +0x4b, 0x71, 0x51, 0x41, 0x41, 0x49, 0x41, 0x42, 0x4a, 0x52, 0x45, 0x46, 0x55, 0x5a, 0x4a, 0x49, +0x2b, 0x36, 0x51, 0x51, 0x61, 0x72, 0x62, 0x42, 0x31, 0x47, 0x50, 0x78, 0x6f, 0x76, 0x33, 0x43, +0x58, 0x54, 0x6e, 0x54, 0x38, 0x36, 0x48, 0x31, 0x32, 0x33, 0x54, 0x53, 0x47, 0x6b, 0x71, 0x66, +0x2f, 0x51, 0x54, 0x67, 0x74, 0x68, 0x31, 0x42, 0x2b, 0x67, 0x55, 0x4e, 0x46, 0x37, 0x61, 0x6b, +0x59, 0x77, 0x32, 0x35, 0x6a, 0x71, 0x45, 0x6c, 0x50, 0x54, 0x38, 0x34, 0x49, 0x2f, 0x79, 0x32, +0x72, 0x37, 0x62, 0x54, 0x49, 0x63, 0x43, 0x4c, 0x68, 0x78, 0x37, 0x48, 0x52, 0x4d, 0x6a, 0x2f, +0x39, 0x56, 0x53, 0x49, 0x78, 0x68, 0x6e, 0x4a, 0x6e, 0x71, 0x38, 0x42, 0x49, 0x35, 0x36, 0x6f, +0x78, 0x30, 0x6f, 0x57, 0x68, 0x47, 0x6b, 0x55, 0x67, 0x6f, 0x79, 0x33, 0x44, 0x51, 0x6b, 0x39, +0x52, 0x74, 0x62, 0x6d, 0x51, 0x6a, 0x44, 0x57, 0x74, 0x69, 0x43, 0x79, 0x65, 0x54, 0x62, 0x79, +0x71, 0x47, 0x6c, 0x30, 0x58, 0x4a, 0x61, 0x30, 0x67, 0x6c, 0x36, 0x6a, 0x32, 0x47, 0x46, 0x49, +0x76, 0x6d, 0x4d, 0x6b, 0x67, 0x64, 0x6f, 0x73, 0x51, 0x52, 0x61, 0x31, 0x32, 0x30, 0x79, 0x36, +0x72, 0x43, 0x68, 0x4d, 0x32, 0x62, 0x4e, 0x79, 0x5a, 0x6a, 0x72, 0x54, 0x74, 0x41, 0x4a, 0x47, +0x45, 0x6f, 0x70, 0x5a, 0x57, 0x78, 0x48, 0x31, 0x57, 0x47, 0x51, 0x38, 0x6c, 0x79, 0x6a, 0x43, +0x42, 0x57, 0x70, 0x2b, 0x41, 0x55, 0x32, 0x4d, 0x38, 0x68, 0x59, 0x33, 0x46, 0x6b, 0x63, 0x55, +0x62, 0x58, 0x54, 0x75, 0x6b, 0x49, 0x4e, 0x43, 0x68, 0x51, 0x78, 0x4a, 0x4a, 0x61, 0x37, 0x47, +0x55, 0x6c, 0x4e, 0x63, 0x6c, 0x58, 0x34, 0x2b, 0x31, 0x46, 0x6a, 0x5a, 0x74, 0x54, 0x44, 0x37, +0x37, 0x78, 0x6e, 0x67, 0x6c, 0x32, 0x6b, 0x2f, 0x5a, 0x4a, 0x58, 0x32, 0x69, 0x32, 0x41, 0x36, +0x46, 0x4c, 0x55, 0x67, 0x75, 0x66, 0x65, 0x6e, 0x70, 0x32, 0x48, 0x62, 0x74, 0x59, 0x50, 0x42, +0x67, 0x65, 0x48, 0x6b, 0x61, 0x31, 0x6b, 0x65, 0x6c, 0x33, 0x5a, 0x74, 0x58, 0x54, 0x55, 0x6a, +0x37, 0x57, 0x49, 0x67, 0x45, 0x71, 0x34, 0x34, 0x52, 0x47, 0x43, 0x4d, 0x4a, 0x70, 0x42, 0x55, +0x78, 0x63, 0x51, 0x51, 0x77, 0x6f, 0x37, 0x6e, 0x39, 0x34, 0x2f, 0x63, 0x59, 0x52, 0x44, 0x33, +0x50, 0x77, 0x7a, 0x7a, 0x2b, 0x4f, 0x47, 0x62, 0x4f, 0x34, 0x61, 0x77, 0x74, 0x7a, 0x57, 0x51, +0x55, 0x51, 0x2b, 0x67, 0x66, 0x4b, 0x75, 0x44, 0x57, 0x72, 0x41, 0x57, 0x63, 0x6c, 0x2f, 0x55, +0x38, 0x65, 0x66, 0x6f, 0x6e, 0x52, 0x6c, 0x5a, 0x64, 0x51, 0x4c, 0x77, 0x75, 0x7a, 0x4f, 0x37, +0x49, 0x54, 0x6a, 0x4b, 0x4b, 0x46, 0x72, 0x49, 0x32, 0x31, 0x6f, 0x2b, 0x54, 0x53, 0x79, 0x36, +0x68, 0x74, 0x46, 0x4a, 0x7a, 0x55, 0x2b, 0x45, 0x72, 0x6e, 0x4a, 0x4d, 0x35, 0x45, 0x39, 0x61, +0x37, 0x4e, 0x79, 0x43, 0x32, 0x62, 0x73, 0x4d, 0x6d, 0x39, 0x76, 0x62, 0x53, 0x70, 0x33, 0x4f, +0x58, 0x4b, 0x54, 0x79, 0x4f, 0x4b, 0x59, 0x41, 0x73, 0x49, 0x79, 0x55, 0x52, 0x48, 0x34, 0x71, +0x64, 0x5a, 0x46, 0x55, 0x75, 0x46, 0x58, 0x68, 0x57, 0x38, 0x62, 0x65, 0x62, 0x4f, 0x2f, 0x48, +0x6b, 0x79, 0x31, 0x74, 0x70, 0x30, 0x36, 0x4b, 0x47, 0x75, 0x54, 0x39, 0x30, 0x52, 0x6b, 0x6d, +0x4c, 0x4e, 0x6f, 0x71, 0x42, 0x6e, 0x62, 0x39, 0x43, 0x52, 0x58, 0x39, 0x6d, 0x36, 0x71, 0x63, +0x6e, 0x73, 0x6e, 0x31, 0x6e, 0x43, 0x34, 0x72, 0x61, 0x70, 0x35, 0x46, 0x59, 0x37, 0x78, 0x65, +0x74, 0x4e, 0x4f, 0x7a, 0x6f, 0x76, 0x59, 0x30, 0x2f, 0x58, 0x57, 0x59, 0x49, 0x76, 0x36, 0x6d, +0x78, 0x33, 0x34, 0x70, 0x39, 0x67, 0x36, 0x4a, 0x62, 0x32, 0x4c, 0x31, 0x78, 0x47, 0x79, 0x33, +0x62, 0x42, 0x69, 0x6c, 0x62, 0x46, 0x69, 0x58, 0x33, 0x78, 0x49, 0x4e, 0x59, 0x76, 0x75, 0x46, +0x48, 0x2b, 0x68, 0x66, 0x31, 0x35, 0x47, 0x38, 0x66, 0x50, 0x63, 0x75, 0x2f, 0x2f, 0x2f, 0x77, +0x41, 0x79, 0x7a, 0x66, 0x2b, 0x51, 0x48, 0x48, 0x5a, 0x5a, 0x70, 0x66, 0x69, 0x54, 0x77, 0x6f, +0x36, 0x46, 0x68, 0x51, 0x43, 0x45, 0x41, 0x70, 0x34, 0x59, 0x4c, 0x62, 0x55, 0x55, 0x32, 0x5a, +0x79, 0x34, 0x64, 0x68, 0x76, 0x2b, 0x48, 0x7a, 0x30, 0x44, 0x6f, 0x37, 0x72, 0x6f, 0x49, 0x69, +0x46, 0x57, 0x69, 0x49, 0x44, 0x59, 0x51, 0x4a, 0x32, 0x37, 0x79, 0x76, 0x70, 0x4c, 0x61, 0x4e, +0x48, 0x77, 0x78, 0x74, 0x76, 0x6b, 0x42, 0x6d, 0x31, 0x65, 0x47, 0x6d, 0x61, 0x4a, 0x31, 0x5a, +0x72, 0x37, 0x4f, 0x55, 0x53, 0x59, 0x7a, 0x56, 0x4a, 0x68, 0x68, 0x49, 0x6b, 0x4a, 0x67, 0x47, +0x41, 0x77, 0x56, 0x6c, 0x56, 0x6a, 0x5a, 0x59, 0x45, 0x41, 0x35, 0x4b, 0x50, 0x43, 0x36, 0x42, +0x62, 0x71, 0x41, 0x76, 0x64, 0x69, 0x79, 0x49, 0x49, 0x30, 0x5a, 0x68, 0x52, 0x78, 0x69, 0x54, +0x63, 0x62, 0x38, 0x5a, 0x70, 0x64, 0x63, 0x62, 0x6e, 0x66, 0x48, 0x66, 0x4a, 0x52, 0x53, 0x31, +0x70, 0x6b, 0x51, 0x43, 0x48, 0x39, 0x75, 0x77, 0x44, 0x72, 0x49, 0x46, 0x64, 0x57, 0x36, 0x6c, +0x63, 0x39, 0x67, 0x77, 0x74, 0x78, 0x31, 0x39, 0x4b, 0x75, 0x47, 0x38, 0x66, 0x64, 0x6f, 0x79, +0x36, 0x44, 0x72, 0x47, 0x31, 0x6d, 0x6b, 0x6a, 0x37, 0x72, 0x6e, 0x75, 0x63, 0x42, 0x46, 0x4b, +0x4a, 0x6d, 0x58, 0x5a, 0x58, 0x56, 0x35, 0x4f, 0x54, 0x6b, 0x37, 0x4e, 0x50, 0x67, 0x79, 0x38, +0x42, 0x52, 0x4b, 0x6e, 0x59, 0x74, 0x49, 0x6b, 0x58, 0x2b, 0x2f, 0x5a, 0x6c, 0x32, 0x46, 0x2b, +0x32, 0x55, 0x62, 0x4e, 0x6c, 0x43, 0x31, 0x5a, 0x72, 0x51, 0x6c, 0x61, 0x79, 0x4d, 0x61, 0x37, +0x35, 0x78, 0x49, 0x4a, 0x55, 0x67, 0x6c, 0x64, 0x65, 0x66, 0x70, 0x48, 0x61, 0x48, 0x31, 0x66, +0x78, 0x2f, 0x5a, 0x4e, 0x54, 0x71, 0x4e, 0x36, 0x77, 0x44, 0x53, 0x30, 0x46, 0x73, 0x62, 0x67, +0x6b, 0x72, 0x31, 0x4d, 0x6e, 0x6e, 0x70, 0x38, 0x46, 0x42, 0x77, 0x38, 0x65, 0x79, 0x70, 0x39, +0x37, 0x48, 0x6b, 0x44, 0x57, 0x72, 0x71, 0x33, 0x55, 0x2f, 0x72, 0x49, 0x65, 0x72, 0x31, 0x56, +0x72, 0x30, 0x72, 0x70, 0x33, 0x6f, 0x57, 0x78, 0x7a, 0x4f, 0x61, 0x73, 0x7a, 0x4d, 0x6f, 0x69, +0x57, 0x67, 0x68, 0x43, 0x4b, 0x65, 0x34, 0x66, 0x4d, 0x49, 0x44, 0x2b, 0x76, 0x42, 0x64, 0x47, +0x71, 0x31, 0x58, 0x79, 0x33, 0x6f, 0x77, 0x4f, 0x54, 0x46, 0x76, 0x30, 0x4a, 0x45, 0x41, 0x36, +0x4b, 0x61, 0x68, 0x75, 0x41, 0x4b, 0x46, 0x4c, 0x6a, 0x33, 0x6a, 0x2f, 0x4f, 0x32, 0x47, 0x4f, +0x4e, 0x78, 0x6e, 0x72, 0x61, 0x34, 0x65, 0x4b, 0x6c, 0x39, 0x48, 0x4d, 0x56, 0x53, 0x41, 0x49, +0x4a, 0x52, 0x68, 0x77, 0x4d, 0x52, 0x6f, 0x4e, 0x57, 0x75, 0x76, 0x48, 0x7a, 0x43, 0x2b, 0x46, +0x57, 0x47, 0x69, 0x45, 0x64, 0x55, 0x55, 0x71, 0x4b, 0x56, 0x30, 0x48, 0x35, 0x52, 0x43, 0x6d, +0x4a, 0x4b, 0x45, 0x34, 0x72, 0x42, 0x41, 0x77, 0x5a, 0x41, 0x6a, 0x31, 0x36, 0x59, 0x47, 0x2b, +0x36, 0x45, 0x63, 0x61, 0x50, 0x78, 0x30, 0x70, 0x4a, 0x69, 0x77, 0x79, 0x4a, 0x72, 0x5a, 0x4e, +0x59, 0x54, 0x32, 0x41, 0x52, 0x44, 0x70, 0x54, 0x69, 0x75, 0x62, 0x50, 0x6e, 0x53, 0x56, 0x70, +0x46, 0x59, 0x4f, 0x6a, 0x77, 0x47, 0x64, 0x78, 0x34, 0x66, 0x58, 0x38, 0x71, 0x4b, 0x75, 0x4a, +0x6f, 0x59, 0x7a, 0x45, 0x4a, 0x64, 0x74, 0x38, 0x45, 0x68, 0x34, 0x44, 0x50, 0x30, 0x5a, 0x43, +0x45, 0x45, 0x30, 0x74, 0x6e, 0x42, 0x38, 0x6c, 0x76, 0x6c, 0x63, 0x48, 0x59, 0x4f, 0x7a, 0x35, +0x69, 0x2b, 0x32, 0x73, 0x37, 0x65, 0x49, 0x68, 0x70, 0x4c, 0x41, 0x74, 0x6b, 0x38, 0x55, 0x46, +0x56, 0x56, 0x30, 0x34, 0x72, 0x4f, 0x35, 0x57, 0x54, 0x30, 0x2f, 0x73, 0x79, 0x4f, 0x66, 0x39, +0x64, 0x37, 0x6f, 0x2f, 0x2f, 0x68, 0x7a, 0x48, 0x65, 0x4d, 0x4c, 0x72, 0x30, 0x2b, 0x70, 0x47, +0x74, 0x57, 0x33, 0x4b, 0x35, 0x74, 0x48, 0x77, 0x45, 0x78, 0x36, 0x53, 0x76, 0x59, 0x45, 0x4c, +0x37, 0x74, 0x34, 0x6a, 0x59, 0x47, 0x46, 0x2f, 0x56, 0x74, 0x32, 0x64, 0x6b, 0x33, 0x56, 0x6f, +0x79, 0x4d, 0x6a, 0x4b, 0x61, 0x39, 0x62, 0x39, 0x59, 0x64, 0x78, 0x2b, 0x42, 0x37, 0x41, 0x4f, +0x77, 0x42, 0x4e, 0x48, 0x56, 0x69, 0x77, 0x68, 0x32, 0x75, 0x52, 0x76, 0x72, 0x5a, 0x54, 0x53, +0x61, 0x67, 0x4e, 0x4b, 0x32, 0x62, 0x59, 0x4d, 0x2b, 0x5a, 0x61, 0x37, 0x4e, 0x32, 0x71, 0x4b, +0x69, 0x6d, 0x6a, 0x73, 0x6e, 0x72, 0x65, 0x50, 0x52, 0x4f, 0x34, 0x35, 0x6b, 0x7a, 0x4b, 0x51, +0x43, 0x4c, 0x6a, 0x7a, 0x32, 0x58, 0x56, 0x54, 0x41, 0x6b, 0x42, 0x61, 0x70, 0x6f, 0x36, 0x51, +0x36, 0x69, 0x78, 0x34, 0x64, 0x31, 0x7a, 0x47, 0x6f, 0x56, 0x77, 0x48, 0x76, 0x6c, 0x42, 0x7a, +0x74, 0x6b, 0x2b, 0x71, 0x36, 0x73, 0x57, 0x6d, 0x4d, 0x5a, 0x64, 0x35, 0x4d, 0x54, 0x56, 0x32, +0x74, 0x35, 0x74, 0x71, 0x62, 0x46, 0x57, 0x6c, 0x66, 0x61, 0x2b, 0x7a, 0x72, 0x45, 0x6c, 0x75, +0x65, 0x49, 0x76, 0x68, 0x37, 0x67, 0x38, 0x49, 0x62, 0x4d, 0x4e, 0x59, 0x51, 0x6a, 0x6c, 0x69, +0x71, 0x64, 0x30, 0x53, 0x4a, 0x68, 0x41, 0x33, 0x4c, 0x4e, 0x76, 0x7a, 0x49, 0x56, 0x55, 0x50, +0x4f, 0x34, 0x35, 0x39, 0x66, 0x76, 0x4d, 0x4b, 0x34, 0x30, 0x36, 0x34, 0x6c, 0x34, 0x41, 0x58, +0x49, 0x43, 0x4b, 0x63, 0x68, 0x6c, 0x4f, 0x2f, 0x4e, 0x38, 0x76, 0x4e, 0x77, 0x41, 0x6f, 0x53, +0x71, 0x4a, 0x50, 0x54, 0x4f, 0x31, 0x30, 0x77, 0x39, 0x61, 0x79, 0x45, 0x50, 0x4c, 0x68, 0x2f, +0x41, 0x6c, 0x49, 0x6f, 0x65, 0x48, 0x46, 0x6c, 0x5a, 0x53, 0x75, 0x37, 0x71, 0x74, 0x79, 0x43, +0x51, 0x35, 0x6f, 0x36, 0x39, 0x46, 0x47, 0x2f, 0x54, 0x56, 0x67, 0x66, 0x45, 0x31, 0x4a, 0x71, +0x4d, 0x72, 0x51, 0x71, 0x62, 0x70, 0x65, 0x41, 0x46, 0x68, 0x62, 0x33, 0x65, 0x7a, 0x66, 0x68, +0x31, 0x74, 0x5a, 0x4c, 0x5a, 0x73, 0x79, 0x51, 0x6a, 0x54, 0x6e, 0x63, 0x54, 0x51, 0x47, 0x32, +0x4e, 0x35, 0x50, 0x4e, 0x50, 0x42, 0x57, 0x65, 0x64, 0x36, 0x77, 0x5a, 0x41, 0x70, 0x78, 0x5a, +0x77, 0x58, 0x4a, 0x39, 0x30, 0x58, 0x2b, 0x31, 0x73, 0x7a, 0x43, 0x70, 0x72, 0x72, 0x61, 0x56, +0x69, 0x37, 0x62, 0x33, 0x55, 0x6d, 0x54, 0x54, 0x61, 0x39, 0x37, 0x68, 0x7a, 0x6a, 0x79, 0x74, +0x41, 0x6d, 0x35, 0x62, 0x5a, 0x72, 0x46, 0x67, 0x42, 0x38, 0x78, 0x59, 0x73, 0x34, 0x49, 0x33, +0x33, 0x56, 0x7a, 0x4a, 0x34, 0x66, 0x68, 0x5a, 0x58, 0x50, 0x50, 0x41, 0x58, 0x4d, 0x67, 0x34, +0x66, 0x53, 0x48, 0x54, 0x6b, 0x42, 0x62, 0x54, 0x59, 0x74, 0x42, 0x37, 0x53, 0x30, 0x32, 0x6e, +0x67, 0x48, 0x57, 0x36, 0x59, 0x41, 0x48, 0x5a, 0x5a, 0x53, 0x31, 0x78, 0x6e, 0x4e, 0x50, 0x36, +0x37, 0x74, 0x55, 0x52, 0x4e, 0x6e, 0x41, 0x38, 0x33, 0x66, 0x73, 0x67, 0x66, 0x75, 0x70, 0x78, +0x42, 0x6d, 0x6e, 0x56, 0x74, 0x45, 0x6c, 0x62, 0x7a, 0x36, 0x74, 0x70, 0x58, 0x4f, 0x61, 0x66, +0x4c, 0x32, 0x57, 0x51, 0x48, 0x4d, 0x70, 0x4f, 0x44, 0x4a, 0x45, 0x45, 0x38, 0x4b, 0x62, 0x55, +0x47, 0x54, 0x39, 0x46, 0x7a, 0x61, 0x42, 0x62, 0x56, 0x57, 0x76, 0x48, 0x6b, 0x70, 0x31, 0x57, +0x59, 0x51, 0x49, 0x68, 0x34, 0x58, 0x4c, 0x42, 0x36, 0x37, 0x54, 0x70, 0x36, 0x39, 0x65, 0x35, +0x4c, 0x39, 0x33, 0x73, 0x6d, 0x55, 0x50, 0x66, 0x6c, 0x66, 0x57, 0x51, 0x4e, 0x48, 0x63, 0x39, +0x7a, 0x35, 0x31, 0x7a, 0x45, 0x49, 0x43, 0x6d, 0x70, 0x41, 0x6a, 0x59, 0x65, 0x64, 0x77, 0x61, +0x42, 0x7a, 0x45, 0x78, 0x65, 0x4c, 0x32, 0x35, 0x4e, 0x7a, 0x30, 0x67, 0x4e, 0x61, 0x56, 0x61, +0x78, 0x4d, 0x76, 0x30, 0x67, 0x68, 0x76, 0x62, 0x59, 0x54, 0x50, 0x6e, 0x50, 0x56, 0x55, 0x53, +0x46, 0x49, 0x52, 0x78, 0x4d, 0x4a, 0x36, 0x33, 0x64, 0x32, 0x55, 0x54, 0x61, 0x39, 0x71, 0x64, +0x6d, 0x79, 0x35, 0x56, 0x59, 0x48, 0x66, 0x4d, 0x46, 0x55, 0x44, 0x68, 0x42, 0x4d, 0x54, 0x37, +0x54, 0x6a, 0x6f, 0x2b, 0x34, 0x63, 0x32, 0x43, 0x6b, 0x68, 0x41, 0x61, 0x69, 0x33, 0x63, 0x52, +0x72, 0x46, 0x44, 0x59, 0x75, 0x4d, 0x45, 0x59, 0x6c, 0x66, 0x66, 0x45, 0x47, 0x51, 0x50, 0x6a, +0x4a, 0x52, 0x50, 0x79, 0x6b, 0x70, 0x4d, 0x6e, 0x33, 0x6e, 0x37, 0x4c, 0x79, 0x43, 0x4f, 0x6d, +0x49, 0x59, 0x42, 0x30, 0x6a, 0x74, 0x50, 0x4b, 0x33, 0x59, 0x65, 0x37, 0x2b, 0x42, 0x70, 0x7a, +0x61, 0x76, 0x33, 0x34, 0x39, 0x4e, 0x6a, 0x4d, 0x54, 0x66, 0x6c, 0x79, 0x4e, 0x72, 0x61, 0x72, +0x43, 0x52, 0x69, 0x4c, 0x38, 0x5a, 0x61, 0x31, 0x41, 0x78, 0x69, 0x54, 0x4b, 0x43, 0x4a, 0x54, +0x50, 0x52, 0x75, 0x4f, 0x75, 0x4a, 0x57, 0x32, 0x7a, 0x4a, 0x5a, 0x4d, 0x2f, 0x41, 0x72, 0x35, +0x59, 0x78, 0x75, 0x42, 0x44, 0x43, 0x74, 0x69, 0x38, 0x75, 0x53, 0x59, 0x6c, 0x39, 0x71, 0x43, +0x42, 0x6f, 0x57, 0x6c, 0x76, 0x72, 0x4e, 0x53, 0x64, 0x4f, 0x37, 0x63, 0x41, 0x50, 0x67, 0x49, +0x62, 0x35, 0x38, 0x7a, 0x30, 0x47, 0x5a, 0x79, 0x5a, 0x44, 0x67, 0x39, 0x6b, 0x77, 0x50, 0x70, +0x34, 0x48, 0x76, 0x2b, 0x70, 0x50, 0x5a, 0x54, 0x6e, 0x64, 0x68, 0x7a, 0x46, 0x69, 0x54, 0x31, +0x2f, 0x59, 0x4d, 0x32, 0x6b, 0x65, 0x2b, 0x68, 0x34, 0x4a, 0x48, 0x77, 0x77, 0x42, 0x51, 0x35, +0x38, 0x5a, 0x44, 0x73, 0x44, 0x67, 0x31, 0x75, 0x59, 0x57, 0x48, 0x6b, 0x61, 0x6e, 0x30, 0x54, +0x62, 0x55, 0x69, 0x50, 0x44, 0x6a, 0x47, 0x7a, 0x53, 0x2f, 0x31, 0x69, 0x51, 0x6d, 0x36, 0x63, +0x51, 0x79, 0x44, 0x30, 0x53, 0x47, 0x79, 0x2f, 0x42, 0x57, 0x6b, 0x32, 0x77, 0x34, 0x77, 0x33, +0x6f, 0x7a, 0x56, 0x50, 0x77, 0x4f, 0x6a, 0x57, 0x4d, 0x51, 0x38, 0x44, 0x5a, 0x57, 0x4c, 0x52, +0x42, 0x78, 0x79, 0x57, 0x71, 0x58, 0x6e, 0x4c, 0x71, 0x34, 0x66, 0x4d, 0x6f, 0x72, 0x38, 0x7a, +0x6d, 0x78, 0x67, 0x63, 0x73, 0x66, 0x2f, 0x39, 0x4c, 0x44, 0x2f, 0x34, 0x30, 0x35, 0x6c, 0x79, +0x45, 0x68, 0x4c, 0x4e, 0x4f, 0x6d, 0x45, 0x58, 0x66, 0x54, 0x6d, 0x76, 0x34, 0x64, 0x4e, 0x6d, +0x68, 0x48, 0x4e, 0x6a, 0x31, 0x4a, 0x31, 0x36, 0x66, 0x64, 0x53, 0x51, 0x79, 0x67, 0x51, 0x55, +0x47, 0x44, 0x6a, 0x6a, 0x67, 0x41, 0x45, 0x61, 0x4f, 0x48, 0x4d, 0x6e, 0x34, 0x38, 0x66, 0x64, +0x54, 0x56, 0x53, 0x36, 0x35, 0x2f, 0x6d, 0x5a, 0x46, 0x2f, 0x67, 0x45, 0x53, 0x2b, 0x31, 0x6f, +0x69, 0x45, 0x4b, 0x36, 0x35, 0x57, 0x37, 0x61, 0x42, 0x31, 0x52, 0x6d, 0x55, 0x30, 0x63, 0x52, +0x71, 0x4a, 0x48, 0x58, 0x52, 0x4f, 0x4f, 0x6d, 0x65, 0x41, 0x30, 0x50, 0x4e, 0x58, 0x44, 0x57, +0x66, 0x4b, 0x5a, 0x66, 0x64, 0x67, 0x39, 0x53, 0x61, 0x74, 0x35, 0x64, 0x38, 0x79, 0x6f, 0x61, +0x64, 0x57, 0x78, 0x45, 0x79, 0x34, 0x59, 0x35, 0x33, 0x33, 0x6a, 0x36, 0x41, 0x55, 0x45, 0x33, +0x55, 0x63, 0x73, 0x4d, 0x68, 0x4a, 0x5a, 0x7a, 0x51, 0x39, 0x7a, 0x69, 0x45, 0x57, 0x63, 0x6f, +0x70, 0x64, 0x77, 0x2b, 0x67, 0x78, 0x65, 0x44, 0x57, 0x4c, 0x48, 0x30, 0x4a, 0x42, 0x71, 0x32, +0x2f, 0x48, 0x73, 0x58, 0x65, 0x37, 0x59, 0x4e, 0x4a, 0x4e, 0x4c, 0x2f, 0x53, 0x62, 0x6e, 0x62, +0x61, 0x70, 0x57, 0x43, 0x62, 0x51, 0x31, 0x49, 0x70, 0x4a, 0x5a, 0x67, 0x2b, 0x58, 0x54, 0x4c, +0x39, 0x4c, 0x58, 0x63, 0x39, 0x34, 0x6e, 0x54, 0x4a, 0x79, 0x31, 0x4d, 0x46, 0x30, 0x31, 0x34, +0x56, 0x43, 0x43, 0x47, 0x35, 0x34, 0x42, 0x4c, 0x48, 0x53, 0x5a, 0x62, 0x36, 0x38, 0x6c, 0x4e, +0x58, 0x33, 0x2b, 0x55, 0x2f, 0x52, 0x56, 0x6d, 0x38, 0x76, 0x68, 0x78, 0x6c, 0x4a, 0x49, 0x4f, +0x69, 0x74, 0x51, 0x77, 0x2b, 0x49, 0x4c, 0x50, 0x5a, 0x43, 0x6d, 0x79, 0x4d, 0x41, 0x56, 0x6e, +0x47, 0x35, 0x76, 0x6f, 0x43, 0x38, 0x6b, 0x62, 0x2b, 0x6e, 0x57, 0x30, 0x2f, 0x37, 0x32, 0x4c, +0x6a, 0x77, 0x68, 0x6c, 0x30, 0x4f, 0x65, 0x6f, 0x4d, 0x4b, 0x6a, 0x35, 0x5a, 0x78, 0x4c, 0x30, +0x48, 0x58, 0x6f, 0x41, 0x4a, 0x5a, 0x78, 0x4c, 0x49, 0x61, 0x44, 0x36, 0x4a, 0x52, 0x62, 0x57, +0x67, 0x4c, 0x69, 0x52, 0x34, 0x30, 0x72, 0x63, 0x56, 0x4a, 0x48, 0x37, 0x33, 0x76, 0x51, 0x33, +0x76, 0x38, 0x66, 0x57, 0x32, 0x65, 0x64, 0x54, 0x4c, 0x65, 0x69, 0x37, 0x72, 0x66, 0x67, 0x6e, +0x57, 0x57, 0x74, 0x35, 0x61, 0x4e, 0x35, 0x30, 0x76, 0x4e, 0x73, 0x2b, 0x6b, 0x74, 0x4b, 0x36, +0x45, 0x4d, 0x66, 0x31, 0x48, 0x4a, 0x2b, 0x2b, 0x76, 0x66, 0x44, 0x43, 0x49, 0x68, 0x36, 0x62, +0x54, 0x4b, 0x59, 0x56, 0x45, 0x49, 0x32, 0x6e, 0x38, 0x64, 0x65, 0x6f, 0x71, 0x54, 0x6a, 0x2f, +0x37, 0x44, 0x4b, 0x77, 0x78, 0x76, 0x50, 0x62, 0x36, 0x64, 0x4f, 0x72, 0x71, 0x36, 0x68, 0x68, +0x7a, 0x35, 0x33, 0x6a, 0x36, 0x39, 0x75, 0x76, 0x4e, 0x57, 0x59, 0x65, 0x4e, 0x59, 0x75, 0x32, +0x4d, 0x75, 0x7a, 0x6a, 0x35, 0x2b, 0x6f, 0x46, 0x55, 0x7a, 0x79, 0x31, 0x33, 0x4a, 0x71, 0x46, +0x6c, 0x69, 0x33, 0x69, 0x7a, 0x61, 0x79, 0x36, 0x4c, 0x74, 0x78, 0x74, 0x4b, 0x54, 0x43, 0x61, +0x65, 0x6b, 0x69, 0x79, 0x63, 0x39, 0x51, 0x76, 0x66, 0x46, 0x6d, 0x59, 0x78, 0x77, 0x41, 0x4d, +0x6c, 0x34, 0x75, 0x79, 0x4f, 0x42, 0x61, 0x6e, 0x59, 0x4f, 0x4a, 0x55, 0x64, 0x75, 0x77, 0x51, +0x71, 0x6e, 0x45, 0x59, 0x34, 0x46, 0x45, 0x4d, 0x4a, 0x36, 0x77, 0x61, 0x51, 0x38, 0x6c, 0x64, +0x48, 0x6c, 0x57, 0x43, 0x56, 0x39, 0x5a, 0x79, 0x51, 0x57, 0x34, 0x6c, 0x4c, 0x7a, 0x79, 0x32, +0x78, 0x6e, 0x73, 0x59, 0x61, 0x58, 0x35, 0x30, 0x31, 0x54, 0x76, 0x67, 0x44, 0x43, 0x56, 0x5a, +0x62, 0x72, 0x5a, 0x4b, 0x42, 0x4f, 0x6f, 0x32, 0x30, 0x6e, 0x78, 0x54, 0x2f, 0x76, 0x52, 0x51, +0x4a, 0x6b, 0x49, 0x35, 0x43, 0x53, 0x75, 0x33, 0x67, 0x72, 0x4d, 0x71, 0x46, 0x79, 0x77, 0x4b, +0x51, 0x6c, 0x34, 0x64, 0x39, 0x34, 0x77, 0x33, 0x73, 0x74, 0x47, 0x6c, 0x75, 0x2f, 0x79, 0x34, +0x6c, 0x46, 0x76, 0x69, 0x6d, 0x52, 0x69, 0x44, 0x72, 0x45, 0x74, 0x6c, 0x36, 0x66, 0x61, 0x6f, +0x71, 0x48, 0x78, 0x66, 0x53, 0x56, 0x53, 0x73, 0x6f, 0x64, 0x69, 0x4e, 0x59, 0x4b, 0x64, 0x76, +0x67, 0x36, 0x70, 0x4f, 0x32, 0x43, 0x53, 0x75, 0x75, 0x6a, 0x77, 0x75, 0x51, 0x31, 0x73, 0x55, +0x6b, 0x4a, 0x46, 0x6c, 0x78, 0x2f, 0x64, 0x45, 0x50, 0x33, 0x46, 0x39, 0x78, 0x4a, 0x57, 0x6d, +0x5a, 0x6c, 0x55, 0x67, 0x5a, 0x77, 0x78, 0x70, 0x4c, 0x4d, 0x42, 0x43, 0x6b, 0x71, 0x72, 0x79, +0x57, 0x7a, 0x55, 0x50, 0x57, 0x38, 0x34, 0x63, 0x6a, 0x33, 0x64, 0x65, 0x47, 0x6e, 0x67, 0x66, +0x72, 0x48, 0x76, 0x6d, 0x45, 0x6b, 0x71, 0x71, 0x42, 0x64, 0x4d, 0x75, 0x72, 0x35, 0x73, 0x2f, +0x42, 0x45, 0x75, 0x71, 0x4e, 0x54, 0x42, 0x6f, 0x39, 0x45, 0x2f, 0x32, 0x76, 0x4e, 0x6b, 0x30, +0x68, 0x32, 0x4d, 0x6c, 0x50, 0x2f, 0x37, 0x31, 0x6a, 0x4b, 0x74, 0x5a, 0x6f, 0x43, 0x4c, 0x66, +0x48, 0x36, 0x33, 0x51, 0x6e, 0x75, 0x6e, 0x67, 0x43, 0x58, 0x70, 0x63, 0x4a, 0x6a, 0x63, 0x63, +0x66, 0x39, 0x54, 0x36, 0x58, 0x6f, 0x47, 0x46, 0x77, 0x72, 0x31, 0x58, 0x4d, 0x2f, 0x66, 0x46, +0x41, 0x72, 0x6a, 0x37, 0x6a, 0x44, 0x57, 0x36, 0x5a, 0x65, 0x42, 0x70, 0x43, 0x5a, 0x69, 0x4f, +0x6c, 0x34, 0x66, 0x4d, 0x6c, 0x42, 0x39, 0x4f, 0x7a, 0x2f, 0x57, 0x6f, 0x38, 0x42, 0x4a, 0x33, +0x61, 0x62, 0x45, 0x4a, 0x49, 0x39, 0x38, 0x79, 0x4a, 0x39, 0x7a, 0x66, 0x69, 0x31, 0x46, 0x4e, +0x4a, 0x53, 0x30, 0x2f, 0x6e, 0x67, 0x51, 0x66, 0x75, 0x59, 0x38, 0x7a, 0x74, 0x74, 0x2f, 0x50, +0x36, 0x69, 0x34, 0x70, 0x52, 0x4e, 0x38, 0x58, 0x68, 0x64, 0x6f, 0x55, 0x4e, 0x4b, 0x77, 0x66, +0x6c, 0x62, 0x59, 0x4c, 0x50, 0x53, 0x45, 0x42, 0x35, 0x45, 0x57, 0x43, 0x4d, 0x4a, 0x68, 0x7a, +0x57, 0x31, 0x4e, 0x63, 0x61, 0x63, 0x6a, 0x4b, 0x64, 0x30, 0x58, 0x6e, 0x56, 0x31, 0x6a, 0x56, +0x63, 0x2f, 0x66, 0x78, 0x64, 0x39, 0x47, 0x37, 0x58, 0x6a, 0x65, 0x4b, 0x64, 0x57, 0x79, 0x69, +0x72, 0x33, 0x75, 0x57, 0x44, 0x38, 0x52, 0x4b, 0x5a, 0x76, 0x76, 0x30, 0x4a, 0x49, 0x43, 0x4f, +0x67, 0x2b, 0x48, 0x78, 0x7a, 0x4b, 0x34, 0x5a, 0x32, 0x65, 0x5a, 0x46, 0x2f, 0x66, 0x74, 0x75, +0x64, 0x64, 0x75, 0x31, 0x67, 0x31, 0x6e, 0x66, 0x72, 0x36, 0x52, 0x66, 0x2f, 0x45, 0x76, 0x49, +0x4f, 0x49, 0x52, 0x52, 0x75, 0x55, 0x49, 0x2b, 0x62, 0x46, 0x68, 0x31, 0x64, 0x41, 0x7a, 0x55, +0x6c, 0x62, 0x6c, 0x2b, 0x70, 0x46, 0x54, 0x5a, 0x54, 0x51, 0x47, 0x63, 0x33, 0x2b, 0x41, 0x49, +0x42, 0x77, 0x54, 0x6e, 0x6e, 0x53, 0x4e, 0x49, 0x69, 0x67, 0x6a, 0x2b, 0x63, 0x36, 0x56, 0x54, +0x2f, 0x53, 0x79, 0x36, 0x56, 0x5a, 0x47, 0x51, 0x49, 0x7a, 0x72, 0x76, 0x51, 0x30, 0x52, 0x55, +0x6e, 0x4e, 0x68, 0x64, 0x4a, 0x77, 0x55, 0x36, 0x42, 0x67, 0x68, 0x37, 0x53, 0x4f, 0x38, 0x4a, +0x75, 0x65, 0x53, 0x7a, 0x61, 0x61, 0x41, 0x59, 0x66, 0x6b, 0x45, 0x45, 0x7a, 0x44, 0x63, 0x44, +0x66, 0x49, 0x6b, 0x68, 0x5a, 0x53, 0x57, 0x2b, 0x78, 0x68, 0x4d, 0x4b, 0x66, 0x44, 0x79, 0x55, +0x69, 0x4e, 0x74, 0x4f, 0x6c, 0x61, 0x78, 0x70, 0x66, 0x66, 0x54, 0x2b, 0x49, 0x53, 0x32, 0x2b, +0x62, 0x77, 0x34, 0x37, 0x38, 0x38, 0x79, 0x45, 0x37, 0x6e, 0x4e, 0x79, 0x6e, 0x70, 0x55, 0x77, +0x33, 0x6f, 0x4f, 0x72, 0x49, 0x44, 0x4f, 0x7a, 0x6b, 0x69, 0x53, 0x62, 0x33, 0x50, 0x36, 0x66, +0x72, 0x57, 0x65, 0x79, 0x4f, 0x56, 0x33, 0x4e, 0x65, 0x39, 0x37, 0x4f, 0x54, 0x66, 0x37, 0x2b, +0x34, 0x32, 0x34, 0x57, 0x55, 0x31, 0x4f, 0x2f, 0x67, 0x73, 0x6c, 0x36, 0x58, 0x4e, 0x72, 0x6f, +0x2f, 0x79, 0x53, 0x34, 0x4d, 0x4d, 0x44, 0x39, 0x32, 0x49, 0x69, 0x4b, 0x59, 0x78, 0x30, 0x6c, +0x69, 0x42, 0x57, 0x2b, 0x2b, 0x38, 0x52, 0x5a, 0x4b, 0x61, 0x32, 0x4b, 0x78, 0x47, 0x4b, 0x46, +0x51, 0x69, 0x50, 0x45, 0x54, 0x37, 0x6d, 0x48, 0x72, 0x69, 0x75, 0x39, 0x59, 0x50, 0x6d, 0x59, +0x38, 0x50, 0x78, 0x33, 0x37, 0x52, 0x2b, 0x70, 0x7a, 0x65, 0x6e, 0x4a, 0x51, 0x31, 0x55, 0x51, +0x55, 0x38, 0x4e, 0x72, 0x63, 0x47, 0x41, 0x56, 0x6e, 0x52, 0x56, 0x43, 0x79, 0x69, 0x69, 0x57, +0x71, 0x70, 0x57, 0x2f, 0x6b, 0x45, 0x2f, 0x79, 0x79, 0x4d, 0x63, 0x6f, 0x71, 0x70, 0x52, 0x33, +0x30, 0x56, 0x73, 0x53, 0x70, 0x72, 0x67, 0x6b, 0x77, 0x4a, 0x36, 0x63, 0x56, 0x4f, 0x62, 0x6c, +0x52, 0x75, 0x70, 0x59, 0x49, 0x70, 0x46, 0x52, 0x41, 0x44, 0x4a, 0x52, 0x62, 0x77, 0x52, 0x33, +0x65, 0x77, 0x43, 0x4a, 0x55, 0x43, 0x6a, 0x54, 0x5a, 0x74, 0x30, 0x46, 0x59, 0x66, 0x50, 0x75, +0x44, 0x46, 0x49, 0x35, 0x4b, 0x79, 0x34, 0x38, 0x59, 0x55, 0x2f, 0x34, 0x54, 0x4a, 0x44, 0x41, +0x43, 0x56, 0x39, 0x38, 0x78, 0x6f, 0x38, 0x48, 0x59, 0x32, 0x4f, 0x4d, 0x61, 0x50, 0x31, 0x32, +0x33, 0x4a, 0x71, 0x49, 0x30, 0x52, 0x78, 0x78, 0x65, 0x78, 0x4b, 0x6a, 0x4c, 0x44, 0x38, 0x4e, +0x59, 0x53, 0x33, 0x32, 0x39, 0x34, 0x4b, 0x57, 0x33, 0x56, 0x76, 0x4a, 0x4a, 0x59, 0x67, 0x74, +0x51, 0x56, 0x5a, 0x58, 0x63, 0x58, 0x69, 0x43, 0x56, 0x67, 0x32, 0x39, 0x4c, 0x53, 0x58, 0x73, +0x72, 0x79, 0x4d, 0x35, 0x4d, 0x38, 0x4e, 0x44, 0x35, 0x5a, 0x2b, 0x33, 0x41, 0x59, 0x4f, 0x30, +0x7a, 0x4a, 0x51, 0x76, 0x61, 0x41, 0x4d, 0x52, 0x63, 0x62, 0x49, 0x6d, 0x53, 0x54, 0x6a, 0x43, +0x6b, 0x62, 0x72, 0x54, 0x36, 0x4e, 0x31, 0x33, 0x35, 0x33, 0x64, 0x6b, 0x67, 0x70, 0x53, 0x43, +0x52, 0x46, 0x50, 0x47, 0x70, 0x36, 0x42, 0x2b, 0x6f, 0x6a, 0x75, 0x34, 0x45, 0x61, 0x75, 0x67, +0x63, 0x58, 0x63, 0x63, 0x42, 0x30, 0x54, 0x6d, 0x63, 0x31, 0x4c, 0x34, 0x56, 0x35, 0x34, 0x39, +0x35, 0x6c, 0x37, 0x6f, 0x66, 0x38, 0x31, 0x6a, 0x31, 0x7a, 0x2b, 0x58, 0x30, 0x6e, 0x58, 0x51, +0x75, 0x48, 0x61, 0x2f, 0x2f, 0x67, 0x48, 0x58, 0x33, 0x76, 0x30, 0x54, 0x33, 0x36, 0x48, 0x70, +0x4f, 0x36, 0x31, 0x79, 0x48, 0x43, 0x74, 0x41, 0x59, 0x35, 0x59, 0x6c, 0x4e, 0x43, 0x72, 0x2f, +0x65, 0x39, 0x41, 0x69, 0x32, 0x76, 0x68, 0x68, 0x72, 0x46, 0x43, 0x61, 0x36, 0x43, 0x61, 0x2f, +0x7a, 0x2b, 0x4b, 0x54, 0x77, 0x4e, 0x34, 0x49, 0x69, 0x6f, 0x2f, 0x77, 0x4a, 0x30, 0x62, 0x43, +0x35, 0x4e, 0x41, 0x38, 0x68, 0x44, 0x4e, 0x33, 0x62, 0x46, 0x48, 0x50, 0x30, 0x67, 0x63, 0x75, +0x59, 0x2f, 0x74, 0x6b, 0x51, 0x68, 0x49, 0x54, 0x74, 0x64, 0x5a, 0x4b, 0x33, 0x61, 0x33, 0x59, +0x53, 0x62, 0x72, 0x4f, 0x56, 0x67, 0x6e, 0x56, 0x46, 0x53, 0x5a, 0x42, 0x57, 0x59, 0x76, 0x52, +0x38, 0x2f, 0x4d, 0x6e, 0x48, 0x44, 0x42, 0x78, 0x34, 0x4b, 0x4f, 0x50, 0x47, 0x6a, 0x61, 0x64, +0x58, 0x62, 0x38, 0x47, 0x35, 0x6c, 0x79, 0x6f, 0x6f, 0x6c, 0x39, 0x68, 0x70, 0x45, 0x76, 0x75, +0x68, 0x32, 0x4b, 0x4d, 0x47, 0x6b, 0x47, 0x51, 0x6c, 0x56, 0x6b, 0x34, 0x44, 0x69, 0x4e, 0x59, +0x49, 0x69, 0x74, 0x4d, 0x6c, 0x4c, 0x61, 0x6f, 0x6c, 0x55, 0x75, 0x48, 0x62, 0x32, 0x68, 0x54, +0x4c, 0x4e, 0x2f, 0x33, 0x67, 0x67, 0x47, 0x7a, 0x61, 0x72, 0x66, 0x70, 0x43, 0x4e, 0x57, 0x42, +0x39, 0x41, 0x45, 0x4b, 0x74, 0x41, 0x6f, 0x6f, 0x46, 0x47, 0x7a, 0x50, 0x6f, 0x39, 0x4e, 0x70, +0x6c, 0x45, 0x44, 0x46, 0x38, 0x2f, 0x50, 0x63, 0x71, 0x2b, 0x71, 0x51, 0x72, 0x56, 0x47, 0x41, +0x4b, 0x4d, 0x70, 0x43, 0x46, 0x39, 0x79, 0x73, 0x32, 0x41, 0x44, 0x6e, 0x79, 0x53, 0x73, 0x79, +0x48, 0x6e, 0x2b, 0x4a, 0x4a, 0x53, 0x53, 0x78, 0x66, 0x6f, 0x50, 0x49, 0x55, 0x35, 0x6a, 0x71, +0x42, 0x69, 0x66, 0x73, 0x49, 0x71, 0x6e, 0x54, 0x4a, 0x61, 0x65, 0x64, 0x4b, 0x71, 0x6d, 0x4d, +0x2b, 0x76, 0x44, 0x4a, 0x44, 0x63, 0x50, 0x59, 0x6c, 0x6b, 0x71, 0x71, 0x59, 0x49, 0x68, 0x52, +0x55, 0x62, 0x4b, 0x79, 0x41, 0x32, 0x55, 0x74, 0x71, 0x36, 0x64, 0x6b, 0x70, 0x6a, 0x5a, 0x68, +0x6f, 0x53, 0x4f, 0x4b, 0x51, 0x32, 0x4f, 0x2f, 0x6e, 0x5a, 0x35, 0x36, 0x42, 0x4d, 0x66, 0x42, +0x6a, 0x73, 0x58, 0x44, 0x2f, 0x4d, 0x2b, 0x36, 0x6c, 0x47, 0x32, 0x74, 0x4a, 0x54, 0x77, 0x76, +0x79, 0x78, 0x59, 0x49, 0x71, 0x2b, 0x6e, 0x66, 0x6f, 0x7a, 0x75, 0x43, 0x54, 0x65, 0x30, 0x48, +0x5a, 0x39, 0x39, 0x43, 0x39, 0x41, 0x33, 0x39, 0x2f, 0x4c, 0x70, 0x38, 0x78, 0x34, 0x31, 0x36, +0x43, 0x65, 0x42, 0x56, 0x65, 0x7a, 0x7a, 0x59, 0x4f, 0x79, 0x4e, 0x37, 0x73, 0x45, 0x53, 0x7a, +0x6f, 0x4b, 0x4a, 0x36, 0x74, 0x68, 0x69, 0x59, 0x55, 0x54, 0x6d, 0x45, 0x62, 0x35, 0x71, 0x70, +0x65, 0x56, 0x7a, 0x61, 0x62, 0x63, 0x47, 0x37, 0x70, 0x64, 0x33, 0x4d, 0x7a, 0x4c, 0x63, 0x58, +0x78, 0x4a, 0x37, 0x6a, 0x39, 0x63, 0x2f, 0x35, 0x37, 0x54, 0x36, 0x4d, 0x73, 0x70, 0x49, 0x6b, +0x34, 0x70, 0x30, 0x6a, 0x4a, 0x46, 0x30, 0x4a, 0x51, 0x4a, 0x53, 0x56, 0x68, 0x62, 0x66, 0x42, +0x57, 0x2f, 0x38, 0x44, 0x32, 0x52, 0x78, 0x2b, 0x69, 0x59, 0x75, 0x74, 0x32, 0x32, 0x72, 0x37, +0x79, 0x49, 0x43, 0x6f, 0x51, 0x78, 0x4f, 0x75, 0x51, 0x59, 0x4d, 0x4a, 0x78, 0x6b, 0x58, 0x4a, +0x43, 0x2b, 0x78, 0x62, 0x32, 0x52, 0x4e, 0x68, 0x77, 0x51, 0x68, 0x43, 0x55, 0x52, 0x71, 0x42, +0x35, 0x63, 0x74, 0x46, 0x52, 0x33, 0x48, 0x62, 0x43, 0x5a, 0x32, 0x44, 0x69, 0x50, 0x50, 0x6a, +0x4e, 0x63, 0x48, 0x51, 0x69, 0x41, 0x57, 0x70, 0x4d, 0x6f, 0x54, 0x51, 0x2b, 0x4b, 0x61, 0x5a, +0x62, 0x47, 0x5a, 0x4e, 0x47, 0x4e, 0x2b, 0x75, 0x4d, 0x6b, 0x63, 0x5a, 0x54, 0x47, 0x4f, 0x73, +0x4d, 0x57, 0x59, 0x6d, 0x4a, 0x77, 0x53, 0x52, 0x57, 0x45, 0x49, 0x52, 0x76, 0x62, 0x4e, 0x56, +0x4a, 0x52, 0x47, 0x47, 0x6a, 0x31, 0x4e, 0x7a, 0x2b, 0x35, 0x77, 0x58, 0x4c, 0x74, 0x67, 0x41, +0x65, 0x51, 0x34, 0x37, 0x73, 0x78, 0x45, 0x4f, 0x50, 0x7a, 0x30, 0x4e, 0x70, 0x43, 0x78, 0x6a, +0x4d, 0x41, 0x76, 0x41, 0x36, 0x31, 0x32, 0x44, 0x6a, 0x56, 0x58, 0x34, 0x67, 0x6c, 0x49, 0x2b, +0x67, 0x55, 0x34, 0x4a, 0x70, 0x43, 0x51, 0x4e, 0x67, 0x6b, 0x30, 0x68, 0x49, 0x6a, 0x4d, 0x4a, +0x4c, 0x55, 0x39, 0x78, 0x31, 0x43, 0x76, 0x52, 0x66, 0x31, 0x49, 0x73, 0x65, 0x50, 0x56, 0x75, +0x52, 0x6e, 0x5a, 0x50, 0x6d, 0x74, 0x7a, 0x2b, 0x52, 0x44, 0x74, 0x78, 0x4e, 0x42, 0x71, 0x6d, +0x45, 0x6e, 0x77, 0x6d, 0x51, 0x6b, 0x4e, 0x61, 0x47, 0x77, 0x73, 0x49, 0x73, 0x6c, 0x69, 0x77, +0x35, 0x44, 0x47, 0x76, 0x57, 0x4d, 0x6a, 0x53, 0x77, 0x6d, 0x47, 0x4f, 0x7a, 0x46, 0x74, 0x4f, +0x72, 0x39, 0x43, 0x76, 0x36, 0x5a, 0x6b, 0x50, 0x68, 0x2b, 0x46, 0x76, 0x59, 0x65, 0x63, 0x6b, +0x5a, 0x76, 0x46, 0x64, 0x71, 0x4f, 0x4b, 0x4a, 0x45, 0x6b, 0x7a, 0x32, 0x69, 0x46, 0x51, 0x73, +0x57, 0x62, 0x6b, 0x46, 0x66, 0x63, 0x41, 0x44, 0x44, 0x54, 0x70, 0x72, 0x4c, 0x59, 0x32, 0x50, +0x66, 0x34, 0x59, 0x34, 0x46, 0x62, 0x39, 0x50, 0x4c, 0x71, 0x32, 0x4d, 0x70, 0x7a, 0x62, 0x56, +0x50, 0x61, 0x79, 0x31, 0x65, 0x30, 0x52, 0x32, 0x2b, 0x61, 0x37, 0x46, 0x78, 0x50, 0x48, 0x31, +0x7a, 0x30, 0x4a, 0x59, 0x2f, 0x38, 0x55, 0x72, 0x44, 0x71, 0x76, 0x56, 0x46, 0x44, 0x4f, 0x6a, +0x35, 0x49, 0x39, 0x58, 0x31, 0x59, 0x55, 0x34, 0x66, 0x50, 0x49, 0x76, 0x42, 0x33, 0x52, 0x61, +0x7a, 0x70, 0x53, 0x79, 0x50, 0x52, 0x7a, 0x34, 0x65, 0x54, 0x73, 0x58, 0x32, 0x31, 0x72, 0x51, +0x6f, 0x58, 0x4d, 0x4e, 0x62, 0x32, 0x79, 0x4d, 0x6f, 0x6d, 0x55, 0x67, 0x50, 0x37, 0x33, 0x70, +0x67, 0x79, 0x5a, 0x4b, 0x6c, 0x76, 0x50, 0x37, 0x36, 0x47, 0x78, 0x78, 0x79, 0x75, 0x47, 0x4c, +0x4d, 0x72, 0x5a, 0x4b, 0x73, 0x72, 0x78, 0x58, 0x32, 0x57, 0x59, 0x48, 0x64, 0x30, 0x67, 0x53, +0x4e, 0x75, 0x55, 0x64, 0x57, 0x5a, 0x31, 0x42, 0x4b, 0x45, 0x77, 0x6c, 0x72, 0x30, 0x6f, 0x55, +0x6b, 0x50, 0x64, 0x4d, 0x69, 0x6c, 0x45, 0x69, 0x71, 0x2b, 0x73, 0x49, 0x48, 0x34, 0x69, 0x55, +0x6d, 0x41, 0x4b, 0x6b, 0x63, 0x53, 0x43, 0x67, 0x42, 0x78, 0x41, 0x73, 0x46, 0x74, 0x45, 0x4a, +0x75, 0x54, 0x4b, 0x65, 0x67, 0x74, 0x34, 0x4a, 0x4c, 0x6e, 0x32, 0x52, 0x55, 0x2b, 0x6b, 0x64, +0x73, 0x39, 0x41, 0x34, 0x44, 0x6d, 0x35, 0x6b, 0x4d, 0x47, 0x64, 0x78, 0x72, 0x55, 0x65, 0x73, +0x78, 0x77, 0x49, 0x34, 0x63, 0x78, 0x5a, 0x71, 0x77, 0x35, 0x4c, 0x48, 0x2b, 0x45, 0x76, 0x6c, +0x46, 0x67, 0x37, 0x55, 0x2f, 0x79, 0x57, 0x69, 0x72, 0x48, 0x61, 0x47, 0x44, 0x53, 0x6a, 0x43, +0x55, 0x47, 0x6b, 0x33, 0x33, 0x6c, 0x70, 0x6f, 0x6c, 0x6b, 0x34, 0x41, 0x66, 0x31, 0x6e, 0x44, +0x58, 0x6f, 0x30, 0x56, 0x73, 0x4c, 0x68, 0x45, 0x70, 0x31, 0x6e, 0x36, 0x44, 0x38, 0x44, 0x48, +0x66, 0x79, 0x64, 0x79, 0x45, 0x76, 0x68, 0x64, 0x41, 0x2b, 0x65, 0x70, 0x71, 0x6c, 0x38, 0x49, +0x49, 0x6e, 0x7a, 0x36, 0x37, 0x67, 0x6f, 0x38, 0x2f, 0x4c, 0x6f, 0x43, 0x63, 0x45, 0x65, 0x69, +0x63, 0x30, 0x78, 0x67, 0x35, 0x2b, 0x67, 0x74, 0x65, 0x2f, 0x38, 0x63, 0x43, 0x4b, 0x46, 0x52, +0x34, 0x52, 0x51, 0x55, 0x2b, 0x4a, 0x39, 0x50, 0x65, 0x69, 0x75, 0x76, 0x41, 0x2f, 0x50, 0x78, +0x38, 0x72, 0x72, 0x6e, 0x6d, 0x47, 0x6f, 0x71, 0x4c, 0x69, 0x35, 0x50, 0x6f, 0x76, 0x33, 0x32, +0x42, 0x41, 0x6c, 0x63, 0x2f, 0x41, 0x70, 0x47, 0x68, 0x75, 0x5a, 0x69, 0x61, 0x39, 0x69, 0x37, +0x69, 0x79, 0x75, 0x5a, 0x79, 0x6a, 0x4e, 0x61, 0x4d, 0x4e, 0x42, 0x4b, 0x74, 0x4a, 0x65, 0x79, +0x65, 0x67, 0x74, 0x57, 0x43, 0x34, 0x32, 0x2f, 0x50, 0x77, 0x70, 0x6a, 0x75, 0x76, 0x72, 0x5a, +0x6b, 0x43, 0x4c, 0x55, 0x73, 0x6f, 0x75, 0x38, 0x2f, 0x56, 0x7a, 0x44, 0x67, 0x43, 0x7a, 0x38, +0x55, 0x4f, 0x79, 0x46, 0x34, 0x4d, 0x6d, 0x55, 0x43, 0x53, 0x4a, 0x79, 0x31, 0x5a, 0x6c, 0x31, +0x35, 0x42, 0x74, 0x65, 0x39, 0x38, 0x51, 0x65, 0x4d, 0x31, 0x73, 0x53, 0x56, 0x4a, 0x54, 0x33, +0x62, 0x33, 0x77, 0x49, 0x49, 0x31, 0x65, 0x53, 0x39, 0x34, 0x62, 0x59, 0x41, 0x52, 0x76, 0x71, +0x5a, 0x63, 0x66, 0x77, 0x74, 0x67, 0x4f, 0x2f, 0x2b, 0x73, 0x36, 0x59, 0x68, 0x78, 0x33, 0x7a, +0x43, 0x43, 0x4a, 0x67, 0x6b, 0x51, 0x4a, 0x55, 0x71, 0x75, 0x66, 0x38, 0x57, 0x30, 0x69, 0x58, +0x6c, 0x6c, 0x50, 0x37, 0x66, 0x32, 0x72, 0x58, 0x4b, 0x34, 0x75, 0x70, 0x4c, 0x44, 0x2b, 0x47, +0x58, 0x39, 0x65, 0x57, 0x38, 0x4d, 0x50, 0x6b, 0x4d, 0x6e, 0x70, 0x36, 0x36, 0x6a, 0x48, 0x6e, +0x76, 0x43, 0x33, 0x37, 0x65, 0x43, 0x65, 0x33, 0x61, 0x4b, 0x6d, 0x52, 0x55, 0x59, 0x6f, 0x78, +0x44, 0x51, 0x42, 0x72, 0x62, 0x59, 0x4f, 0x30, 0x33, 0x32, 0x67, 0x6d, 0x39, 0x38, 0x53, 0x63, +0x41, 0x64, 0x39, 0x5a, 0x45, 0x50, 0x4d, 0x32, 0x33, 0x56, 0x56, 0x43, 0x78, 0x38, 0x2f, 0x4a, +0x6b, 0x49, 0x6f, 0x39, 0x55, 0x41, 0x66, 0x77, 0x74, 0x4b, 0x4c, 0x54, 0x6e, 0x65, 0x64, 0x77, +0x35, 0x74, 0x69, 0x66, 0x6d, 0x79, 0x39, 0x64, 0x34, 0x51, 0x6a, 0x36, 0x4d, 0x72, 0x51, 0x44, +0x76, 0x72, 0x4f, 0x4e, 0x52, 0x4e, 0x39, 0x7a, 0x44, 0x39, 0x49, 0x4a, 0x30, 0x30, 0x6e, 0x59, +0x4a, 0x53, 0x6c, 0x59, 0x76, 0x59, 0x30, 0x46, 0x64, 0x6c, 0x4b, 0x37, 0x68, 0x33, 0x61, 0x77, +0x4b, 0x62, 0x4b, 0x4a, 0x56, 0x72, 0x41, 0x73, 0x46, 0x58, 0x57, 0x4b, 0x4d, 0x65, 0x79, 0x79, +0x58, 0x39, 0x51, 0x74, 0x75, 0x5a, 0x4f, 0x4a, 0x6a, 0x48, 0x39, 0x46, 0x79, 0x55, 0x45, 0x75, +0x75, 0x75, 0x65, 0x63, 0x61, 0x69, 0x73, 0x75, 0x4b, 0x66, 0x65, 0x47, 0x51, 0x76, 0x67, 0x41, +0x31, 0x77, 0x4f, 0x41, 0x54, 0x71, 0x6e, 0x4f, 0x43, 0x56, 0x56, 0x64, 0x70, 0x54, 0x59, 0x2b, +0x32, 0x50, 0x66, 0x68, 0x75, 0x34, 0x6e, 0x66, 0x41, 0x65, 0x38, 0x6c, 0x4a, 0x36, 0x70, 0x73, +0x66, 0x65, 0x39, 0x4f, 0x78, 0x64, 0x54, 0x47, 0x74, 0x73, 0x68, 0x57, 0x66, 0x72, 0x52, 0x35, +0x45, 0x35, 0x2f, 0x79, 0x4e, 0x5a, 0x47, 0x58, 0x74, 0x5a, 0x75, 0x77, 0x66, 0x33, 0x6d, 0x58, +0x71, 0x6d, 0x68, 0x79, 0x6b, 0x56, 0x71, 0x7a, 0x36, 0x37, 0x46, 0x78, 0x2f, 0x48, 0x4a, 0x4f, +0x63, 0x41, 0x4f, 0x4c, 0x78, 0x4f, 0x45, 0x65, 0x63, 0x49, 0x4c, 0x6e, 0x74, 0x64, 0x45, 0x6e, +0x61, 0x51, 0x77, 0x6f, 0x37, 0x4f, 0x2f, 0x36, 0x37, 0x57, 0x62, 0x45, 0x54, 0x53, 0x4e, 0x34, +0x57, 0x68, 0x78, 0x7a, 0x4f, 0x6f, 0x47, 0x2f, 0x6e, 0x45, 0x65, 0x70, 0x34, 0x41, 0x43, 0x4b, +0x36, 0x4b, 0x6d, 0x55, 0x43, 0x38, 0x4d, 0x2b, 0x2b, 0x36, 0x30, 0x38, 0x71, 0x35, 0x53, 0x66, +0x74, 0x39, 0x53, 0x63, 0x41, 0x57, 0x30, 0x4d, 0x6f, 0x30, 0x43, 0x6d, 0x47, 0x50, 0x50, 0x74, +0x75, 0x52, 0x4d, 0x37, 0x6e, 0x56, 0x46, 0x55, 0x64, 0x42, 0x48, 0x59, 0x39, 0x65, 0x4c, 0x2f, +0x69, 0x52, 0x30, 0x38, 0x55, 0x55, 0x78, 0x50, 0x61, 0x43, 0x65, 0x78, 0x4d, 0x56, 0x37, 0x78, +0x79, 0x61, 0x69, 0x46, 0x74, 0x68, 0x55, 0x53, 0x46, 0x2f, 0x64, 0x44, 0x4b, 0x42, 0x4b, 0x75, +0x74, 0x56, 0x69, 0x68, 0x6b, 0x45, 0x6f, 0x62, 0x6f, 0x71, 0x49, 0x72, 0x63, 0x6f, 0x48, 0x5a, +0x70, 0x78, 0x4a, 0x33, 0x31, 0x76, 0x37, 0x42, 0x31, 0x43, 0x4e, 0x6b, 0x6f, 0x41, 0x43, 0x51, +0x31, 0x32, 0x55, 0x50, 0x51, 0x68, 0x33, 0x2f, 0x61, 0x4a, 0x4e, 0x5a, 0x61, 0x4a, 0x30, 0x79, +0x67, 0x77, 0x4d, 0x6f, 0x31, 0x5a, 0x5a, 0x77, 0x2f, 0x63, 0x69, 0x72, 0x72, 0x46, 0x71, 0x2b, +0x44, 0x48, 0x6d, 0x33, 0x77, 0x77, 0x67, 0x47, 0x49, 0x31, 0x2f, 0x35, 0x4b, 0x77, 0x77, 0x45, +0x64, 0x6f, 0x7a, 0x37, 0x6d, 0x45, 0x42, 0x46, 0x53, 0x4b, 0x67, 0x6f, 0x4c, 0x43, 0x33, 0x33, +0x49, 0x37, 0x37, 0x35, 0x42, 0x67, 0x59, 0x66, 0x58, 0x76, 0x38, 0x33, 0x4e, 0x34, 0x6b, 0x42, +0x4d, 0x32, 0x4b, 0x4b, 0x43, 0x50, 0x74, 0x39, 0x63, 0x73, 0x45, 0x46, 0x62, 0x45, 0x55, 0x4a, +0x69, 0x67, 0x67, 0x34, 0x66, 0x6f, 0x50, 0x32, 0x55, 0x54, 0x63, 0x59, 0x61, 0x72, 0x4c, 0x43, +0x4d, 0x6a, 0x2f, 0x55, 0x41, 0x74, 0x76, 0x71, 0x73, 0x74, 0x4a, 0x6b, 0x4e, 0x4b, 0x31, 0x38, +0x43, 0x30, 0x71, 0x74, 0x31, 0x77, 0x34, 0x71, 0x6f, 0x63, 0x31, 0x42, 0x61, 0x6f, 0x37, 0x58, +0x42, 0x30, 0x39, 0x61, 0x66, 0x77, 0x51, 0x33, 0x55, 0x4f, 0x68, 0x57, 0x2b, 0x64, 0x56, 0x34, +0x45, 0x71, 0x61, 0x78, 0x6a, 0x50, 0x67, 0x37, 0x6e, 0x34, 0x77, 0x57, 0x64, 0x6d, 0x79, 0x6b, +0x51, 0x6c, 0x46, 0x67, 0x4d, 0x58, 0x6b, 0x51, 0x51, 0x36, 0x70, 0x54, 0x51, 0x43, 0x6c, 0x49, +0x6e, 0x41, 0x44, 0x66, 0x78, 0x74, 0x73, 0x6e, 0x33, 0x57, 0x5a, 0x47, 0x56, 0x39, 0x65, 0x39, +0x72, 0x58, 0x48, 0x4a, 0x4f, 0x76, 0x7a, 0x31, 0x43, 0x47, 0x74, 0x37, 0x37, 0x39, 0x47, 0x66, +0x4f, 0x50, 0x72, 0x55, 0x50, 0x54, 0x30, 0x31, 0x64, 0x77, 0x6f, 0x4a, 0x6c, 0x6d, 0x77, 0x48, +0x46, 0x67, 0x58, 0x50, 0x67, 0x36, 0x68, 0x79, 0x46, 0x4e, 0x49, 0x55, 0x2b, 0x31, 0x5a, 0x52, +0x4f, 0x36, 0x58, 0x76, 0x66, 0x35, 0x32, 0x2b, 0x62, 0x39, 0x37, 0x2b, 0x32, 0x6d, 0x70, 0x58, +0x76, 0x51, 0x50, 0x53, 0x42, 0x4e, 0x41, 0x4a, 0x6a, 0x78, 0x72, 0x67, 0x34, 0x68, 0x41, 0x52, +0x55, 0x57, 0x4c, 0x70, 0x74, 0x53, 0x68, 0x4a, 0x4b, 0x6e, 0x48, 0x72, 0x34, 0x66, 0x6e, 0x71, +0x30, 0x78, 0x6e, 0x7a, 0x35, 0x4a, 0x62, 0x45, 0x70, 0x73, 0x4b, 0x50, 0x67, 0x62, 0x41, 0x4c, +0x6a, 0x72, 0x38, 0x4e, 0x32, 0x7a, 0x38, 0x51, 0x59, 0x77, 0x39, 0x61, 0x46, 0x61, 0x32, 0x6c, +0x68, 0x51, 0x2f, 0x54, 0x76, 0x63, 0x6a, 0x53, 0x37, 0x4e, 0x6d, 0x36, 0x6e, 0x62, 0x48, 0x73, +0x78, 0x33, 0x51, 0x38, 0x2f, 0x41, 0x69, 0x73, 0x38, 0x35, 0x73, 0x2f, 0x35, 0x6d, 0x54, 0x5a, +0x35, 0x32, 0x58, 0x54, 0x74, 0x46, 0x75, 0x44, 0x5a, 0x4a, 0x30, 0x2f, 0x69, 0x67, 0x74, 0x76, +0x2f, 0x6a, 0x64, 0x51, 0x2b, 0x71, 0x37, 0x49, 0x76, 0x33, 0x41, 0x6b, 0x6f, 0x66, 0x41, 0x4c, +0x43, 0x6e, 0x6f, 0x53, 0x79, 0x36, 0x77, 0x5a, 0x57, 0x33, 0x63, 0x51, 0x4b, 0x6d, 0x74, 0x44, +0x67, 0x43, 0x74, 0x74, 0x45, 0x6b, 0x43, 0x4b, 0x66, 0x32, 0x53, 0x76, 0x50, 0x49, 0x4b, 0x36, +0x58, 0x63, 0x2f, 0x4c, 0x41, 0x6c, 0x65, 0x54, 0x6e, 0x56, 0x47, 0x4b, 0x4e, 0x70, 0x4c, 0x51, +0x71, 0x68, 0x2b, 0x46, 0x6c, 0x33, 0x66, 0x6d, 0x75, 0x49, 0x70, 0x2f, 0x4f, 0x68, 0x54, 0x6c, +0x2b, 0x32, 0x71, 0x34, 0x47, 0x4c, 0x38, 0x44, 0x68, 0x42, 0x79, 0x73, 0x75, 0x61, 0x64, 0x75, +0x65, 0x77, 0x44, 0x38, 0x6b, 0x56, 0x43, 0x6a, 0x6f, 0x75, 0x41, 0x2b, 0x73, 0x77, 0x4d, 0x49, +0x5a, 0x49, 0x32, 0x76, 0x57, 0x72, 0x79, 0x48, 0x55, 0x70, 0x69, 0x75, 0x69, 0x61, 0x67, 0x66, +0x74, 0x43, 0x39, 0x75, 0x35, 0x63, 0x5a, 0x73, 0x43, 0x36, 0x58, 0x63, 0x4c, 0x5a, 0x30, 0x50, +0x37, 0x45, 0x38, 0x46, 0x38, 0x58, 0x75, 0x46, 0x70, 0x49, 0x36, 0x4e, 0x31, 0x2b, 0x64, 0x2b, +0x46, 0x6a, 0x4b, 0x6e, 0x46, 0x6b, 0x39, 0x6c, 0x75, 0x31, 0x54, 0x63, 0x47, 0x6a, 0x48, 0x59, +0x72, 0x69, 0x47, 0x37, 0x41, 0x71, 0x78, 0x74, 0x74, 0x73, 0x61, 0x6c, 0x62, 0x41, 0x6d, 0x50, +0x56, 0x39, 0x4e, 0x6e, 0x62, 0x30, 0x73, 0x2b, 0x39, 0x48, 0x59, 0x66, 0x34, 0x32, 0x6c, 0x64, +0x57, 0x32, 0x32, 0x78, 0x67, 0x78, 0x51, 0x4a, 0x48, 0x76, 0x39, 0x62, 0x6f, 0x48, 0x30, 0x31, +0x68, 0x68, 0x45, 0x30, 0x52, 0x67, 0x41, 0x31, 0x34, 0x72, 0x54, 0x48, 0x6a, 0x61, 0x2f, 0x6a, +0x58, 0x31, 0x4c, 0x58, 0x59, 0x36, 0x69, 0x6f, 0x6f, 0x79, 0x6e, 0x4e, 0x37, 0x38, 0x39, 0x39, +0x41, 0x67, 0x34, 0x45, 0x44, 0x6e, 0x57, 0x53, 0x6b, 0x77, 0x61, 0x37, 0x76, 0x2f, 0x2f, 0x57, +0x62, 0x33, 0x2f, 0x32, 0x31, 0x63, 0x73, 0x6a, 0x74, 0x6e, 0x37, 0x4e, 0x7a, 0x64, 0x79, 0x79, +0x4a, 0x37, 0x6f, 0x73, 0x4a, 0x35, 0x56, 0x79, 0x61, 0x4b, 0x67, 0x46, 0x44, 0x39, 0x6e, 0x48, +0x42, 0x53, 0x56, 0x69, 0x6f, 0x2f, 0x33, 0x36, 0x56, 0x67, 0x65, 0x77, 0x51, 0x4c, 0x46, 0x2f, +0x55, 0x35, 0x4d, 0x58, 0x74, 0x36, 0x57, 0x69, 0x4b, 0x42, 0x45, 0x78, 0x35, 0x42, 0x34, 0x58, +0x50, 0x51, 0x46, 0x6c, 0x39, 0x43, 0x6a, 0x4e, 0x76, 0x67, 0x4c, 0x6c, 0x76, 0x6a, 0x36, 0x4a, +0x39, 0x4b, 0x2f, 0x39, 0x57, 0x43, 0x6c, 0x51, 0x41, 0x31, 0x45, 0x61, 0x49, 0x58, 0x64, 0x2f, +0x34, 0x37, 0x51, 0x57, 0x41, 0x49, 0x56, 0x7a, 0x34, 0x4f, 0x2b, 0x36, 0x66, 0x32, 0x6e, 0x47, +0x70, 0x6e, 0x33, 0x50, 0x68, 0x39, 0x6d, 0x33, 0x73, 0x44, 0x78, 0x53, 0x31, 0x62, 0x6e, 0x6c, +0x7a, 0x64, 0x42, 0x73, 0x30, 0x2f, 0x39, 0x75, 0x65, 0x76, 0x67, 0x4e, 0x51, 0x38, 0x6c, 0x66, +0x59, 0x55, 0x51, 0x6b, 0x56, 0x74, 0x52, 0x43, 0x56, 0x44, 0x54, 0x77, 0x44, 0x76, 0x31, 0x61, +0x30, 0x44, 0x7a, 0x68, 0x4c, 0x43, 0x38, 0x4f, 0x74, 0x6e, 0x2f, 0x46, 0x66, 0x51, 0x65, 0x41, +0x62, 0x79, 0x74, 0x73, 0x30, 0x37, 0x71, 0x4f, 0x45, 0x31, 0x6c, 0x6b, 0x4c, 0x2b, 0x48, 0x6b, +0x42, 0x79, 0x63, 0x58, 0x42, 0x58, 0x70, 0x76, 0x30, 0x48, 0x51, 0x47, 0x47, 0x4d, 0x5a, 0x46, +0x33, 0x6d, 0x6a, 0x77, 0x7a, 0x2f, 0x50, 0x37, 0x6e, 0x37, 0x39, 0x37, 0x53, 0x74, 0x66, 0x33, +0x78, 0x4f, 0x48, 0x51, 0x45, 0x31, 0x67, 0x48, 0x6a, 0x2b, 0x50, 0x33, 0x46, 0x53, 0x37, 0x43, +0x49, 0x4a, 0x63, 0x71, 0x2b, 0x51, 0x68, 0x46, 0x44, 0x31, 0x64, 0x58, 0x4e, 0x66, 0x74, 0x54, +0x34, 0x71, 0x33, 0x4f, 0x4c, 0x76, 0x4c, 0x7a, 0x66, 0x72, 0x4e, 0x39, 0x71, 0x44, 0x2f, 0x66, +0x62, 0x6c, 0x2f, 0x76, 0x6e, 0x6c, 0x70, 0x66, 0x54, 0x38, 0x61, 0x43, 0x44, 0x32, 0x4c, 0x46, +0x6a, 0x42, 0x77, 0x42, 0x74, 0x32, 0x37, 0x5a, 0x6c, 0x2b, 0x34, 0x6f, 0x56, 0x4d, 0x47, 0x59, +0x4d, 0x76, 0x50, 0x48, 0x47, 0x62, 0x39, 0x61, 0x2f, 0x5a, 0x77, 0x2f, 0x33, 0x53, 0x35, 0x31, +0x32, 0x39, 0x6a, 0x61, 0x6d, 0x72, 0x2f, 0x73, 0x6a, 0x54, 0x48, 0x6f, 0x46, 0x76, 0x75, 0x76, +0x39, 0x59, 0x65, 0x4d, 0x66, 0x53, 0x4d, 0x56, 0x39, 0x78, 0x78, 0x53, 0x62, 0x4b, 0x69, 0x2f, +0x63, 0x49, 0x31, 0x34, 0x2b, 0x63, 0x65, 0x53, 0x6e, 0x6b, 0x69, 0x4b, 0x6e, 0x4e, 0x69, 0x43, +0x31, 0x49, 0x66, 0x56, 0x41, 0x4e, 0x76, 0x78, 0x70, 0x4f, 0x46, 0x79, 0x75, 0x34, 0x49, 0x51, +0x54, 0x55, 0x37, 0x34, 0x2f, 0x73, 0x63, 0x6c, 0x6b, 0x6c, 0x38, 0x43, 0x5a, 0x4a, 0x2b, 0x75, +0x62, 0x35, 0x6c, 0x6a, 0x30, 0x78, 0x47, 0x51, 0x45, 0x4d, 0x4c, 0x30, 0x4a, 0x4b, 0x2b, 0x34, +0x2b, 0x6c, 0x6b, 0x73, 0x66, 0x61, 0x41, 0x77, 0x63, 0x61, 0x38, 0x61, 0x2b, 0x71, 0x78, 0x52, +0x50, 0x7a, 0x72, 0x6f, 0x42, 0x58, 0x56, 0x65, 0x48, 0x58, 0x72, 0x4d, 0x47, 0x61, 0x77, 0x77, +0x4a, 0x79, 0x6b, 0x30, 0x4e, 0x54, 0x4c, 0x6c, 0x32, 0x66, 0x76, 0x50, 0x32, 0x6d, 0x38, 0x53, +0x62, 0x64, 0x74, 0x75, 0x63, 0x66, 0x33, 0x65, 0x65, 0x68, 0x61, 0x32, 0x76, 0x59, 0x32, 0x64, +0x35, 0x53, 0x53, 0x4d, 0x52, 0x55, 0x6b, 0x44, 0x62, 0x79, 0x57, 0x38, 0x30, 0x71, 0x68, 0x6f, +0x49, 0x4e, 0x49, 0x79, 0x2f, 0x58, 0x32, 0x4d, 0x30, 0x54, 0x68, 0x78, 0x64, 0x75, 0x2f, 0x36, +0x56, 0x64, 0x39, 0x38, 0x64, 0x53, 0x35, 0x38, 0x2b, 0x42, 0x54, 0x7a, 0x36, 0x36, 0x48, 0x78, +0x65, 0x66, 0x76, 0x6c, 0x39, 0x51, 0x50, 0x48, 0x35, 0x35, 0x2f, 0x65, 0x79, 0x2b, 0x6f, 0x63, +0x79, 0x65, 0x76, 0x51, 0x71, 0x34, 0x50, 0x54, 0x54, 0x52, 0x39, 0x4f, 0x34, 0x39, 0x78, 0x76, +0x6f, 0x73, 0x63, 0x75, 0x2f, 0x72, 0x51, 0x4a, 0x54, 0x67, 0x63, 0x2b, 0x76, 0x69, 0x33, 0x48, +0x68, 0x68, 0x65, 0x34, 0x78, 0x41, 0x68, 0x36, 0x5a, 0x50, 0x59, 0x6f, 0x68, 0x6b, 0x4c, 0x76, +0x48, 0x65, 0x79, 0x74, 0x6a, 0x36, 0x46, 0x79, 0x30, 0x31, 0x66, 0x2f, 0x74, 0x43, 0x67, 0x44, +0x30, 0x2b, 0x6a, 0x4d, 0x62, 0x44, 0x52, 0x43, 0x54, 0x38, 0x6b, 0x71, 0x4d, 0x67, 0x61, 0x78, +0x4a, 0x4e, 0x42, 0x71, 0x55, 0x65, 0x68, 0x72, 0x4d, 0x4c, 0x41, 0x45, 0x43, 0x63, 0x45, 0x71, +0x72, 0x78, 0x4c, 0x4f, 0x6e, 0x31, 0x45, 0x38, 0x39, 0x61, 0x50, 0x67, 0x64, 0x34, 0x79, 0x38, +0x4f, 0x72, 0x74, 0x58, 0x37, 0x41, 0x59, 0x55, 0x46, 0x61, 0x4e, 0x47, 0x69, 0x42, 0x61, 0x78, +0x62, 0x68, 0x33, 0x33, 0x72, 0x4c, 0x5a, 0x66, 0x76, 0x75, 0x47, 0x64, 0x50, 0x74, 0x77, 0x6a, +0x66, 0x64, 0x4e, 0x50, 0x76, 0x71, 0x73, 0x2b, 0x39, 0x39, 0x37, 0x70, 0x37, 0x2f, 0x68, 0x66, +0x33, 0x44, 0x78, 0x78, 0x31, 0x46, 0x4e, 0x76, 0x57, 0x72, 0x57, 0x50, 0x71, 0x39, 0x4f, 0x6d, +0x73, 0x58, 0x62, 0x73, 0x57, 0x59, 0x77, 0x7a, 0x50, 0x66, 0x2f, 0x51, 0x52, 0x56, 0x7a, 0x33, +0x37, 0x4c, 0x46, 0x78, 0x34, 0x49, 0x64, 0x37, 0x6e, 0x6e, 0x2f, 0x2f, 0x6d, 0x2f, 0x53, 0x2f, +0x38, 0x2b, 0x34, 0x54, 0x6b, 0x51, 0x4d, 0x46, 0x6f, 0x6a, 0x4a, 0x39, 0x4f, 0x79, 0x69, 0x5a, +0x59, 0x6b, 0x4a, 0x58, 0x47, 0x4b, 0x45, 0x6d, 0x33, 0x49, 0x79, 0x47, 0x76, 0x45, 0x79, 0x78, +0x34, 0x6f, 0x59, 0x62, 0x57, 0x50, 0x53, 0x79, 0x78, 0x56, 0x36, 0x59, 0x44, 0x38, 0x4f, 0x44, +0x34, 0x2f, 0x67, 0x41, 0x4d, 0x7a, 0x45, 0x38, 0x6a, 0x47, 0x41, 0x67, 0x77, 0x66, 0x31, 0x75, +0x74, 0x48, 0x77, 0x47, 0x6d, 0x79, 0x56, 0x31, 0x35, 0x4b, 0x30, 0x46, 0x56, 0x74, 0x2f, 0x66, +0x37, 0x31, 0x38, 0x4c, 0x64, 0x77, 0x78, 0x71, 0x7a, 0x30, 0x6a, 0x6f, 0x75, 0x50, 0x4f, 0x33, +0x32, 0x61, 0x6b, 0x72, 0x52, 0x72, 0x55, 0x42, 0x78, 0x56, 0x68, 0x74, 0x4a, 0x51, 0x55, 0x67, +0x78, 0x39, 0x57, 0x58, 0x4a, 0x75, 0x65, 0x65, 0x36, 0x62, 0x63, 0x6d, 0x4d, 0x47, 0x54, 0x50, +0x41, 0x77, 0x4e, 0x30, 0x6e, 0x2b, 0x33, 0x31, 0x75, 0x4c, 0x63, 0x59, 0x36, 0x65, 0x71, 0x70, +0x45, 0x7a, 0x4c, 0x6d, 0x79, 0x48, 0x73, 0x70, 0x6e, 0x70, 0x55, 0x32, 0x51, 0x55, 0x55, 0x69, +0x66, 0x6d, 0x32, 0x37, 0x47, 0x73, 0x32, 0x36, 0x62, 0x39, 0x50, 0x44, 0x44, 0x69, 0x65, 0x65, +0x33, 0x54, 0x6a, 0x33, 0x58, 0x4c, 0x69, 0x68, 0x4a, 0x4b, 0x65, 0x31, 0x62, 0x36, 0x42, 0x30, +0x4f, 0x51, 0x43, 0x57, 0x75, 0x66, 0x55, 0x61, 0x6e, 0x71, 0x56, 0x50, 0x66, 0x42, 0x75, 0x43, +0x56, 0x75, 0x2f, 0x73, 0x79, 0x61, 0x33, 0x6b, 0x6c, 0x4a, 0x78, 0x36, 0x61, 0x79, 0x36, 0x79, +0x6c, 0x37, 0x6a, 0x78, 0x7a, 0x57, 0x51, 0x55, 0x6e, 0x44, 0x63, 0x78, 0x6c, 0x35, 0x74, 0x4a, +0x64, 0x46, 0x4e, 0x77, 0x33, 0x50, 0x32, 0x6b, 0x30, 0x54, 0x52, 0x58, 0x4b, 0x68, 0x78, 0x39, +0x2b, 0x47, 0x43, 0x72, 0x68, 0x75, 0x58, 0x38, 0x64, 0x79, 0x61, 0x76, 0x7a, 0x4c, 0x42, 0x63, +0x50, 0x4d, 0x62, 0x7a, 0x2b, 0x56, 0x59, 0x42, 0x4c, 0x6a, 0x72, 0x57, 0x38, 0x50, 0x4d, 0x2f, +0x6a, 0x6a, 0x38, 0x63, 0x6f, 0x58, 0x70, 0x6f, 0x54, 0x51, 0x70, 0x39, 0x77, 0x43, 0x74, 0x5a, +0x43, 0x72, 0x6b, 0x32, 0x4e, 0x6e, 0x44, 0x52, 0x38, 0x38, 0x73, 0x6e, 0x62, 0x44, 0x41, 0x4d, +0x69, 0x45, 0x59, 0x58, 0x57, 0x4d, 0x2f, 0x41, 0x38, 0x51, 0x79, 0x52, 0x38, 0x46, 0x73, 0x72, +0x4c, 0x35, 0x62, 0x55, 0x6c, 0x75, 0x34, 0x6a, 0x46, 0x4e, 0x51, 0x61, 0x66, 0x72, 0x30, 0x38, +0x37, 0x53, 0x72, 0x49, 0x45, 0x49, 0x34, 0x38, 0x32, 0x68, 0x6f, 0x66, 0x2b, 0x35, 0x69, 0x61, +0x66, 0x59, 0x63, 0x4f, 0x36, 0x38, 0x50, 0x6e, 0x6e, 0x36, 0x32, 0x6e, 0x66, 0x50, 0x6f, 0x64, +0x78, 0x34, 0x79, 0x35, 0x6c, 0x31, 0x4b, 0x6a, 0x42, 0x52, 0x4b, 0x4f, 0x61, 0x58, 0x72, 0x30, +0x4b, 0x32, 0x4c, 0x55, 0x72, 0x79, 0x74, 0x56, 0x58, 0x58, 0x2b, 0x76, 0x6a, 0x45, 0x33, 0x54, +0x79, 0x4c, 0x4b, 0x56, 0x6d, 0x78, 0x6f, 0x79, 0x37, 0x77, 0x4f, 0x77, 0x6d, 0x72, 0x2f, 0x73, +0x2f, 0x58, 0x41, 0x64, 0x59, 0x37, 0x52, 0x73, 0x4e, 0x6e, 0x59, 0x58, 0x66, 0x45, 0x73, 0x46, +0x72, 0x32, 0x52, 0x70, 0x49, 0x33, 0x36, 0x4d, 0x74, 0x6f, 0x36, 0x53, 0x6b, 0x42, 0x46, 0x44, +0x63, 0x66, 0x58, 0x64, 0x58, 0x30, 0x74, 0x4d, 0x37, 0x6f, 0x49, 0x31, 0x46, 0x74, 0x42, 0x39, +0x50, 0x57, 0x6c, 0x71, 0x55, 0x4a, 0x43, 0x75, 0x32, 0x56, 0x51, 0x52, 0x52, 0x42, 0x4b, 0x79, +0x6b, 0x58, 0x69, 0x6b, 0x75, 0x2b, 0x6d, 0x4d, 0x44, 0x73, 0x2b, 0x2b, 0x4d, 0x4b, 0x54, 0x4d, +0x34, 0x36, 0x52, 0x32, 0x59, 0x55, 0x54, 0x4f, 0x42, 0x6a, 0x4e, 0x47, 0x61, 0x64, 0x31, 0x66, +0x6e, 0x63, 0x45, 0x37, 0x2f, 0x43, 0x6b, 0x44, 0x76, 0x73, 0x58, 0x35, 0x44, 0x75, 0x6e, 0x4f, +0x66, 0x39, 0x6d, 0x7a, 0x4a, 0x6a, 0x49, 0x53, 0x54, 0x76, 0x77, 0x6b, 0x55, 0x39, 0x72, 0x72, +0x72, 0x58, 0x44, 0x72, 0x6e, 0x33, 0x46, 0x7a, 0x58, 0x32, 0x4b, 0x2b, 0x2f, 0x78, 0x6e, 0x37, +0x7a, 0x44, 0x66, 0x61, 0x72, 0x72, 0x2f, 0x62, 0x43, 0x69, 0x67, 0x76, 0x32, 0x77, 0x51, 0x64, +0x64, 0x2f, 0x59, 0x6b, 0x50, 0x59, 0x56, 0x39, 0x38, 0x41, 0x54, 0x77, 0x50, 0x75, 0x32, 0x48, +0x44, 0x37, 0x34, 0x4d, 0x79, 0x65, 0x68, 0x35, 0x32, 0x36, 0x39, 0x61, 0x47, 0x2b, 0x77, 0x38, +0x66, 0x44, 0x73, 0x5a, 0x67, 0x50, 0x2f, 0x73, 0x4d, 0x75, 0x33, 0x76, 0x33, 0x72, 0x39, 0x64, +0x66, 0x75, 0x78, 0x5a, 0x76, 0x2f, 0x6e, 0x77, 0x75, 0x50, 0x2f, 0x39, 0x38, 0x48, 0x6e, 0x33, +0x71, 0x4b, 0x62, 0x37, 0x37, 0x37, 0x6a, 0x76, 0x57, 0x72, 0x31, 0x2f, 0x50, 0x39, 0x75, 0x33, +0x62, 0x47, 0x58, 0x2f, 0x7a, 0x7a, 0x64, 0x6a, 0x79, 0x63, 0x75, 0x65, 0x6a, 0x33, 0x6b, 0x76, +0x39, 0x70, 0x35, 0x74, 0x5a, 0x64, 0x58, 0x38, 0x62, 0x44, 0x58, 0x6a, 0x36, 0x4a, 0x41, 0x64, +0x45, 0x6d, 0x6e, 0x66, 0x70, 0x45, 0x37, 0x51, 0x39, 0x62, 0x67, 0x6b, 0x41, 0x42, 0x58, 0x57, +0x47, 0x45, 0x38, 0x39, 0x76, 0x53, 0x7a, 0x6a, 0x73, 0x73, 0x66, 0x47, 0x35, 0x57, 0x72, 0x37, +0x65, 0x47, 0x58, 0x58, 0x37, 0x35, 0x2b, 0x4b, 0x4e, 0x47, 0x4c, 0x6c, 0x37, 0x37, 0x2b, 0x33, +0x33, 0x65, 0x5a, 0x6c, 0x54, 0x57, 0x57, 0x6d, 0x6c, 0x6b, 0x57, 0x69, 0x70, 0x49, 0x53, 0x6a, +0x35, 0x59, 0x78, 0x2f, 0x4a, 0x34, 0x4b, 0x44, 0x6b, 0x35, 0x78, 0x57, 0x53, 0x36, 0x2f, 0x38, +0x75, 0x32, 0x4c, 0x58, 0x4c, 0x47, 0x53, 0x56, 0x50, 0x50, 0x36, 0x57, 0x49, 0x6f, 0x31, 0x2b, +0x41, 0x63, 0x53, 0x57, 0x75, 0x7a, 0x56, 0x74, 0x39, 0x56, 0x6c, 0x70, 0x74, 0x51, 0x50, 0x71, +0x73, 0x74, 0x4e, 0x49, 0x32, 0x4d, 0x4e, 0x46, 0x4b, 0x37, 0x65, 0x4c, 0x52, 0x45, 0x2b, 0x6d, +0x39, 0x69, 0x37, 0x49, 0x39, 0x69, 0x42, 0x6e, 0x71, 0x4c, 0x49, 0x53, 0x52, 0x57, 0x4c, 0x76, +0x4e, 0x6b, 0x57, 0x48, 0x69, 0x30, 0x35, 0x75, 0x68, 0x49, 0x65, 0x46, 0x4e, 0x49, 0x4f, 0x46, +0x56, 0x38, 0x42, 0x47, 0x64, 0x56, 0x75, 0x4a, 0x35, 0x52, 0x59, 0x78, 0x2f, 0x42, 0x4f, 0x37, +0x39, 0x4e, 0x38, 0x78, 0x61, 0x58, 0x73, 0x6e, 0x75, 0x4f, 0x73, 0x56, 0x2f, 0x35, 0x70, 0x5a, +0x6a, 0x72, 0x65, 0x57, 0x64, 0x4f, 0x61, 0x56, 0x59, 0x61, 0x33, 0x68, 0x6e, 0x54, 0x67, 0x6e, +0x61, 0x47, 0x4b, 0x49, 0x33, 0x33, 0x51, 0x53, 0x37, 0x61, 0x7a, 0x42, 0x31, 0x64, 0x64, 0x68, +0x6f, 0x50, 0x53, 0x59, 0x57, 0x49, 0x35, 0x44, 0x66, 0x69, 0x76, 0x4d, 0x2f, 0x2f, 0x49, 0x69, +0x6e, 0x72, 0x2f, 0x30, 0x44, 0x72, 0x38, 0x36, 0x7a, 0x76, 0x44, 0x48, 0x50, 0x38, 0x4f, 0x6f, +0x63, 0x46, 0x79, 0x2f, 0x78, 0x2f, 0x43, 0x7a, 0x33, 0x4c, 0x4d, 0x2f, 0x4e, 0x39, 0x49, 0x67, +0x70, 0x78, 0x56, 0x55, 0x7a, 0x37, 0x34, 0x61, 0x4b, 0x4b, 0x74, 0x68, 0x64, 0x44, 0x62, 0x55, +0x31, 0x4c, 0x70, 0x33, 0x36, 0x4a, 0x61, 0x66, 0x53, 0x64, 0x39, 0x6c, 0x38, 0x31, 0x41, 0x6c, +0x6e, 0x45, 0x41, 0x6a, 0x4d, 0x49, 0x42, 0x43, 0x59, 0x51, 0x7a, 0x43, 0x6f, 0x6b, 0x53, 0x71, +0x4b, 0x44, 0x56, 0x37, 0x44, 0x52, 0x59, 0x66, 0x6d, 0x4e, 0x65, 0x4d, 0x57, 0x4e, 0x43, 0x6e, +0x58, 0x67, 0x55, 0x43, 0x41, 0x59, 0x55, 0x55, 0x44, 0x4f, 0x65, 0x48, 0x77, 0x32, 0x5a, 0x53, +0x58, 0x31, 0x7a, 0x4e, 0x6b, 0x53, 0x42, 0x64, 0x32, 0x37, 0x71, 0x78, 0x6e, 0x32, 0x4c, 0x42, +0x75, 0x62, 0x4e, 0x32, 0x36, 0x6d, 0x2f, 0x78, 0x57, 0x47, 0x57, 0x7a, 0x5a, 0x55, 0x6b, 0x64, +0x2b, 0x66, 0x67, 0x62, 0x72, 0x31, 0x31, 0x63, 0x67, 0x68, 0x54, 0x4f, 0x4d, 0x43, 0x75, 0x47, +0x77, 0x45, 0x45, 0x56, 0x46, 0x76, 0x75, 0x36, 0x64, 0x4b, 0x4b, 0x72, 0x55, 0x70, 0x34, 0x62, +0x54, 0x7a, 0x68, 0x74, 0x69, 0x42, 0x64, 0x5a, 0x4c, 0x4a, 0x36, 0x41, 0x56, 0x31, 0x6b, 0x74, +0x34, 0x6d, 0x76, 0x7a, 0x38, 0x69, 0x4e, 0x5a, 0x4c, 0x59, 0x56, 0x56, 0x32, 0x5a, 0x64, 0x74, +0x32, 0x67, 0x64, 0x45, 0x47, 0x72, 0x62, 0x64, 0x67, 0x62, 0x57, 0x31, 0x44, 0x50, 0x36, 0x51, +0x63, 0x53, 0x67, 0x74, 0x2b, 0x71, 0x58, 0x53, 0x47, 0x39, 0x4b, 0x4c, 0x73, 0x49, 0x68, 0x41, +0x51, 0x4d, 0x44, 0x42, 0x46, 0x2f, 0x49, 0x6d, 0x74, 0x4e, 0x77, 0x6e, 0x4f, 0x75, 0x65, 0x31, +0x78, 0x6f, 0x4d, 0x70, 0x35, 0x57, 0x76, 0x5a, 0x51, 0x76, 0x32, 0x6e, 0x2f, 0x4a, 0x54, 0x55, +0x41, 0x61, 0x32, 0x79, 0x44, 0x38, 0x49, 0x30, 0x63, 0x43, 0x54, 0x55, 0x31, 0x32, 0x47, 0x65, +0x65, 0x77, 0x61, 0x35, 0x64, 0x69, 0x79, 0x30, 0x71, 0x77, 0x70, 0x35, 0x78, 0x42, 0x72, 0x5a, +0x6a, 0x42, 0x2b, 0x77, 0x68, 0x42, 0x32, 0x4f, 0x2f, 0x6e, 0x74, 0x38, 0x59, 0x69, 0x70, 0x67, +0x51, 0x6d, 0x4e, 0x74, 0x76, 0x64, 0x32, 0x6d, 0x2b, 0x62, 0x37, 0x6d, 0x6c, 0x51, 0x58, 0x68, +0x53, 0x42, 0x58, 0x64, 0x76, 0x55, 0x45, 0x5a, 0x49, 0x42, 0x6d, 0x43, 0x67, 0x4e, 0x66, 0x62, +0x53, 0x53, 0x32, 0x48, 0x77, 0x59, 0x46, 0x65, 0x33, 0x65, 0x33, 0x66, 0x73, 0x77, 0x77, 0x2f, +0x37, 0x64, 0x58, 0x36, 0x6c, 0x2f, 0x70, 0x77, 0x35, 0x55, 0x46, 0x6e, 0x46, 0x48, 0x64, 0x64, +0x66, 0x7a, 0x38, 0x54, 0x48, 0x48, 0x2b, 0x66, 0x62, 0x62, 0x37, 0x39, 0x6c, 0x32, 0x62, 0x4a, +0x6c, 0x33, 0x50, 0x33, 0x6f, 0x6f, 0x7a, 0x77, 0x77, 0x5a, 0x67, 0x77, 0x32, 0x48, 0x73, 0x65, +0x2b, 0x4d, 0x6d, 0x33, 0x76, 0x39, 0x61, 0x32, 0x6c, 0x50, 0x43, 0x70, 0x35, 0x65, 0x46, 0x45, +0x70, 0x75, 0x32, 0x75, 0x69, 0x4b, 0x4f, 0x4d, 0x7a, 0x39, 0x79, 0x54, 0x70, 0x6e, 0x45, 0x33, +0x79, 0x45, 0x4e, 0x72, 0x77, 0x39, 0x71, 0x46, 0x58, 0x38, 0x30, 0x62, 0x5a, 0x7a, 0x64, 0x78, +0x32, 0x34, 0x79, 0x34, 0x49, 0x39, 0x48, 0x46, 0x34, 0x42, 0x4b, 0x45, 0x42, 0x35, 0x37, 0x57, +0x49, 0x52, 0x70, 0x58, 0x50, 0x2f, 0x47, 0x4e, 0x2b, 0x48, 0x35, 0x51, 0x7a, 0x6c, 0x5a, 0x56, +0x57, 0x4f, 0x2b, 0x48, 0x76, 0x56, 0x43, 0x43, 0x34, 0x75, 0x6f, 0x73, 0x69, 0x70, 0x31, 0x37, +0x79, 0x37, 0x2b, 0x63, 0x45, 0x58, 0x33, 0x77, 0x70, 0x69, 0x4d, 0x63, 0x6c, 0x6b, 0x59, 0x44, +0x67, 0x32, 0x6d, 0x73, 0x6c, 0x51, 0x38, 0x39, 0x76, 0x79, 0x39, 0x65, 0x62, 0x67, 0x4f, 0x32, +0x4a, 0x2b, 0x71, 0x41, 0x73, 0x53, 0x55, 0x70, 0x71, 0x59, 0x52, 0x75, 0x6f, 0x71, 0x45, 0x58, +0x71, 0x42, 0x4a, 0x43, 0x67, 0x70, 0x2f, 0x61, 0x74, 0x30, 0x4a, 0x45, 0x56, 0x34, 0x48, 0x57, +0x77, 0x49, 0x50, 0x33, 0x42, 0x61, 0x33, 0x78, 0x57, 0x59, 0x35, 0x38, 0x56, 0x4e, 0x35, 0x58, +0x67, 0x4a, 0x4f, 0x48, 0x4b, 0x77, 0x30, 0x6f, 0x49, 0x53, 0x79, 0x4c, 0x66, 0x67, 0x4d, 0x45, +0x5a, 0x63, 0x63, 0x38, 0x36, 0x4a, 0x70, 0x39, 0x33, 0x35, 0x35, 0x56, 0x7a, 0x39, 0x6a, 0x48, +0x35, 0x76, 0x44, 0x75, 0x33, 0x6c, 0x4c, 0x4f, 0x4f, 0x4b, 0x65, 0x43, 0x64, 0x75, 0x61, 0x56, +0x55, 0x47, 0x55, 0x74, 0x6f, 0x38, 0x75, 0x52, 0x6b, 0x4f, 0x4c, 0x4d, 0x78, 0x68, 0x6f, 0x41, +0x31, 0x42, 0x41, 0x4a, 0x42, 0x31, 0x73, 0x79, 0x63, 0x43, 0x58, 0x4d, 0x6b, 0x31, 0x73, 0x44, +0x37, 0x34, 0x79, 0x7a, 0x44, 0x4a, 0x33, 0x70, 0x38, 0x4d, 0x6b, 0x34, 0x79, 0x37, 0x4d, 0x45, +0x51, 0x48, 0x34, 0x2b, 0x74, 0x35, 0x2f, 0x67, 0x48, 0x4d, 0x2f, 0x6a, 0x52, 0x67, 0x2f, 0x70, +0x37, 0x4a, 0x7a, 0x52, 0x53, 0x6e, 0x66, 0x50, 0x79, 0x62, 0x69, 0x45, 0x61, 0x76, 0x5a, 0x48, +0x61, 0x67, 0x55, 0x65, 0x37, 0x38, 0x47, 0x6b, 0x54, 0x4a, 0x52, 0x42, 0x49, 0x72, 0x48, 0x6f, +0x2f, 0x34, 0x46, 0x6e, 0x46, 0x35, 0x36, 0x76, 0x72, 0x47, 0x78, 0x6c, 0x65, 0x74, 0x55, 0x39, +0x4e, 0x70, 0x6f, 0x78, 0x7a, 0x4e, 0x2b, 0x65, 0x6b, 0x42, 0x37, 0x6c, 0x6a, 0x57, 0x6a, 0x46, +0x58, 0x38, 0x78, 0x4b, 0x62, 0x6e, 0x6a, 0x2b, 0x41, 0x36, 0x69, 0x30, 0x6c, 0x74, 0x4e, 0x61, +0x61, 0x62, 0x37, 0x39, 0x30, 0x62, 0x46, 0x55, 0x62, 0x68, 0x45, 0x73, 0x6c, 0x58, 0x79, 0x77, +0x30, 0x6c, 0x30, 0x6a, 0x70, 0x6b, 0x6e, 0x49, 0x4b, 0x6c, 0x36, 0x64, 0x51, 0x53, 0x30, 0x6c, +0x4c, 0x32, 0x5a, 0x35, 0x6c, 0x6c, 0x41, 0x4e, 0x68, 0x66, 0x2b, 0x56, 0x50, 0x45, 0x58, 0x35, +0x53, 0x38, 0x42, 0x64, 0x65, 0x67, 0x47, 0x68, 0x55, 0x55, 0x62, 0x74, 0x37, 0x4e, 0x52, 0x73, +0x32, 0x76, 0x45, 0x39, 0x63, 0x68, 0x4f, 0x6e, 0x54, 0x61, 0x79, 0x67, 0x74, 0x57, 0x72, 0x52, +0x50, 0x30, 0x59, 0x5a, 0x38, 0x5a, 0x69, 0x46, 0x74, 0x2f, 0x57, 0x66, 0x51, 0x56, 0x4d, 0x59, +0x45, 0x6d, 0x53, 0x45, 0x46, 0x53, 0x48, 0x62, 0x48, 0x42, 0x62, 0x6b, 0x52, 0x4a, 0x37, 0x68, +0x4a, 0x72, 0x35, 0x71, 0x52, 0x49, 0x47, 0x44, 0x57, 0x4b, 0x57, 0x43, 0x37, 0x50, 0x6f, 0x66, +0x6a, 0x43, 0x74, 0x63, 0x70, 0x77, 0x69, 0x39, 0x53, 0x56, 0x76, 0x77, 0x47, 0x77, 0x57, 0x39, +0x49, 0x45, 0x4f, 0x6f, 0x6f, 0x36, 0x55, 0x49, 0x47, 0x42, 0x2b, 0x56, 0x4e, 0x2b, 0x42, 0x59, +0x78, 0x42, 0x6a, 0x74, 0x76, 0x48, 0x72, 0x5a, 0x76, 0x58, 0x2b, 0x7a, 0x6f, 0x30, 0x64, 0x68, +0x6e, 0x6e, 0x33, 0x57, 0x72, 0x2f, 0x30, 0x55, 0x58, 0x59, 0x62, 0x39, 0x64, 0x32, 0x52, 0x79, +0x4b, 0x6d, 0x43, 0x6a, 0x39, 0x2b, 0x32, 0x4e, 0x66, 0x65, 0x4b, 0x45, 0x52, 0x6c, 0x4e, 0x66, +0x36, 0x71, 0x5a, 0x69, 0x62, 0x73, 0x66, 0x71, 0x6d, 0x31, 0x47, 0x39, 0x30, 0x2f, 0x32, 0x37, +0x64, 0x59, 0x4f, 0x68, 0x51, 0x37, 0x4b, 0x4f, 0x50, 0x59, 0x68, 0x63, 0x75, 0x78, 0x50, 0x62, +0x72, 0x68, 0x36, 0x32, 0x72, 0x63, 0x79, 0x76, 0x34, 0x35, 0x5a, 0x64, 0x6a, 0x53, 0x30, 0x76, +0x33, 0x58, 0x76, 0x2f, 0x39, 0x39, 0x30, 0x41, 0x4b, 0x37, 0x72, 0x72, 0x70, 0x4a, 0x69, 0x5a, +0x4d, 0x6d, 0x73, 0x54, 0x53, 0x70, 0x55, 0x74, 0x5a, 0x73, 0x6d, 0x51, 0x4a, 0x64, 0x7a, 0x7a, +0x34, 0x49, 0x49, 0x2f, 0x38, 0x35, 0x53, 0x39, 0x75, 0x45, 0x6e, 0x6a, 0x78, 0x78, 0x65, 0x62, +0x31, 0x6a, 0x63, 0x45, 0x72, 0x2f, 0x51, 0x75, 0x74, 0x78, 0x57, 0x59, 0x65, 0x4f, 0x2f, 0x34, +0x31, 0x46, 0x6d, 0x32, 0x70, 0x35, 0x6c, 0x2f, 0x4c, 0x74, 0x76, 0x76, 0x38, 0x37, 0x51, 0x6e, +0x42, 0x54, 0x77, 0x69, 0x4e, 0x2b, 0x7a, 0x78, 0x6c, 0x33, 0x61, 0x58, 0x38, 0x4c, 0x41, 0x34, +0x47, 0x38, 0x54, 0x6d, 0x45, 0x46, 0x46, 0x72, 0x44, 0x79, 0x70, 0x6a, 0x6b, 0x6e, 0x75, 0x65, +0x4c, 0x55, 0x63, 0x61, 0x77, 0x76, 0x54, 0x70, 0x4f, 0x49, 0x67, 0x47, 0x49, 0x2b, 0x59, 0x33, +0x6e, 0x68, 0x78, 0x52, 0x57, 0x57, 0x71, 0x6b, 0x77, 0x41, 0x63, 0x57, 0x35, 0x2f, 0x53, 0x51, +0x6e, 0x5a, 0x6b, 0x70, 0x4b, 0x74, 0x6b, 0x69, 0x75, 0x6e, 0x79, 0x44, 0x5a, 0x75, 0x64, 0x4f, +0x35, 0x4a, 0x66, 0x76, 0x33, 0x6c, 0x6c, 0x77, 0x33, 0x4a, 0x70, 0x4f, 0x73, 0x44, 0x71, 0x31, +0x5a, 0x56, 0x44, 0x36, 0x49, 0x4b, 0x2b, 0x2f, 0x39, 0x4d, 0x78, 0x7a, 0x6d, 0x55, 0x31, 0x49, +0x5a, 0x6b, 0x70, 0x78, 0x34, 0x79, 0x5a, 0x57, 0x2f, 0x69, 0x66, 0x41, 0x6e, 0x7a, 0x38, 0x61, +0x78, 0x31, 0x31, 0x41, 0x46, 0x67, 0x55, 0x50, 0x42, 0x47, 0x36, 0x74, 0x68, 0x63, 0x79, 0x49, +0x42, 0x69, 0x52, 0x38, 0x74, 0x4f, 0x47, 0x34, 0x63, 0x72, 0x36, 0x31, 0x62, 0x78, 0x79, 0x57, +0x58, 0x58, 0x67, 0x72, 0x7a, 0x35, 0x73, 0x45, 0x64, 0x64, 0x2b, 0x42, 0x7a, 0x76, 0x7a, 0x6b, +0x4e, 0x70, 0x72, 0x4d, 0x6b, 0x4e, 0x42, 0x65, 0x34, 0x48, 0x37, 0x43, 0x47, 0x64, 0x2b, 0x65, +0x57, 0x59, 0x61, 0x33, 0x6c, 0x33, 0x62, 0x6d, 0x6c, 0x47, 0x47, 0x4e, 0x35, 0x5a, 0x32, 0x34, +0x70, 0x6c, 0x63, 0x5a, 0x51, 0x5a, 0x69, 0x7a, 0x78, 0x43, 0x79, 0x2f, 0x45, 0x78, 0x6d, 0x4c, +0x75, 0x69, 0x4c, 0x76, 0x73, 0x76, 0x4d, 0x48, 0x57, 0x72, 0x63, 0x6d, 0x66, 0x50, 0x52, 0x75, +0x75, 0x6e, 0x67, 0x66, 0x41, 0x79, 0x51, 0x39, 0x34, 0x47, 0x47, 0x4d, 0x5a, 0x39, 0x6d, 0x41, +0x49, 0x4a, 0x58, 0x48, 0x43, 0x54, 0x78, 0x78, 0x56, 0x74, 0x35, 0x54, 0x4d, 0x6b, 0x55, 0x39, +0x43, 0x66, 0x54, 0x33, 0x55, 0x31, 0x6d, 0x4a, 0x6a, 0x4d, 0x59, 0x77, 0x51, 0x5a, 0x46, 0x7a, +0x78, 0x4b, 0x4f, 0x72, 0x48, 0x46, 0x55, 0x51, 0x6d, 0x76, 0x30, 0x45, 0x6f, 0x65, 0x42, 0x5a, +0x78, 0x73, 0x51, 0x31, 0x72, 0x46, 0x4f, 0x6d, 0x52, 0x36, 0x78, 0x45, 0x32, 0x7a, 0x4b, 0x65, +0x72, 0x71, 0x71, 0x6d, 0x4a, 0x4b, 0x56, 0x2f, 0x37, 0x4d, 0x55, 0x6c, 0x57, 0x59, 0x75, 0x6e, +0x54, 0x73, 0x68, 0x58, 0x6c, 0x52, 0x64, 0x6a, 0x78, 0x37, 0x44, 0x6f, 0x6d, 0x56, 0x63, 0x66, +0x4a, 0x79, 0x51, 0x6b, 0x33, 0x4c, 0x47, 0x54, 0x37, 0x77, 0x45, 0x72, 0x63, 0x59, 0x38, 0x55, +0x34, 0x6a, 0x4f, 0x6e, 0x76, 0x34, 0x77, 0x51, 0x53, 0x4b, 0x37, 0x39, 0x75, 0x6d, 0x44, 0x69, +0x39, 0x49, 0x4e, 0x61, 0x47, 0x4b, 0x43, 0x75, 0x76, 0x5a, 0x66, 0x6e, 0x4b, 0x61, 0x58, 0x54, +0x4e, 0x62, 0x30, 0x6b, 0x36, 0x78, 0x61, 0x7a, 0x2b, 0x38, 0x51, 0x4d, 0x47, 0x44, 0x4c, 0x67, +0x48, 0x70, 0x66, 0x6f, 0x43, 0x43, 0x59, 0x49, 0x54, 0x42, 0x79, 0x62, 0x43, 0x53, 0x68, 0x61, +0x56, 0x43, 0x54, 0x37, 0x5a, 0x4a, 0x42, 0x6c, 0x59, 0x49, 0x41, 0x6c, 0x37, 0x6b, 0x73, 0x38, +0x32, 0x43, 0x38, 0x37, 0x73, 0x49, 0x68, 0x69, 0x55, 0x33, 0x34, 0x52, 0x54, 0x55, 0x34, 0x44, +0x58, 0x66, 0x53, 0x35, 0x6a, 0x78, 0x33, 0x5a, 0x6e, 0x38, 0x2b, 0x61, 0x34, 0x63, 0x78, 0x54, +0x34, 0x4e, 0x4f, 0x34, 0x76, 0x76, 0x6c, 0x68, 0x45, 0x52, 0x6f, 0x62, 0x6a, 0x57, 0x71, 0x79, +0x72, 0x55, 0x34, 0x77, 0x59, 0x73, 0x62, 0x34, 0x52, 0x77, 0x31, 0x4c, 0x6e, 0x7a, 0x6d, 0x6e, +0x4d, 0x6e, 0x54, 0x76, 0x62, 0x33, 0x77, 0x4b, 0x6b, 0x73, 0x6f, 0x70, 0x71, 0x37, 0x56, 0x62, +0x2b, 0x32, 0x32, 0x2f, 0x48, 0x54, 0x70, 0x36, 0x4d, 0x58, 0x62, 0x72, 0x55, 0x58, 0x65, 0x66, +0x6b, 0x4e, 0x41, 0x4d, 0x6a, 0x47, 0x43, 0x43, 0x37, 0x5a, 0x55, 0x73, 0x59, 0x66, 0x54, 0x74, +0x32, 0x30, 0x38, 0x62, 0x47, 0x74, 0x4d, 0x52, 0x37, 0x53, 0x2b, 0x2f, 0x64, 0x46, 0x4d, 0x6f, +0x49, 0x45, 0x49, 0x75, 0x37, 0x2f, 0x35, 0x38, 0x30, 0x7a, 0x4e, 0x31, 0x2f, 0x34, 0x55, 0x4c, +0x33, 0x76, 0x61, 0x56, 0x4c, 0x73, 0x57, 0x2b, 0x39, 0x35, 0x62, 0x59, 0x69, 0x37, 0x37, 0x7a, +0x6a, 0x32, 0x76, 0x48, 0x6c, 0x6c, 0x38, 0x33, 0x72, 0x4a, 0x39, 0x72, 0x2f, 0x7a, 0x6a, 0x73, +0x67, 0x4a, 0x52, 0x4e, 0x47, 0x6a, 0x2b, 0x62, 0x4f, 0x69, 0x52, 0x4e, 0x5a, 0x76, 0x48, 0x67, +0x78, 0x33, 0x33, 0x7a, 0x7a, 0x44, 0x54, 0x65, 0x4e, 0x76, 0x35, 0x66, 0x48, 0x37, 0x37, 0x2f, +0x50, 0x54, 0x51, 0x4c, 0x50, 0x50, 0x74, 0x75, 0x73, 0x2f, 0x73, 0x63, 0x6c, 0x78, 0x31, 0x4a, +0x52, 0x56, 0x38, 0x6d, 0x6c, 0x48, 0x53, 0x31, 0x48, 0x64, 0x47, 0x78, 0x42, 0x6c, 0x39, 0x77, +0x30, 0x72, 0x76, 0x74, 0x6f, 0x6a, 0x63, 0x76, 0x58, 0x6f, 0x47, 0x6b, 0x51, 0x66, 0x75, 0x57, +0x45, 0x2b, 0x70, 0x70, 0x4f, 0x4c, 0x2f, 0x50, 0x57, 0x7a, 0x68, 0x7a, 0x65, 0x46, 0x77, 0x4a, +0x38, 0x64, 0x69, 0x53, 0x74, 0x4e, 0x44, 0x73, 0x71, 0x66, 0x4a, 0x2b, 0x38, 0x64, 0x6d, 0x6d, +0x70, 0x6c, 0x54, 0x4b, 0x6b, 0x79, 0x64, 0x70, 0x66, 0x66, 0x33, 0x34, 0x66, 0x79, 0x53, 0x58, +0x6a, 0x6b, 0x76, 0x5a, 0x35, 0x69, 0x6d, 0x74, 0x37, 0x4b, 0x48, 0x4a, 0x71, 0x4a, 0x64, 0x4e, +0x65, 0x45, 0x6e, 0x7a, 0x38, 0x71, 0x53, 0x51, 0x57, 0x63, 0x31, 0x46, 0x6f, 0x56, 0x31, 0x77, +0x6d, 0x4f, 0x66, 0x6e, 0x69, 0x41, 0x75, 0x4b, 0x45, 0x75, 0x58, 0x2f, 0x4a, 0x62, 0x5a, 0x54, +0x45, 0x6a, 0x34, 0x4c, 0x61, 0x4b, 0x69, 0x68, 0x59, 0x51, 0x6b, 0x46, 0x47, 0x46, 0x34, 0x53, +0x4f, 0x4a, 0x31, 0x63, 0x34, 0x61, 0x66, 0x44, 0x50, 0x4a, 0x69, 0x6b, 0x41, 0x43, 0x61, 0x30, +0x6d, 0x38, 0x62, 0x6c, 0x6a, 0x5a, 0x67, 0x54, 0x61, 0x7a, 0x32, 0x63, 0x4d, 0x63, 0x4c, 0x72, +0x53, 0x56, 0x45, 0x76, 0x70, 0x38, 0x2f, 0x32, 0x35, 0x6c, 0x65, 0x2b, 0x63, 0x77, 0x59, 0x50, +0x52, 0x61, 0x39, 0x59, 0x77, 0x65, 0x76, 0x52, 0x6f, 0x48, 0x6e, 0x76, 0x6b, 0x45, 0x56, 0x36, +0x52, 0x45, 0x69, 0x32, 0x45, 0x4f, 0x36, 0x53, 0x6b, 0x70, 0x56, 0x4b, 0x4d, 0x42, 0x59, 0x59, +0x71, 0x78, 0x59, 0x6d, 0x48, 0x35, 0x76, 0x48, 0x4f, 0x6e, 0x46, 0x4b, 0x6e, 0x42, 0x63, 0x77, +0x74, 0x34, 0x36, 0x78, 0x6a, 0x38, 0x6e, 0x6c, 0x32, 0x54, 0x69, 0x6c, 0x58, 0x48, 0x70, 0x50, +0x50, 0x2b, 0x45, 0x39, 0x4b, 0x43, 0x62, 0x37, 0x32, 0x57, 0x73, 0x50, 0x2b, 0x33, 0x31, 0x70, +0x6e, 0x35, 0x77, 0x6b, 0x47, 0x57, 0x66, 0x72, 0x63, 0x63, 0x31, 0x42, 0x63, 0x7a, 0x79, 0x58, +0x48, 0x57, 0x70, 0x36, 0x66, 0x5a, 0x66, 0x6c, 0x6f, 0x58, 0x49, 0x78, 0x68, 0x44, 0x36, 0x54, +0x7a, 0x38, 0x62, 0x6a, 0x64, 0x74, 0x48, 0x74, 0x49, 0x73, 0x48, 0x47, 0x30, 0x6f, 0x65, 0x6a, +0x47, 0x4f, 0x4c, 0x74, 0x66, 0x65, 0x6a, 0x46, 0x5a, 0x50, 0x32, 0x46, 0x4c, 0x71, 0x47, 0x72, +0x62, 0x68, 0x73, 0x70, 0x50, 0x33, 0x6b, 0x59, 0x6f, 0x51, 0x31, 0x5a, 0x57, 0x4f, 0x37, 0x7a, +0x41, 0x76, 0x56, 0x68, 0x72, 0x43, 0x55, 0x64, 0x43, 0x42, 0x49, 0x31, 0x68, 0x30, 0x6e, 0x6b, +0x64, 0x66, 0x4f, 0x30, 0x6b, 0x5a, 0x51, 0x74, 0x67, 0x47, 0x72, 0x59, 0x43, 0x6f, 0x55, 0x43, +0x41, 0x4b, 0x77, 0x38, 0x38, 0x70, 0x68, 0x6e, 0x2b, 0x49, 0x50, 0x58, 0x36, 0x56, 0x37, 0x45, +0x49, 0x6e, 0x6f, 0x4e, 0x63, 0x59, 0x2f, 0x79, 0x51, 0x61, 0x36, 0x74, 0x49, 0x73, 0x6b, 0x50, +0x37, 0x6e, 0x79, 0x30, 0x53, 0x71, 0x36, 0x4e, 0x30, 0x37, 0x4a, 0x42, 0x44, 0x2b, 0x38, 0x4c, +0x37, 0x57, 0x66, 0x79, 0x66, 0x30, 0x5a, 0x52, 0x76, 0x61, 0x38, 0x6e, 0x4a, 0x31, 0x33, 0x31, +0x4f, 0x4b, 0x4a, 0x78, 0x42, 0x65, 0x65, 0x55, 0x6d, 0x6f, 0x49, 0x45, 0x48, 0x55, 0x55, 0x71, +0x4c, 0x5a, 0x79, 0x55, 0x2f, 0x56, 0x45, 0x67, 0x57, 0x6c, 0x51, 0x71, 0x75, 0x36, 0x75, 0x31, +0x57, 0x36, 0x6e, 0x75, 0x58, 0x43, 0x44, 0x70, 0x6d, 0x53, 0x77, 0x62, 0x6e, 0x2b, 0x2f, 0x67, +0x61, 0x50, 0x32, 0x6b, 0x73, 0x50, 0x68, 0x79, 0x36, 0x45, 0x57, 0x75, 0x53, 0x74, 0x4c, 0x7a, +0x34, 0x55, 0x68, 0x47, 0x7a, 0x5a, 0x74, 0x58, 0x77, 0x39, 0x4e, 0x50, 0x6c, 0x53, 0x47, 0x6d, +0x34, 0x35, 0x70, 0x70, 0x38, 0x50, 0x76, 0x79, 0x77, 0x4b, 0x30, 0x4f, 0x48, 0x72, 0x6b, 0x31, +0x4f, 0x41, 0x45, 0x6f, 0x35, 0x4d, 0x36, 0x72, 0x62, 0x41, 0x71, 0x53, 0x79, 0x69, 0x68, 0x71, +0x44, 0x37, 0x64, 0x67, 0x52, 0x2b, 0x2f, 0x35, 0x37, 0x32, 0x46, 0x74, 0x76, 0x78, 0x58, 0x37, +0x79, 0x69, 0x64, 0x4d, 0x41, 0x65, 0x76, 0x54, 0x59, 0x4d, 0x78, 0x53, 0x78, 0x61, 0x66, 0x30, +0x45, 0x4b, 0x32, 0x6b, 0x54, 0x6c, 0x58, 0x65, 0x76, 0x55, 0x4d, 0x62, 0x55, 0x2b, 0x6c, 0x75, +0x33, 0x77, 0x4f, 0x42, 0x42, 0x32, 0x41, 0x4d, 0x4f, 0x77, 0x43, 0x35, 0x5a, 0x6a, 0x4f, 0x33, +0x56, 0x47, 0x2f, 0x76, 0x39, 0x39, 0x32, 0x35, 0x43, 0x4f, 0x4f, 0x38, 0x38, 0x37, 0x4f, 0x7a, +0x5a, 0x76, 0x33, 0x33, 0x2f, 0x4e, 0x39, 0x34, 0x41, 0x49, 0x66, 0x6a, 0x62, 0x6e, 0x58, 0x64, +0x79, 0x36, 0x34, 0x51, 0x4a, 0x4c, 0x46, 0x79, 0x34, 0x6b, 0x41, 0x55, 0x4c, 0x35, 0x6e, 0x50, +0x4e, 0x32, 0x4c, 0x45, 0x38, 0x38, 0x37, 0x65, 0x48, 0x33, 0x43, 0x54, 0x77, 0x31, 0x46, 0x4d, +0x4e, 0x39, 0x63, 0x73, 0x65, 0x5a, 0x6b, 0x52, 0x52, 0x53, 0x36, 0x77, 0x73, 0x77, 0x64, 0x62, +0x4e, 0x34, 0x66, 0x75, 0x61, 0x51, 0x54, 0x7a, 0x30, 0x39, 0x53, 0x61, 0x73, 0x42, 0x61, 0x46, +0x4e, 0x63, 0x75, 0x57, 0x38, 0x73, 0x66, 0x4d, 0x4c, 0x48, 0x4a, 0x38, 0x33, 0x6a, 0x2b, 0x45, +0x4c, 0x6e, 0x32, 0x50, 0x45, 0x77, 0x71, 0x66, 0x70, 0x6c, 0x4a, 0x63, 0x4f, 0x36, 0x6d, 0x4e, +0x30, 0x36, 0x66, 0x6e, 0x77, 0x2f, 0x53, 0x33, 0x59, 0x6a, 0x52, 0x76, 0x2f, 0x75, 0x2b, 0x65, +0x50, 0x4f, 0x56, 0x62, 0x61, 0x45, 0x62, 0x30, 0x55, 0x70, 0x37, 0x59, 0x51, 0x56, 0x4f, 0x35, +0x51, 0x6a, 0x4c, 0x35, 0x66, 0x55, 0x6c, 0x4c, 0x71, 0x59, 0x69, 0x61, 0x36, 0x64, 0x52, 0x53, +0x4d, 0x47, 0x68, 0x4f, 0x6b, 0x65, 0x35, 0x39, 0x73, 0x50, 0x74, 0x35, 0x79, 0x4c, 0x50, 0x63, +0x74, 0x48, 0x6f, 0x76, 0x77, 0x6f, 0x46, 0x73, 0x4c, 0x78, 0x79, 0x71, 0x72, 0x7a, 0x7a, 0x6f, +0x53, 0x4f, 0x74, 0x36, 0x43, 0x74, 0x52, 0x73, 0x64, 0x74, 0x56, 0x4d, 0x6a, 0x74, 0x57, 0x2f, +0x76, 0x35, 0x30, 0x43, 0x67, 0x47, 0x77, 0x2b, 0x48, 0x6c, 0x6c, 0x44, 0x30, 0x41, 0x52, 0x69, +0x74, 0x32, 0x4b, 0x69, 0x55, 0x59, 0x34, 0x47, 0x57, 0x7a, 0x73, 0x44, 0x59, 0x5a, 0x75, 0x46, +0x43, 0x4c, 0x72, 0x76, 0x73, 0x4d, 0x6f, 0x36, 0x61, 0x50, 0x70, 0x30, 0x35, 0x38, 0x2b, 0x62, +0x78, 0x57, 0x44, 0x7a, 0x65, 0x43, 0x42, 0x6a, 0x56, 0x54, 0x55, 0x72, 0x4b, 0x63, 0x52, 0x50, +0x4e, 0x7a, 0x4b, 0x55, 0x75, 0x51, 0x65, 0x59, 0x37, 0x63, 0x30, 0x75, 0x78, 0x78, 0x76, 0x4c, +0x4d, 0x6e, 0x46, 0x49, 0x71, 0x72, 0x4f, 0x47, 0x75, 0x44, 0x30, 0x75, 0x70, 0x71, 0x37, 0x61, +0x49, 0x45, 0x53, 0x50, 0x63, 0x65, 0x35, 0x63, 0x75, 0x30, 0x32, 0x39, 0x4d, 0x4b, 0x57, 0x6a, +0x58, 0x6a, 0x76, 0x62, 0x7a, 0x35, 0x31, 0x4e, 0x38, 0x35, 0x61, 0x64, 0x4d, 0x6e, 0x65, 0x4f, +0x68, 0x46, 0x4a, 0x7a, 0x77, 0x59, 0x42, 0x70, 0x47, 0x57, 0x64, 0x6f, 0x39, 0x57, 0x49, 0x2b, +0x4f, 0x2f, 0x30, 0x7a, 0x52, 0x4e, 0x52, 0x6f, 0x32, 0x47, 0x31, 0x71, 0x63, 0x64, 0x68, 0x6f, +0x32, 0x46, 0x6e, 0x50, 0x70, 0x6e, 0x65, 0x4e, 0x78, 0x62, 0x43, 0x78, 0x47, 0x36, 0x31, 0x45, +0x58, 0x38, 0x76, 0x50, 0x36, 0x6e, 0x78, 0x6d, 0x39, 0x35, 0x51, 0x44, 0x2b, 0x64, 0x48, 0x79, +0x41, 0x36, 0x6e, 0x71, 0x56, 0x35, 0x46, 0x70, 0x49, 0x68, 0x4a, 0x56, 0x72, 0x59, 0x39, 0x48, +0x57, 0x63, 0x53, 0x38, 0x34, 0x66, 0x67, 0x6d, 0x33, 0x44, 0x54, 0x44, 0x47, 0x6b, 0x4a, 0x73, +0x52, 0x34, 0x6f, 0x5a, 0x6e, 0x69, 0x74, 0x6e, 0x2b, 0x54, 0x4c, 0x38, 0x47, 0x77, 0x64, 0x35, +0x48, 0x56, 0x6d, 0x4b, 0x6c, 0x6e, 0x41, 0x62, 0x71, 0x45, 0x6f, 0x6d, 0x6f, 0x42, 0x73, 0x46, +0x50, 0x6f, 0x42, 0x36, 0x39, 0x49, 0x4e, 0x5a, 0x4c, 0x6f, 0x36, 0x35, 0x71, 0x42, 0x74, 0x57, +0x6c, 0x4d, 0x2b, 0x6e, 0x57, 0x34, 0x68, 0x67, 0x36, 0x65, 0x49, 0x55, 0x73, 0x58, 0x54, 0x69, +0x66, 0x56, 0x75, 0x32, 0x4c, 0x69, 0x41, 0x54, 0x44, 0x76, 0x67, 0x62, 0x67, 0x55, 0x36, 0x41, +0x70, 0x67, 0x37, 0x4b, 0x53, 0x66, 0x69, 0x30, 0x46, 0x6c, 0x2f, 0x63, 0x53, 0x50, 0x4c, 0x54, +0x43, 0x45, 0x5a, 0x4a, 0x65, 0x31, 0x55, 0x66, 0x53, 0x76, 0x59, 0x56, 0x41, 0x47, 0x4a, 0x6d, +0x63, 0x41, 0x42, 0x4a, 0x62, 0x41, 0x41, 0x66, 0x6c, 0x78, 0x67, 0x38, 0x46, 0x74, 0x30, 0x78, +0x4e, 0x43, 0x6e, 0x38, 0x5a, 0x51, 0x6c, 0x69, 0x45, 0x4d, 0x45, 0x79, 0x65, 0x58, 0x45, 0x6f, +0x38, 0x72, 0x70, 0x6e, 0x35, 0x52, 0x58, 0x65, 0x4f, 0x4f, 0x76, 0x4b, 0x58, 0x5a, 0x49, 0x77, +0x46, 0x4b, 0x48, 0x38, 0x4c, 0x34, 0x41, 0x2f, 0x4d, 0x78, 0x44, 0x62, 0x41, 0x48, 0x6e, 0x4d, +0x4d, 0x64, 0x74, 0x59, 0x73, 0x37, 0x43, 0x75, 0x76, 0x59, 0x72, 0x74, 0x30, 0x77, 0x56, 0x35, +0x77, 0x67, 0x52, 0x50, 0x45, 0x4a, 0x4b, 0x74, 0x6f, 0x41, 0x78, 0x53, 0x78, 0x57, 0x66, 0x32, +0x39, 0x49, 0x5a, 0x6a, 0x32, 0x41, 0x6d, 0x56, 0x73, 0x56, 0x50, 0x2b, 0x56, 0x56, 0x78, 0x77, +0x62, 0x38, 0x4f, 0x6a, 0x52, 0x54, 0x76, 0x57, 0x33, 0x46, 0x6e, 0x76, 0x78, 0x78, 0x64, 0x6a, +0x61, 0x57, 0x75, 0x79, 0x30, 0x61, 0x62, 0x39, 0x64, 0x50, 0x33, 0x48, 0x2f, 0x61, 0x64, 0x4f, +0x77, 0x38, 0x54, 0x69, 0x54, 0x78, 0x34, 0x2f, 0x6e, 0x68, 0x72, 0x76, 0x76, 0x35, 0x75, 0x75, +0x76, 0x76, 0x2b, 0x62, 0x72, 0x72, 0x37, 0x2f, 0x6d, 0x7a, 0x36, 0x4e, 0x76, 0x35, 0x34, 0x56, +0x4a, 0x6b, 0x78, 0x7a, 0x6f, 0x35, 0x4c, 0x50, 0x50, 0x58, 0x50, 0x32, 0x43, 0x73, 0x58, 0x69, +0x78, 0x35, 0x5a, 0x54, 0x4c, 0x53, 0x73, 0x62, 0x4f, 0x36, 0x55, 0x78, 0x4e, 0x37, 0x61, 0x61, +0x55, 0x66, 0x62, 0x4b, 0x76, 0x4c, 0x69, 0x76, 0x44, 0x6f, 0x32, 0x76, 0x2b, 0x78, 0x45, 0x54, +0x39, 0x52, 0x7a, 0x34, 0x37, 0x2f, 0x42, 0x49, 0x65, 0x57, 0x58, 0x73, 0x46, 0x71, 0x2b, 0x4d, +0x6e, 0x67, 0x31, 0x44, 0x37, 0x2f, 0x66, 0x79, 0x30, 0x67, 0x2b, 0x76, 0x37, 0x53, 0x6f, 0x6f, +0x69, 0x67, 0x71, 0x65, 0x66, 0x55, 0x6e, 0x7a, 0x38, 0x71, 0x55, 0x42, 0x49, 0x69, 0x52, 0x4b, +0x43, 0x79, 0x79, 0x36, 0x55, 0x44, 0x4c, 0x38, 0x34, 0x6e, 0x7a, 0x4a, 0x64, 0x79, 0x4b, 0x33, +0x7a, 0x72, 0x2b, 0x43, 0x62, 0x73, 0x6b, 0x4f, 0x64, 0x4f, 0x31, 0x49, 0x33, 0x73, 0x4d, 0x6f, +0x61, 0x67, 0x30, 0x39, 0x61, 0x36, 0x59, 0x64, 0x66, 0x4e, 0x78, 0x50, 0x34, 0x35, 0x73, 0x4c, +0x76, 0x76, 0x75, 0x66, 0x75, 0x2f, 0x2f, 0x61, 0x48, 0x63, 0x47, 0x42, 0x66, 0x53, 0x53, 0x77, +0x71, 0x2f, 0x50, 0x32, 0x30, 0x63, 0x4c, 0x42, 0x68, 0x4d, 0x34, 0x34, 0x56, 0x33, 0x30, 0x76, +0x4d, 0x41, 0x35, 0x49, 0x73, 0x63, 0x7a, 0x50, 0x50, 0x54, 0x66, 0x58, 0x44, 0x75, 0x6e, 0x30, +0x2b, 0x67, 0x34, 0x78, 0x4d, 0x78, 0x66, 0x75, 0x66, 0x77, 0x47, 0x58, 0x6e, 0x42, 0x4f, 0x6a, +0x58, 0x4c, 0x78, 0x65, 0x64, 0x38, 0x4a, 0x79, 0x6b, 0x57, 0x50, 0x75, 0x54, 0x31, 0x2b, 0x66, +0x50, 0x53, 0x4b, 0x37, 0x2b, 0x41, 0x57, 0x50, 0x77, 0x6f, 0x6c, 0x45, 0x77, 0x68, 0x6e, 0x64, +0x48, 0x6a, 0x2b, 0x62, 0x70, 0x43, 0x62, 0x30, 0x6f, 0x4c, 0x4c, 0x52, 0x63, 0x65, 0x6e, 0x52, +0x71, 0x2f, 0x56, 0x79, 0x4d, 0x4f, 0x53, 0x78, 0x5a, 0x76, 0x38, 0x4a, 0x38, 0x30, 0x4f, 0x6a, +0x33, 0x6f, 0x74, 0x45, 0x6f, 0x58, 0x63, 0x4f, 0x77, 0x2b, 0x66, 0x31, 0x58, 0x65, 0x65, 0x58, +0x4e, 0x7a, 0x52, 0x53, 0x31, 0x62, 0x63, 0x6e, 0x57, 0x43, 0x70, 0x47, 0x69, 0x37, 0x71, 0x65, +0x71, 0x2f, 0x53, 0x62, 0x6c, 0x62, 0x39, 0x71, 0x6a, 0x55, 0x31, 0x34, 0x44, 0x41, 0x41, 0x41, +0x58, 0x54, 0x30, 0x6c, 0x45, 0x51, 0x56, 0x54, 0x58, 0x7a, 0x69, 0x79, 0x64, 0x38, 0x39, 0x4f, +0x49, 0x54, 0x31, 0x2f, 0x4e, 0x4e, 0x64, 0x4d, 0x76, 0x35, 0x49, 0x6f, 0x62, 0x37, 0x71, 0x4e, +0x79, 0x77, 0x78, 0x61, 0x66, 0x46, 0x64, 0x6e, 0x74, 0x38, 0x5a, 0x58, 0x77, 0x47, 0x5a, 0x47, +0x6c, 0x52, 0x41, 0x75, 0x4a, 0x6b, 0x75, 0x35, 0x2f, 0x78, 0x74, 0x65, 0x51, 0x38, 0x72, 0x70, +0x31, 0x34, 0x73, 0x59, 0x56, 0x4d, 0x39, 0x69, 0x32, 0x41, 0x4a, 0x38, 0x44, 0x51, 0x76, 0x6f, +0x78, 0x46, 0x36, 0x72, 0x68, 0x76, 0x52, 0x50, 0x43, 0x47, 0x6b, 0x6b, 0x34, 0x38, 0x30, 0x67, +0x4b, 0x4f, 0x68, 0x39, 0x42, 0x78, 0x66, 0x71, 0x66, 0x53, 0x51, 0x76, 0x75, 0x59, 0x74, 0x44, +0x68, 0x4a, 0x79, 0x4f, 0x4e, 0x70, 0x72, 0x53, 0x6b, 0x46, 0x48, 0x43, 0x73, 0x32, 0x67, 0x6c, +0x43, 0x56, 0x47, 0x73, 0x46, 0x68, 0x37, 0x55, 0x57, 0x44, 0x43, 0x6f, 0x51, 0x76, 0x46, 0x38, +0x73, 0x71, 0x52, 0x4b, 0x53, 0x66, 0x78, 0x77, 0x68, 0x43, 0x43, 0x4c, 0x5a, 0x4c, 0x55, 0x51, +0x53, 0x58, 0x4b, 0x65, 0x31, 0x30, 0x77, 0x42, 0x4f, 0x35, 0x44, 0x36, 0x47, 0x79, 0x46, 0x76, +0x6f, 0x4c, 0x33, 0x61, 0x68, 0x6c, 0x65, 0x61, 0x64, 0x43, 0x78, 0x78, 0x72, 0x38, 0x37, 0x6e, +0x43, 0x6e, 0x56, 0x32, 0x37, 0x44, 0x65, 0x57, 0x50, 0x4b, 0x6c, 0x35, 0x38, 0x55, 0x48, 0x47, +0x46, 0x48, 0x38, 0x35, 0x64, 0x6f, 0x41, 0x70, 0x59, 0x77, 0x6c, 0x31, 0x75, 0x41, 0x67, 0x67, +0x6d, 0x42, 0x46, 0x74, 0x4b, 0x70, 0x2f, 0x62, 0x66, 0x65, 0x53, 0x66, 0x32, 0x74, 0x74, 0x75, +0x77, 0x62, 0x56, 0x77, 0x75, 0x50, 0x66, 0x76, 0x4a, 0x4a, 0x32, 0x35, 0x43, 0x6d, 0x44, 0x32, +0x37, 0x47, 0x52, 0x53, 0x78, 0x57, 0x66, 0x30, 0x6d, 0x71, 0x75, 0x35, 0x76, 0x51, 0x52, 0x6d, +0x62, 0x31, 0x58, 0x2f, 0x30, 0x55, 0x5a, 0x63, 0x44, 0x49, 0x42, 0x78, 0x32, 0x65, 0x2f, 0x39, +0x45, 0x68, 0x70, 0x7a, 0x66, 0x57, 0x7a, 0x2f, 0x78, 0x76, 0x52, 0x64, 0x65, 0x77, 0x4d, 0x62, +0x6a, 0x50, 0x50, 0x6e, 0x41, 0x41, 0x31, 0x77, 0x35, 0x5a, 0x67, 0x78, 0x7a, 0x35, 0x73, 0x35, +0x6c, 0x39, 0x75, 0x7a, 0x5a, 0x58, 0x44, 0x4a, 0x71, 0x46, 0x4b, 0x38, 0x39, 0x38, 0x51, 0x54, +0x6b, 0x35, 0x73, 0x4b, 0x4b, 0x46, 0x52, 0x68, 0x6a, 0x43, 0x47, 0x59, 0x4d, 0x49, 0x6a, 0x2f, +0x4e, 0x38, 0x4d, 0x4b, 0x70, 0x76, 0x32, 0x66, 0x32, 0x2f, 0x35, 0x34, 0x48, 0x2b, 0x7a, 0x6b, +0x6f, 0x36, 0x71, 0x36, 0x54, 0x32, 0x6d, 0x4b, 0x36, 0x54, 0x74, 0x79, 0x76, 0x35, 0x2f, 0x2f, +0x75, 0x46, 0x4e, 0x44, 0x62, 0x46, 0x4a, 0x63, 0x2f, 0x49, 0x43, 0x6b, 0x72, 0x63, 0x2b, 0x6a, +0x44, 0x74, 0x76, 0x6d, 0x43, 0x57, 0x32, 0x34, 0x33, 0x74, 0x4f, 0x33, 0x58, 0x67, 0x62, 0x6e, +0x62, 0x6a, 0x2b, 0x53, 0x35, 0x37, 0x79, 0x39, 0x6a, 0x6d, 0x79, 0x68, 0x6f, 0x34, 0x4c, 0x37, +0x33, 0x33, 0x66, 0x6e, 0x34, 0x50, 0x74, 0x30, 0x67, 0x4b, 0x6d, 0x6e, 0x59, 0x32, 0x5a, 0x76, +0x52, 0x70, 0x2f, 0x45, 0x45, 0x34, 0x48, 0x76, 0x68, 0x46, 0x5a, 0x77, 0x78, 0x48, 0x49, 0x4a, +0x42, 0x35, 0x57, 0x43, 0x38, 0x2b, 0x31, 0x44, 0x66, 0x38, 0x7a, 0x51, 0x64, 0x32, 0x30, 0x48, +0x6f, 0x76, 0x4b, 0x75, 0x49, 0x33, 0x33, 0x67, 0x6a, 0x65, 0x75, 0x56, 0x4b, 0x37, 0x4b, 0x35, +0x64, 0x6d, 0x4a, 0x6f, 0x61, 0x62, 0x44, 0x53, 0x4b, 0x69, 0x55, 0x62, 0x64, 0x71, 0x75, 0x2b, +0x76, 0x2f, 0x45, 0x49, 0x70, 0x34, 0x6b, 0x6f, 0x68, 0x74, 0x53, 0x61, 0x75, 0x4e, 0x5a, 0x45, +0x4f, 0x48, 0x52, 0x69, 0x34, 0x65, 0x44, 0x45, 0x64, 0x44, 0x75, 0x75, 0x4b, 0x64, 0x38, 0x70, +0x35, 0x42, 0x44, 0x36, 0x65, 0x6a, 0x53, 0x30, 0x74, 0x68, 0x61, 0x6f, 0x71, 0x71, 0x4b, 0x31, +0x31, 0x52, 0x79, 0x79, 0x47, 0x72, 0x61, 0x39, 0x33, 0x64, 0x6f, 0x66, 0x55, 0x61, 0x79, 0x6b, +0x78, 0x59, 0x79, 0x36, 0x6e, 0x35, 0x64, 0x59, 0x4e, 0x2f, 0x44, 0x54, 0x31, 0x57, 0x6a, 0x71, +0x30, 0x4c, 0x55, 0x69, 0x47, 0x4d, 0x36, 0x64, 0x61, 0x2b, 0x6f, 0x31, 0x31, 0x69, 0x45, 0x79, +0x4c, 0x61, 0x62, 0x6a, 0x32, 0x56, 0x2f, 0x68, 0x51, 0x79, 0x47, 0x50, 0x52, 0x67, 0x63, 0x4d, +0x35, 0x39, 0x2b, 0x6e, 0x37, 0x79, 0x54, 0x39, 0x35, 0x4f, 0x38, 0x55, 0x56, 0x6d, 0x35, 0x4c, +0x49, 0x4f, 0x61, 0x47, 0x61, 0x51, 0x4e, 0x6d, 0x56, 0x52, 0x4a, 0x67, 0x6d, 0x55, 0x4f, 0x42, +0x38, 0x43, 0x79, 0x76, 0x63, 0x2b, 0x33, 0x64, 0x43, 0x6e, 0x2b, 0x4a, 0x69, 0x53, 0x79, 0x53, +0x45, 0x38, 0x55, 0x4a, 0x59, 0x49, 0x77, 0x67, 0x47, 0x57, 0x32, 0x45, 0x44, 0x6c, 0x71, 0x78, +0x42, 0x66, 0x66, 0x41, 0x43, 0x48, 0x6f, 0x46, 0x51, 0x69, 0x48, 0x51, 0x76, 0x37, 0x4d, 0x4b, +0x4a, 0x63, 0x64, 0x74, 0x47, 0x34, 0x54, 0x4d, 0x65, 0x4a, 0x39, 0x34, 0x7a, 0x56, 0x6e, 0x42, +0x61, 0x4a, 0x30, 0x6c, 0x55, 0x4f, 0x65, 0x46, 0x50, 0x2f, 0x44, 0x30, 0x42, 0x70, 0x56, 0x66, +0x57, 0x39, 0x64, 0x38, 0x6e, 0x4c, 0x43, 0x43, 0x6f, 0x44, 0x73, 0x44, 0x49, 0x34, 0x6e, 0x31, +0x6a, 0x64, 0x64, 0x59, 0x39, 0x4f, 0x41, 0x2f, 0x66, 0x43, 0x4e, 0x69, 0x4d, 0x46, 0x66, 0x62, +0x46, 0x46, 0x2f, 0x63, 0x4d, 0x52, 0x65, 0x7a, 0x57, 0x37, 0x64, 0x64, 0x5a, 0x59, 0x52, 0x50, +0x31, 0x39, 0x35, 0x56, 0x56, 0x31, 0x74, 0x72, 0x47, 0x39, 0x52, 0x63, 0x76, 0x64, 0x76, 0x58, +0x7a, 0x38, 0x36, 0x46, 0x6c, 0x79, 0x39, 0x2f, 0x50, 0x53, 0x74, 0x76, 0x30, 0x2f, 0x72, 0x4e, +0x6d, 0x51, 0x58, 0x59, 0x32, 0x7a, 0x30, 0x2b, 0x65, 0x7a, 0x4a, 0x30, 0x50, 0x50, 0x63, 0x54, +0x69, 0x78, 0x59, 0x76, 0x5a, 0x76, 0x6e, 0x30, 0x37, 0x6f, 0x79, 0x64, 0x4f, 0x5a, 0x50, 0x4b, +0x45, 0x43, 0x5a, 0x69, 0x78, 0x59, 0x7a, 0x6b, 0x6e, 0x4c, 0x59, 0x31, 0x72, 0x78, 0x31, 0x33, +0x6a, 0x65, 0x4f, 0x2b, 0x56, 0x52, 0x45, 0x76, 0x2f, 0x72, 0x4e, 0x78, 0x4d, 0x72, 0x35, 0x57, +0x6b, 0x55, 0x7a, 0x39, 0x42, 0x6c, 0x34, 0x4d, 0x6b, 0x32, 0x39, 0x64, 0x70, 0x56, 0x73, 0x31, +0x32, 0x76, 0x6e, 0x4b, 0x72, 0x4e, 0x44, 0x66, 0x4e, 0x2f, 0x4a, 0x62, 0x6f, 0x66, 0x6a, 0x37, +0x2f, 0x67, 0x4a, 0x35, 0x77, 0x39, 0x56, 0x57, 0x4b, 0x39, 0x50, 0x52, 0x43, 0x43, 0x67, 0x73, +0x6c, 0x78, 0x78, 0x32, 0x68, 0x47, 0x58, 0x46, 0x52, 0x46, 0x70, 0x46, 0x30, 0x7a, 0x65, 0x53, +0x56, 0x4e, 0x37, 0x4a, 0x69, 0x31, 0x34, 0x46, 0x6b, 0x5a, 0x6c, 0x71, 0x36, 0x70, 0x74, 0x6b, +0x39, 0x73, 0x73, 0x6f, 0x61, 0x41, 0x77, 0x47, 0x72, 0x67, 0x4d, 0x49, 0x55, 0x34, 0x64, 0x34, +0x44, 0x71, 0x32, 0x30, 0x53, 0x56, 0x64, 0x51, 0x41, 0x77, 0x7a, 0x45, 0x47, 0x54, 0x42, 0x6f, +0x45, 0x4a, 0x69, 0x72, 0x51, 0x68, 0x56, 0x69, 0x64, 0x30, 0x6e, 0x37, 0x74, 0x74, 0x31, 0x38, +0x72, 0x30, 0x48, 0x37, 0x37, 0x74, 0x51, 0x4c, 0x6a, 0x6b, 0x77, 0x35, 0x59, 0x6a, 0x58, 0x6b, +0x4e, 0x4e, 0x73, 0x7a, 0x37, 0x42, 0x34, 0x4d, 0x47, 0x44, 0x53, 0x4a, 0x77, 0x77, 0x51, 0x55, +0x2b, 0x41, 0x31, 0x46, 0x6a, 0x44, 0x53, 0x41, 0x5a, 0x4e, 0x47, 0x57, 0x4d, 0x34, 0x77, 0x32, +0x49, 0x78, 0x63, 0x46, 0x50, 0x4f, 0x46, 0x50, 0x38, 0x79, 0x43, 0x4f, 0x73, 0x76, 0x2b, 0x67, +0x61, 0x4f, 0x6e, 0x66, 0x75, 0x52, 0x63, 0x32, 0x67, 0x59, 0x38, 0x6b, 0x57, 0x4d, 0x56, 0x39, +0x41, 0x6d, 0x2b, 0x64, 0x68, 0x73, 0x4e, 0x61, 0x69, 0x6c, 0x43, 0x51, 0x57, 0x61, 0x77, 0x56, +0x73, 0x52, 0x57, 0x76, 0x44, 0x65, 0x55, 0x2f, 0x63, 0x52, 0x2f, 0x5a, 0x56, 0x79, 0x37, 0x68, +0x72, 0x31, 0x41, 0x43, 0x66, 0x44, 0x38, 0x48, 0x34, 0x39, 0x4e, 0x77, 0x4a, 0x52, 0x69, 0x6b, +0x66, 0x56, 0x75, 0x36, 0x44, 0x62, 0x72, 0x53, 0x66, 0x6b, 0x38, 0x39, 0x59, 0x74, 0x78, 0x58, +0x34, 0x65, 0x50, 0x52, 0x4d, 0x4f, 0x42, 0x6b, 0x48, 0x42, 0x63, 0x35, 0x4a, 0x67, 0x51, 0x49, +0x6e, 0x57, 0x4b, 0x78, 0x53, 0x6d, 0x62, 0x45, 0x54, 0x55, 0x47, 0x43, 0x74, 0x47, 0x35, 0x4b, +0x49, 0x34, 0x6c, 0x36, 0x4c, 0x74, 0x51, 0x71, 0x43, 0x72, 0x63, 0x45, 0x36, 0x76, 0x7a, 0x73, +0x42, 0x42, 0x54, 0x6f, 0x4f, 0x58, 0x6a, 0x71, 0x65, 0x46, 0x77, 0x43, 0x66, 0x5a, 0x69, 0x32, +0x6a, 0x56, 0x53, 0x75, 0x63, 0x6d, 0x53, 0x45, 0x56, 0x76, 0x4b, 0x57, 0x51, 0x30, 0x74, 0x4b, +0x75, 0x58, 0x51, 0x53, 0x6c, 0x4c, 0x49, 0x46, 0x41, 0x49, 0x5a, 0x41, 0x44, 0x53, 0x43, 0x37, +0x73, 0x4c, 0x6a, 0x46, 0x57, 0x34, 0x66, 0x6e, 0x39, 0x46, 0x77, 0x77, 0x6f, 0x75, 0x72, 0x66, +0x55, 0x53, 0x54, 0x67, 0x76, 0x61, 0x76, 0x2f, 0x6c, 0x7a, 0x36, 0x73, 0x44, 0x32, 0x78, 0x53, +0x64, 0x52, 0x70, 0x50, 0x50, 0x65, 0x7a, 0x6f, 0x53, 0x5a, 0x58, 0x39, 0x5a, 0x59, 0x66, 0x2b, +0x66, 0x31, 0x41, 0x2b, 0x48, 0x4d, 0x62, 0x4e, 0x6d, 0x55, 0x54, 0x52, 0x6b, 0x43, 0x4b, 0x6c, +0x6c, 0x37, 0x52, 0x64, 0x66, 0x63, 0x4f, 0x4f, 0x77, 0x59, 0x58, 0x73, 0x45, 0x76, 0x69, 0x61, +0x77, 0x58, 0x6d, 0x4f, 0x37, 0x77, 0x73, 0x46, 0x44, 0x34, 0x5a, 0x6b, 0x58, 0x34, 0x42, 0x32, +0x63, 0x43, 0x4b, 0x56, 0x32, 0x58, 0x39, 0x31, 0x2b, 0x74, 0x72, 0x39, 0x37, 0x79, 0x76, 0x58, +0x39, 0x39, 0x38, 0x4f, 0x49, 0x6b, 0x66, 0x44, 0x77, 0x43, 0x6e, 0x6a, 0x33, 0x78, 0x5a, 0x39, +0x41, 0x74, 0x65, 0x4b, 0x33, 0x57, 0x47, 0x58, 0x72, 0x58, 0x75, 0x33, 0x65, 0x43, 0x43, 0x6d, +0x57, 0x79, 0x48, 0x65, 0x58, 0x2f, 0x4a, 0x79, 0x34, 0x70, 0x76, 0x48, 0x66, 0x45, 0x6f, 0x31, +0x6f, 0x64, 0x39, 0x72, 0x2b, 0x74, 0x5a, 0x2b, 0x41, 0x35, 0x35, 0x4a, 0x6a, 0x30, 0x6a, 0x43, +0x31, 0x32, 0x4a, 0x54, 0x72, 0x57, 0x68, 0x78, 0x53, 0x75, 0x42, 0x61, 0x6f, 0x78, 0x49, 0x45, +0x61, 0x71, 0x32, 0x6a, 0x67, 0x6b, 0x42, 0x31, 0x7a, 0x31, 0x51, 0x69, 0x58, 0x56, 0x64, 0x66, +0x2f, 0x33, 0x51, 0x53, 0x51, 0x4e, 0x6e, 0x45, 0x64, 0x41, 0x32, 0x72, 0x38, 0x37, 0x39, 0x66, +0x6a, 0x70, 0x72, 0x4a, 0x59, 0x79, 0x76, 0x65, 0x47, 0x33, 0x66, 0x74, 0x43, 0x6b, 0x71, 0x62, +0x65, 0x47, 0x49, 0x4e, 0x52, 0x54, 0x74, 0x67, 0x4e, 0x79, 0x72, 0x2f, 0x47, 0x42, 0x7a, 0x57, +0x35, 0x4f, 0x37, 0x6a, 0x33, 0x34, 0x62, 0x5a, 0x75, 0x41, 0x65, 0x43, 0x45, 0x65, 0x77, 0x37, +0x66, 0x65, 0x2b, 0x63, 0x6e, 0x7a, 0x71, 0x6e, 0x41, 0x78, 0x43, 0x5a, 0x6c, 0x2f, 0x56, 0x64, +0x67, 0x59, 0x69, 0x6e, 0x76, 0x56, 0x7a, 0x56, 0x41, 0x73, 0x41, 0x32, 0x51, 0x66, 0x66, 0x44, +0x58, 0x47, 0x41, 0x71, 0x61, 0x6f, 0x51, 0x41, 0x54, 0x35, 0x5a, 0x42, 0x44, 0x74, 0x76, 0x73, +0x2f, 0x37, 0x68, 0x43, 0x42, 0x75, 0x78, 0x62, 0x63, 0x35, 0x67, 0x53, 0x37, 0x61, 0x66, 0x2f, +0x35, 0x35, 0x38, 0x34, 0x4a, 0x55, 0x4b, 0x4c, 0x2f, 0x45, 0x33, 0x58, 0x62, 0x39, 0x71, 0x2f, +0x2f, 0x76, 0x4b, 0x2b, 0x75, 0x48, 0x57, 0x38, 0x2f, 0x71, 0x2b, 0x2f, 0x48, 0x49, 0x36, 0x2f, +0x55, 0x63, 0x33, 0x76, 0x47, 0x66, 0x38, 0x68, 0x4e, 0x46, 0x34, 0x79, 0x76, 0x48, 0x4d, 0x45, +0x66, 0x57, 0x33, 0x37, 0x50, 0x57, 0x61, 0x65, 0x30, 0x34, 0x64, 0x7a, 0x70, 0x69, 0x61, 0x64, +0x50, 0x68, 0x55, 0x49, 0x32, 0x58, 0x46, 0x64, 0x58, 0x76, 0x39, 0x72, 0x73, 0x70, 0x65, 0x77, +0x4c, 0x46, 0x4c, 0x4e, 0x4c, 0x31, 0x36, 0x36, 0x4e, 0x36, 0x7a, 0x62, 0x39, 0x72, 0x64, 0x38, +0x34, 0x6a, 0x75, 0x38, 0x41, 0x62, 0x30, 0x36, 0x42, 0x51, 0x65, 0x66, 0x44, 0x4a, 0x4f, 0x43, +0x36, 0x66, 0x61, 0x77, 0x76, 0x66, 0x41, 0x68, 0x78, 0x30, 0x2f, 0x59, 0x62, 0x47, 0x57, 0x39, +0x67, 0x78, 0x6b, 0x31, 0x5a, 0x32, 0x65, 0x4a, 0x61, 0x45, 0x69, 0x4b, 0x51, 0x62, 0x48, 0x2f, +0x66, 0x76, 0x72, 0x4d, 0x42, 0x73, 0x50, 0x59, 0x47, 0x41, 0x4e, 0x37, 0x33, 0x50, 0x41, 0x7a, +0x51, 0x37, 0x64, 0x52, 0x54, 0x32, 0x66, 0x6a, 0x70, 0x70, 0x34, 0x30, 0x51, 0x34, 0x6b, 0x32, +0x50, 0x41, 0x44, 0x43, 0x4b, 0x6f, 0x2f, 0x66, 0x51, 0x34, 0x6c, 0x51, 0x41, 0x66, 0x59, 0x77, +0x34, 0x36, 0x2f, 0x66, 0x61, 0x2f, 0x70, 0x48, 0x58, 0x7a, 0x79, 0x51, 0x59, 0x39, 0x41, 0x6a, +0x34, 0x71, 0x34, 0x78, 0x54, 0x67, 0x5a, 0x73, 0x39, 0x6b, 0x74, 0x39, 0x47, 0x46, 0x37, 0x59, +0x61, 0x6c, 0x34, 0x5a, 0x6f, 0x58, 0x46, 0x4e, 0x66, 0x72, 0x2f, 0x6a, 0x36, 0x67, 0x37, 0x4f, +0x62, 0x33, 0x54, 0x33, 0x31, 0x76, 0x65, 0x33, 0x74, 0x48, 0x53, 0x62, 0x47, 0x59, 0x4d, 0x65, +0x36, 0x75, 0x70, 0x54, 0x4b, 0x62, 0x73, 0x51, 0x6d, 0x2b, 0x31, 0x38, 0x49, 0x54, 0x43, 0x41, +0x41, 0x51, 0x72, 0x6a, 0x33, 0x46, 0x51, 0x70, 0x68, 0x41, 0x67, 0x33, 0x76, 0x54, 0x68, 0x6c, +0x44, 0x35, 0x32, 0x6b, 0x48, 0x41, 0x34, 0x72, 0x54, 0x6a, 0x72, 0x71, 0x4f, 0x79, 0x61, 0x33, +0x4f, 0x6f, 0x2f, 0x30, 0x46, 0x6c, 0x35, 0x48, 0x35, 0x79, 0x79, 0x2b, 0x4e, 0x32, 0x76, 0x4e, +0x72, 0x52, 0x2f, 0x38, 0x50, 0x6a, 0x74, 0x70, 0x65, 0x33, 0x7a, 0x61, 0x7a, 0x78, 0x59, 0x41, +0x43, 0x52, 0x66, 0x6f, 0x2f, 0x6c, 0x72, 0x50, 0x72, 0x36, 0x52, 0x70, 0x4b, 0x2f, 0x76, 0x49, +0x55, 0x32, 0x34, 0x36, 0x39, 0x41, 0x58, 0x59, 0x57, 0x37, 0x2f, 0x6c, 0x46, 0x4e, 0x4a, 0x54, +0x64, 0x77, 0x65, 0x4a, 0x65, 0x37, 0x56, 0x50, 0x2f, 0x6f, 0x49, 0x31, 0x75, 0x65, 0x4d, 0x42, +0x55, 0x50, 0x50, 0x69, 0x65, 0x68, 0x7a, 0x38, 0x2f, 0x50, 0x66, 0x6b, 0x54, 0x66, 0x53, 0x2f, +0x6f, 0x43, 0x32, 0x65, 0x6b, 0x66, 0x50, 0x2f, 0x33, 0x31, 0x6f, 0x2b, 0x41, 0x66, 0x64, 0x33, +0x75, 0x4b, 0x66, 0x6e, 0x44, 0x2f, 0x37, 0x4d, 0x53, 0x47, 0x6a, 0x6b, 0x31, 0x6d, 0x7a, 0x6e, +0x76, 0x64, 0x65, 0x53, 0x61, 0x32, 0x7a, 0x6f, 0x53, 0x2f, 0x36, 0x55, 0x39, 0x58, 0x73, 0x31, +0x75, 0x7a, 0x69, 0x37, 0x73, 0x53, 0x45, 0x37, 0x72, 0x59, 0x58, 0x79, 0x30, 0x45, 0x6d, 0x34, +0x6f, 0x32, 0x49, 0x55, 0x55, 0x4f, 0x6b, 0x6e, 0x56, 0x35, 0x42, 0x68, 0x62, 0x48, 0x44, 0x50, +0x73, 0x6a, 0x42, 0x6c, 0x50, 0x41, 0x6f, 0x5a, 0x30, 0x62, 0x79, 0x62, 0x42, 0x74, 0x45, 0x50, +0x78, 0x41, 0x6d, 0x47, 0x73, 0x58, 0x49, 0x2b, 0x4e, 0x72, 0x79, 0x54, 0x51, 0x34, 0x6c, 0x5a, +0x45, 0x39, 0x56, 0x54, 0x77, 0x42, 0x4f, 0x47, 0x57, 0x56, 0x36, 0x46, 0x71, 0x33, 0x34, 0x52, +0x41, 0x52, 0x37, 0x78, 0x51, 0x61, 0x34, 0x79, 0x57, 0x79, 0x4c, 0x6f, 0x76, 0x32, 0x56, 0x48, +0x71, 0x6b, 0x33, 0x4c, 0x75, 0x42, 0x78, 0x52, 0x35, 0x31, 0x54, 0x62, 0x34, 0x76, 0x76, 0x5a, +0x75, 0x74, 0x71, 0x34, 0x4c, 0x4d, 0x66, 0x31, 0x46, 0x77, 0x53, 0x70, 0x74, 0x4f, 0x47, 0x67, +0x66, 0x6f, 0x63, 0x78, 0x74, 0x32, 0x37, 0x58, 0x46, 0x57, 0x71, 0x68, 0x62, 0x75, 0x34, 0x62, +0x6f, 0x6e, 0x4d, 0x2b, 0x70, 0x58, 0x62, 0x75, 0x46, 0x6c, 0x68, 0x65, 0x64, 0x52, 0x2f, 0x34, +0x68, 0x67, 0x37, 0x48, 0x57, 0x73, 0x76, 0x32, 0x4a, 0x52, 0x30, 0x6e, 0x76, 0x32, 0x5a, 0x64, +0x77, 0x58, 0x69, 0x76, 0x6f, 0x30, 0x4a, 0x48, 0x4d, 0x77, 0x67, 0x35, 0x59, 0x59, 0x79, 0x6a, +0x65, 0x73, 0x4d, 0x46, 0x76, 0x2f, 0x6e, 0x47, 0x75, 0x2f, 0x64, 0x5a, 0x79, 0x30, 0x4c, 0x68, +0x78, 0x4b, 0x4b, 0x33, 0x4a, 0x50, 0x66, 0x78, 0x77, 0x4d, 0x6e, 0x76, 0x31, 0x78, 0x41, 0x72, +0x6e, 0x58, 0x6a, 0x4d, 0x70, 0x39, 0x39, 0x58, 0x2b, 0x35, 0x38, 0x2f, 0x38, 0x2b, 0x39, 0x39, +0x39, 0x39, 0x78, 0x69, 0x36, 0x64, 0x69, 0x74, 0x67, 0x30, 0x4b, 0x44, 0x4f, 0x7a, 0x50, 0x72, +0x69, 0x4a, 0x77, 0x59, 0x4f, 0x4c, 0x47, 0x4c, 0x35, 0x38, 0x69, 0x32, 0x55, 0x62, 0x53, 0x35, +0x44, 0x4b, 0x30, 0x4e, 0x51, 0x7a, 0x64, 0x38, 0x37, 0x4b, 0x37, 0x47, 0x31, 0x62, 0x71, 0x6b, +0x4e, 0x65, 0x46, 0x54, 0x58, 0x43, 0x75, 0x71, 0x46, 0x6f, 0x6b, 0x31, 0x75, 0x4f, 0x72, 0x6b, +0x74, 0x30, 0x6f, 0x69, 0x45, 0x41, 0x6e, 0x67, 0x42, 0x5a, 0x79, 0x45, 0x75, 0x72, 0x34, 0x68, +0x53, 0x56, 0x68, 0x46, 0x44, 0x61, 0x55, 0x74, 0x47, 0x65, 0x6f, 0x6a, 0x36, 0x65, 0x6b, 0x56, +0x39, 0x33, 0x47, 0x45, 0x52, 0x4d, 0x69, 0x62, 0x36, 0x37, 0x39, 0x38, 0x61, 0x50, 0x31, 0x4b, +0x6d, 0x34, 0x66, 0x30, 0x6c, 0x50, 0x53, 0x7a, 0x4b, 0x64, 0x78, 0x50, 0x37, 0x64, 0x47, 0x4a, +0x57, 0x53, 0x55, 0x70, 0x65, 0x64, 0x65, 0x33, 0x50, 0x7a, 0x4d, 0x78, 0x30, 0x39, 0x55, 0x74, +0x4c, 0x59, 0x65, 0x6c, 0x53, 0x79, 0x4d, 0x72, 0x43, 0x65, 0x68, 0x36, 0x6b, 0x70, 0x54, 0x6d, +0x69, 0x54, 0x62, 0x39, 0x76, 0x62, 0x56, 0x55, 0x56, 0x39, 0x74, 0x68, 0x6a, 0x73, 0x5a, 0x6d, +0x4f, 0x33, 0x61, 0x6d, 0x6b, 0x70, 0x49, 0x54, 0x37, 0x6a, 0x39, 0x75, 0x46, 0x43, 0x44, 0x38, +0x4a, 0x52, 0x76, 0x46, 0x35, 0x32, 0x6b, 0x62, 0x4f, 0x2b, 0x57, 0x59, 0x75, 0x6b, 0x53, 0x2f, +0x6e, 0x45, 0x31, 0x71, 0x77, 0x30, 0x47, 0x31, 0x44, 0x66, 0x71, 0x50, 0x2f, 0x4d, 0x76, 0x76, +0x6c, 0x74, 0x42, 0x2b, 0x77, 0x6f, 0x5a, 0x7a, 0x59, 0x4e, 0x53, 0x73, 0x6f, 0x2f, 0x77, 0x58, +0x53, 0x48, 0x33, 0x73, 0x51, 0x4d, 0x2f, 0x42, 0x43, 0x32, 0x4c, 0x77, 0x46, 0x67, 0x72, 0x38, +0x35, 0x2f, 0x72, 0x4d, 0x42, 0x6e, 0x6a, 0x6a, 0x31, 0x69, 0x57, 0x54, 0x2f, 0x61, 0x61, 0x74, +0x39, 0x33, 0x6b, 0x6e, 0x6a, 0x56, 0x47, 0x31, 0x66, 0x33, 0x57, 0x39, 0x58, 0x56, 0x63, 0x30, +0x66, 0x61, 0x71, 0x76, 0x38, 0x55, 0x48, 0x64, 0x46, 0x6c, 0x6c, 0x44, 0x30, 0x6e, 0x54, 0x79, +0x64, 0x54, 0x71, 0x30, 0x36, 0x6f, 0x52, 0x59, 0x6f, 0x6e, 0x76, 0x33, 0x30, 0x72, 0x78, 0x51, +0x64, 0x4a, 0x4e, 0x48, 0x57, 0x59, 0x4b, 0x7a, 0x32, 0x44, 0x34, 0x57, 0x78, 0x4c, 0x76, 0x78, +0x57, 0x47, 0x34, 0x6d, 0x32, 0x2f, 0x74, 0x6d, 0x50, 0x6b, 0x4c, 0x78, 0x74, 0x37, 0x6f, 0x7a, +0x2f, 0x56, 0x6d, 0x37, 0x2f, 0x5a, 0x79, 0x58, 0x30, 0x66, 0x6f, 0x76, 0x4a, 0x70, 0x4b, 0x2f, +0x4e, 0x49, 0x72, 0x7a, 0x38, 0x43, 0x39, 0x4b, 0x72, 0x61, 0x74, 0x42, 0x31, 0x39, 0x55, 0x54, +0x79, 0x57, 0x78, 0x49, 0x56, 0x41, 0x59, 0x36, 0x76, 0x69, 0x2f, 0x50, 0x6c, 0x68, 0x71, 0x4f, +0x70, 0x69, 0x6f, 0x66, 0x39, 0x6d, 0x47, 0x4c, 0x48, 0x44, 0x4b, 0x74, 0x69, 0x6c, 0x6f, 0x34, +0x64, 0x73, 0x30, 0x6d, 0x77, 0x38, 0x6b, 0x6f, 0x6a, 0x71, 0x4b, 0x31, 0x38, 0x44, 0x47, 0x77, +0x72, 0x30, 0x74, 0x4c, 0x61, 0x45, 0x41, 0x67, 0x57, 0x6b, 0x45, 0x59, 0x55, 0x61, 0x58, 0x34, +0x6b, 0x47, 0x46, 0x79, 0x4e, 0x4d, 0x5a, 0x64, 0x67, 0x30, 0x34, 0x35, 0x48, 0x56, 0x44, 0x32, +0x4d, 0x69, 0x4a, 0x56, 0x53, 0x4a, 0x33, 0x61, 0x68, 0x51, 0x2b, 0x33, 0x59, 0x58, 0x70, 0x46, +0x50, 0x4c, 0x36, 0x41, 0x5a, 0x46, 0x46, 0x6e, 0x36, 0x72, 0x4c, 0x79, 0x39, 0x66, 0x57, 0x50, +0x4b, 0x73, 0x68, 0x52, 0x45, 0x34, 0x52, 0x36, 0x67, 0x78, 0x4b, 0x75, 0x4c, 0x4c, 0x62, 0x74, +0x32, 0x62, 0x75, 0x54, 0x38, 0x69, 0x77, 0x50, 0x38, 0x38, 0x32, 0x38, 0x78, 0x64, 0x6b, 0x76, +0x4a, 0x30, 0x51, 0x6c, 0x73, 0x51, 0x4e, 0x49, 0x41, 0x73, 0x76, 0x66, 0x36, 0x48, 0x68, 0x36, +0x6c, 0x58, 0x33, 0x36, 0x47, 0x4b, 0x69, 0x2b, 0x6a, 0x59, 0x76, 0x6c, 0x79, 0x63, 0x69, 0x72, +0x71, 0x43, 0x65, 0x37, 0x63, 0x69, 0x62, 0x57, 0x57, 0x58, 0x79, 0x34, 0x2b, 0x41, 0x33, 0x62, +0x46, 0x71, 0x42, 0x53, 0x66, 0x6f, 0x71, 0x53, 0x67, 0x33, 0x35, 0x77, 0x35, 0x62, 0x4c, 0x7a, +0x70, 0x7a, 0x2b, 0x52, 0x66, 0x65, 0x79, 0x73, 0x71, 0x6e, 0x4a, 0x35, 0x38, 0x6b, 0x51, 0x6b, +0x66, 0x63, 0x6e, 0x54, 0x7a, 0x5a, 0x70, 0x53, 0x55, 0x5a, 0x50, 0x58, 0x6f, 0x51, 0x57, 0x7a, +0x44, 0x52, 0x72, 0x51, 0x50, 0x66, 0x48, 0x47, 0x57, 0x5a, 0x4a, 0x45, 0x30, 0x59, 0x71, 0x55, +0x58, 0x46, 0x61, 0x56, 0x30, 0x67, 0x36, 0x56, 0x7a, 0x70, 0x33, 0x79, 0x65, 0x66, 0x57, 0x59, +0x65, 0x51, 0x6d, 0x68, 0x79, 0x63, 0x7a, 0x4e, 0x5a, 0x75, 0x48, 0x41, 0x64, 0x45, 0x52, 0x6c, +0x48, 0x53, 0x6f, 0x32, 0x52, 0x36, 0x2f, 0x66, 0x61, 0x66, 0x71, 0x30, 0x74, 0x43, 0x6b, 0x74, +0x4e, 0x6e, 0x61, 0x42, 0x50, 0x6c, 0x78, 0x5a, 0x6b, 0x70, 0x49, 0x64, 0x49, 0x69, 0x77, 0x54, +0x49, 0x7a, 0x34, 0x31, 0x51, 0x58, 0x42, 0x4c, 0x47, 0x45, 0x71, 0x52, 0x33, 0x52, 0x30, 0x6e, +0x62, 0x56, 0x75, 0x6c, 0x55, 0x31, 0x30, 0x70, 0x32, 0x56, 0x63, 0x64, 0x59, 0x38, 0x73, 0x4e, +0x4f, 0x77, 0x69, 0x45, 0x50, 0x6f, 0x30, 0x58, 0x79, 0x2f, 0x6d, 0x61, 0x48, 0x65, 0x2f, 0x39, +0x57, 0x61, 0x35, 0x2f, 0x5a, 0x52, 0x2f, 0x74, 0x43, 0x37, 0x37, 0x38, 0x2f, 0x48, 0x39, 0x74, +0x68, 0x2f, 0x46, 0x78, 0x7a, 0x67, 0x51, 0x35, 0x4e, 0x6f, 0x4f, 0x44, 0x57, 0x51, 0x6b, 0x45, +0x42, 0x6e, 0x48, 0x53, 0x53, 0x30, 0x35, 0x51, 0x39, 0x73, 0x4a, 0x36, 0x48, 0x31, 0x51, 0x59, +0x62, 0x44, 0x4c, 0x69, 0x7a, 0x45, 0x4e, 0x68, 0x49, 0x78, 0x45, 0x33, 0x30, 0x50, 0x68, 0x52, +0x32, 0x34, 0x4d, 0x39, 0x77, 0x32, 0x49, 0x55, 0x31, 0x6a, 0x46, 0x39, 0x57, 0x79, 0x36, 0x5a, +0x4e, 0x70, 0x53, 0x77, 0x70, 0x57, 0x63, 0x57, 0x34, 0x34, 0x2f, 0x39, 0x4d, 0x7a, 0x2f, 0x70, +0x61, 0x51, 0x67, 0x75, 0x58, 0x59, 0x6a, 0x63, 0x57, 0x2f, 0x32, 0x72, 0x2f, 0x39, 0x66, 0x39, +0x77, 0x62, 0x57, 0x33, 0x56, 0x30, 0x35, 0x75, 0x79, 0x36, 0x77, 0x65, 0x63, 0x54, 0x65, 0x6a, +0x6c, 0x66, 0x37, 0x4d, 0x34, 0x70, 0x77, 0x43, 0x7a, 0x41, 0x53, 0x6a, 0x4b, 0x41, 0x36, 0x38, +0x5a, 0x46, 0x56, 0x54, 0x54, 0x55, 0x6b, 0x75, 0x78, 0x6d, 0x77, 0x54, 0x4b, 0x36, 0x73, 0x71, +0x63, 0x38, 0x42, 0x76, 0x6a, 0x5a, 0x37, 0x42, 0x4b, 0x5a, 0x4e, 0x4e, 0x78, 0x4e, 0x6f, 0x45, +0x66, 0x51, 0x35, 0x5a, 0x35, 0x6d, 0x54, 0x45, 0x65, 0x4b, 0x64, 0x35, 0x4d, 0x57, 0x41, 0x6d, +0x6d, 0x39, 0x42, 0x70, 0x41, 0x5a, 0x58, 0x73, 0x67, 0x41, 0x45, 0x45, 0x44, 0x31, 0x35, 0x34, +0x36, 0x6e, 0x69, 0x2b, 0x2f, 0x75, 0x4a, 0x5a, 0x68, 0x77, 0x36, 0x4a, 0x59, 0x37, 0x2f, 0x64, +0x42, 0x63, 0x63, 0x39, 0x76, 0x75, 0x77, 0x2b, 0x53, 0x2b, 0x6e, 0x2b, 0x70, 0x68, 0x4e, 0x34, +0x50, 0x48, 0x4d, 0x55, 0x56, 0x6e, 0x58, 0x71, 0x54, 0x57, 0x5a, 0x31, 0x4f, 0x62, 0x57, 0x77, +0x54, 0x67, 0x52, 0x62, 0x35, 0x52, 0x4c, 0x71, 0x32, 0x70, 0x33, 0x54, 0x64, 0x4c, 0x6c, 0x62, +0x48, 0x4d, 0x71, 0x6b, 0x58, 0x49, 0x49, 0x53, 0x6c, 0x35, 0x31, 0x6b, 0x66, 0x55, 0x78, 0x74, +0x50, 0x77, 0x7a, 0x4d, 0x61, 0x59, 0x79, 0x75, 0x6f, 0x6d, 0x76, 0x64, 0x48, 0x45, 0x72, 0x48, +0x6b, 0x6d, 0x53, 0x30, 0x75, 0x78, 0x73, 0x59, 0x33, 0x55, 0x78, 0x64, 0x66, 0x67, 0x7a, 0x56, +0x72, 0x79, 0x59, 0x67, 0x45, 0x6d, 0x50, 0x7a, 0x58, 0x34, 0x34, 0x6a, 0x6b, 0x2f, 0x49, 0x46, +0x6f, 0x39, 0x43, 0x69, 0x71, 0x53, 0x6e, 0x64, 0x79, 0x39, 0x66, 0x57, 0x76, 0x6b, 0x4a, 0x65, +0x2f, 0x67, 0x43, 0x32, 0x56, 0x67, 0x74, 0x59, 0x5a, 0x4c, 0x55, 0x6e, 0x4c, 0x76, 0x4a, 0x32, +0x43, 0x67, 0x6b, 0x7a, 0x67, 0x6e, 0x34, 0x32, 0x68, 0x79, 0x41, 0x6e, 0x68, 0x46, 0x77, 0x4a, +0x37, 0x73, 0x73, 0x4c, 0x6d, 0x53, 0x4f, 0x7a, 0x43, 0x58, 0x34, 0x63, 0x43, 0x47, 0x32, 0x31, +0x5a, 0x2b, 0x72, 0x31, 0x47, 0x43, 0x4d, 0x47, 0x6f, 0x73, 0x52, 0x36, 0x54, 0x2f, 0x36, 0x71, +0x70, 0x6c, 0x6f, 0x4a, 0x54, 0x70, 0x50, 0x70, 0x64, 0x55, 0x47, 0x53, 0x74, 0x6e, 0x55, 0x75, +0x73, 0x77, 0x30, 0x56, 0x2f, 0x4a, 0x4e, 0x79, 0x6a, 0x4e, 0x32, 0x56, 0x2f, 0x65, 0x34, 0x53, +0x4f, 0x78, 0x35, 0x39, 0x49, 0x35, 0x61, 0x63, 0x66, 0x45, 0x4e, 0x38, 0x5a, 0x49, 0x36, 0x31, +0x64, 0x4e, 0x70, 0x6e, 0x46, 0x4a, 0x62, 0x52, 0x36, 0x2f, 0x58, 0x57, 0x71, 0x46, 0x73, 0x79, +0x6e, 0x66, 0x4e, 0x58, 0x33, 0x74, 0x43, 0x31, 0x6f, 0x6a, 0x61, 0x6c, 0x30, 0x6b, 0x5a, 0x41, +0x70, 0x57, 0x7a, 0x70, 0x6e, 0x6f, 0x64, 0x5a, 0x2b, 0x51, 0x4a, 0x46, 0x30, 0x38, 0x4e, 0x46, +0x41, 0x54, 0x6a, 0x62, 0x64, 0x4a, 0x6b, 0x77, 0x67, 0x6f, 0x31, 0x38, 0x2f, 0x59, 0x70, 0x73, +0x32, 0x38, 0x66, 0x50, 0x56, 0x56, 0x32, 0x47, 0x6b, 0x54, 0x48, 0x44, 0x43, 0x59, 0x67, 0x78, +0x38, 0x39, 0x64, 0x55, 0x76, 0x56, 0x46, 0x66, 0x48, 0x4f, 0x50, 0x76, 0x73, 0x41, 0x53, 0x78, +0x63, 0x57, 0x49, 0x77, 0x51, 0x7a, 0x73, 0x30, 0x6e, 0x68, 0x66, 0x6e, 0x56, 0x39, 0x69, 0x74, +0x74, 0x4d, 0x4d, 0x59, 0x6a, 0x47, 0x6c, 0x4d, 0x59, 0x43, 0x35, 0x46, 0x77, 0x6b, 0x48, 0x6e, +0x4c, 0x64, 0x72, 0x43, 0x74, 0x4f, 0x6f, 0x73, 0x6a, 0x4f, 0x71, 0x78, 0x44, 0x57, 0x6f, 0x38, +0x50, 0x35, 0x76, 0x57, 0x67, 0x4b, 0x4c, 0x65, 0x65, 0x49, 0x77, 0x61, 0x30, 0x49, 0x75, 0x42, +0x35, 0x31, 0x45, 0x59, 0x6c, 0x75, 0x5a, 0x6b, 0x65, 0x56, 0x73, 0x66, 0x4a, 0x2f, 0x66, 0x76, +0x66, 0x73, 0x55, 0x4f, 0x47, 0x4f, 0x4b, 0x75, 0x37, 0x74, 0x51, 0x36, 0x57, 0x62, 0x52, 0x77, +0x2f, 0x76, 0x69, 0x4d, 0x4f, 0x4d, 0x63, 0x34, 0x6f, 0x70, 0x33, 0x30, 0x65, 0x41, 0x65, 0x55, +0x48, 0x62, 0x57, 0x56, 0x6e, 0x30, 0x36, 0x72, 0x65, 0x34, 0x63, 0x67, 0x63, 0x67, 0x73, 0x35, +0x53, 0x58, 0x56, 0x75, 0x4c, 0x41, 0x6e, 0x4b, 0x79, 0x73, 0x6c, 0x69, 0x32, 0x62, 0x44, 0x74, +0x56, 0x6c, 0x51, 0x4a, 0x6a, 0x4c, 0x63, 0x47, 0x41, 0x59, 0x73, 0x69, 0x78, 0x6e, 0x64, 0x6b, +0x74, 0x42, 0x4b, 0x61, 0x32, 0x6c, 0x74, 0x7a, 0x63, 0x58, 0x41, 0x4c, 0x2b, 0x56, 0x75, 0x44, +0x30, 0x71, 0x32, 0x46, 0x78, 0x72, 0x79, 0x67, 0x50, 0x39, 0x74, 0x76, 0x46, 0x41, 0x7a, 0x39, +0x6c, 0x73, 0x69, 0x4f, 0x71, 0x75, 0x58, 0x66, 0x78, 0x5a, 0x47, 0x34, 0x2f, 0x36, 0x54, 0x70, +0x36, 0x6a, 0x44, 0x69, 0x4a, 0x56, 0x73, 0x58, 0x62, 0x6e, 0x55, 0x76, 0x59, 0x47, 0x4a, 0x2f, +0x48, 0x77, 0x4f, 0x66, 0x75, 0x7a, 0x38, 0x6a, 0x45, 0x64, 0x4f, 0x6e, 0x47, 0x31, 0x36, 0x4f, +0x66, 0x6f, 0x76, 0x43, 0x49, 0x76, 0x73, 0x52, 0x4f, 0x76, 0x4a, 0x6a, 0x31, 0x30, 0x31, 0x66, +0x41, 0x37, 0x6c, 0x2f, 0x77, 0x51, 0x68, 0x35, 0x4e, 0x69, 0x57, 0x44, 0x33, 0x57, 0x76, 0x49, +0x63, 0x46, 0x4e, 0x36, 0x74, 0x39, 0x73, 0x59, 0x6e, 0x79, 0x31, 0x41, 0x4f, 0x6d, 0x65, 0x6b, +0x62, 0x2f, 0x61, 0x53, 0x52, 0x68, 0x49, 0x58, 0x6a, 0x30, 0x62, 0x75, 0x70, 0x73, 0x44, 0x56, +0x4b, 0x4b, 0x39, 0x70, 0x35, 0x4a, 0x44, 0x67, 0x39, 0x73, 0x63, 0x47, 0x48, 0x71, 0x5a, 0x75, +0x65, 0x7a, 0x59, 0x6b, 0x58, 0x50, 0x4d, 0x76, 0x72, 0x64, 0x31, 0x2f, 0x42, 0x55, 0x42, 0x4d, +0x6a, 0x34, 0x49, 0x6c, 0x6b, 0x2f, 0x67, 0x43, 0x72, 0x42, 0x46, 0x59, 0x4a, 0x6a, 0x48, 0x4a, +0x6a, 0x30, 0x53, 0x68, 0x4a, 0x71, 0x4b, 0x33, 0x6b, 0x70, 0x38, 0x64, 0x68, 0x2b, 0x47, 0x39, +0x48, 0x72, 0x76, 0x39, 0x66, 0x4c, 0x61, 0x47, 0x74, 0x78, 0x34, 0x30, 0x6b, 0x6d, 0x4a, 0x66, +0x4c, 0x6d, 0x7a, 0x38, 0x45, 0x36, 0x4f, 0x46, 0x70, 0x30, 0x72, 0x56, 0x69, 0x5a, 0x66, 0x77, +0x59, 0x54, 0x75, 0x69, 0x2f, 0x6e, 0x70, 0x32, 0x4c, 0x64, 0x78, 0x4e, 0x56, 0x6e, 0x6b, 0x4d, +0x50, 0x36, 0x54, 0x68, 0x39, 0x75, 0x37, 0x62, 0x67, 0x6f, 0x49, 0x34, 0x48, 0x38, 0x73, 0x71, +0x58, 0x37, 0x79, 0x47, 0x6c, 0x43, 0x39, 0x56, 0x38, 0x2b, 0x4f, 0x47, 0x4e, 0x2f, 0x50, 0x57, +0x76, 0x42, 0x37, 0x4a, 0x70, 0x32, 0x78, 0x47, 0x30, 0x61, 0x68, 0x31, 0x48, 0x78, 0x4e, 0x61, +0x52, 0x46, 0x74, 0x68, 0x4e, 0x52, 0x57, 0x6b, 0x35, 0x35, 0x64, 0x39, 0x31, 0x51, 0x73, 0x51, +0x37, 0x6f, 0x55, 0x53, 0x55, 0x69, 0x4a, 0x31, 0x4c, 0x66, 0x62, 0x30, 0x67, 0x4c, 0x2b, 0x74, +0x77, 0x4d, 0x72, 0x4a, 0x50, 0x59, 0x4e, 0x34, 0x33, 0x72, 0x63, 0x6e, 0x4c, 0x32, 0x34, 0x57, +0x68, 0x43, 0x52, 0x52, 0x5a, 0x4b, 0x2b, 0x79, 0x44, 0x45, 0x6c, 0x73, 0x76, 0x73, 0x51, 0x50, +0x38, 0x6d, 0x58, 0x4f, 0x69, 0x77, 0x4f, 0x59, 0x4a, 0x37, 0x4a, 0x2f, 0x33, 0x44, 0x4b, 0x57, +0x39, 0x35, 0x48, 0x52, 0x4e, 0x32, 0x35, 0x61, 0x4b, 0x69, 0x69, 0x72, 0x46, 0x74, 0x50, 0x63, +0x55, 0x74, 0x39, 0x77, 0x4e, 0x56, 0x39, 0x38, 0x6a, 0x65, 0x63, 0x4a, 0x6e, 0x52, 0x46, 0x46, +0x61, 0x2b, 0x4b, 0x36, 0x64, 0x42, 0x44, 0x47, 0x6c, 0x70, 0x4c, 0x4f, 0x57, 0x66, 0x41, 0x6e, +0x73, 0x41, 0x41, 0x4b, 0x42, 0x49, 0x48, 0x72, 0x61, 0x79, 0x39, 0x69, 0x68, 0x77, 0x7a, 0x47, +0x7a, 0x5a, 0x6c, 0x49, 0x68, 0x42, 0x4c, 0x55, 0x2f, 0x2f, 0x30, 0x44, 0x39, 0x74, 0x79, 0x73, +0x49, 0x47, 0x6b, 0x46, 0x34, 0x53, 0x77, 0x6c, 0x6d, 0x36, 0x44, 0x46, 0x34, 0x68, 0x65, 0x33, +0x5a, 0x64, 0x75, 0x61, 0x70, 0x48, 0x48, 0x4c, 0x52, 0x48, 0x58, 0x69, 0x74, 0x32, 0x32, 0x4a, +0x32, 0x56, 0x51, 0x4c, 0x47, 0x4a, 0x33, 0x66, 0x77, 0x61, 0x63, 0x4b, 0x6b, 0x49, 0x68, 0x42, +0x79, 0x62, 0x4d, 0x49, 0x36, 0x46, 0x6b, 0x4d, 0x4a, 0x53, 0x63, 0x2f, 0x78, 0x34, 0x31, 0x6b, +0x33, 0x64, 0x69, 0x77, 0x64, 0x62, 0x72, 0x36, 0x5a, 0x7a, 0x59, 0x38, 0x2b, 0x53, 0x73, 0x63, +0x78, 0x59, 0x39, 0x67, 0x36, 0x5a, 0x59, 0x6f, 0x2f, 0x41, 0x52, 0x6d, 0x30, 0x44, 0x72, 0x42, +0x35, 0x63, 0x7a, 0x6b, 0x58, 0x2f, 0x50, 0x46, 0x49, 0x64, 0x6c, 0x58, 0x55, 0x73, 0x32, 0x5a, +0x4e, 0x47, 0x56, 0x4a, 0x36, 0x65, 0x46, 0x49, 0x68, 0x68, 0x66, 0x35, 0x56, 0x4b, 0x48, 0x48, +0x43, 0x35, 0x35, 0x32, 0x52, 0x48, 0x75, 0x4b, 0x62, 0x37, 0x38, 0x71, 0x6f, 0x69, 0x77, 0x6d, +0x32, 0x52, 0x39, 0x73, 0x53, 0x43, 0x53, 0x70, 0x75, 0x50, 0x2b, 0x46, 0x54, 0x44, 0x75, 0x76, +0x30, 0x4d, 0x58, 0x39, 0x36, 0x66, 0x54, 0x4c, 0x54, 0x6c, 0x78, 0x33, 0x4b, 0x7a, 0x7a, 0x75, +0x32, 0x6b, 0x52, 0x65, 0x4f, 0x55, 0x35, 0x41, 0x64, 0x52, 0x4d, 0x67, 0x59, 0x47, 0x45, 0x6e, +0x39, 0x64, 0x64, 0x63, 0x6c, 0x61, 0x62, 0x48, 0x33, 0x42, 0x51, 0x71, 0x4c, 0x35, 0x31, 0x48, +0x56, 0x6f, 0x77, 0x63, 0x74, 0x2f, 0x44, 0x34, 0x6f, 0x33, 0x72, 0x43, 0x42, 0x71, 0x6f, 0x6f, +0x4b, 0x50, 0x43, 0x77, 0x39, 0x65, 0x76, 0x66, 0x68, 0x78, 0x52, 0x66, 0x57, 0x55, 0x31, 0x6f, +0x61, 0x67, 0x34, 0x42, 0x46, 0x78, 0x52, 0x53, 0x48, 0x44, 0x57, 0x72, 0x4c, 0x6d, 0x6c, 0x55, +0x72, 0x6b, 0x64, 0x4b, 0x51, 0x33, 0x62, 0x49, 0x46, 0x42, 0x78, 0x30, 0x30, 0x77, 0x48, 0x65, +0x44, 0x77, 0x62, 0x73, 0x66, 0x78, 0x2b, 0x69, 0x2f, 0x76, 0x70, 0x34, 0x37, 0x6a, 0x71, 0x33, +0x6e, 0x38, 0x59, 0x30, 0x5a, 0x62, 0x43, 0x50, 0x4d, 0x58, 0x35, 0x64, 0x4e, 0x51, 0x56, 0x74, +0x49, 0x44, 0x36, 0x61, 0x6a, 0x6a, 0x52, 0x4d, 0x2b, 0x6d, 0x55, 0x6a, 0x69, 0x61, 0x52, 0x55, +0x64, 0x54, 0x56, 0x76, 0x65, 0x58, 0x2f, 0x63, 0x55, 0x41, 0x42, 0x57, 0x4c, 0x31, 0x73, 0x47, +0x69, 0x43, 0x35, 0x4c, 0x6a, 0x59, 0x56, 0x39, 0x6b, 0x53, 0x6f, 0x39, 0x33, 0x55, 0x47, 0x78, +0x74, 0x47, 0x34, 0x67, 0x79, 0x6b, 0x6f, 0x64, 0x75, 0x49, 0x44, 0x6a, 0x35, 0x2b, 0x7a, 0x39, +0x57, 0x6b, 0x31, 0x6b, 0x64, 0x59, 0x36, 0x67, 0x51, 0x37, 0x44, 0x53, 0x53, 0x6c, 0x36, 0x2f, +0x74, 0x7a, 0x59, 0x51, 0x46, 0x73, 0x50, 0x75, 0x4a, 0x75, 0x77, 0x69, 0x63, 0x32, 0x59, 0x57, +0x63, 0x43, 0x78, 0x64, 0x52, 0x39, 0x65, 0x38, 0x4b, 0x54, 0x75, 0x33, 0x59, 0x6b, 0x66, 0x63, +0x57, 0x72, 0x36, 0x64, 0x6e, 0x74, 0x4d, 0x37, 0x46, 0x44, 0x30, 0x67, 0x6e, 0x39, 0x46, 0x6f, +0x4b, 0x48, 0x30, 0x66, 0x67, 0x6b, 0x4a, 0x52, 0x5a, 0x74, 0x5a, 0x4c, 0x58, 0x67, 0x65, 0x48, +0x37, 0x4a, 0x71, 0x2f, 0x2f, 0x38, 0x78, 0x49, 0x53, 0x53, 0x78, 0x62, 0x79, 0x5a, 0x73, 0x39, +0x54, 0x57, 0x50, 0x79, 0x4c, 0x78, 0x34, 0x37, 0x73, 0x62, 0x41, 0x4a, 0x61, 0x73, 0x48, 0x44, +0x52, 0x4c, 0x33, 0x78, 0x62, 0x6c, 0x4d, 0x6d, 0x41, 0x6c, 0x71, 0x42, 0x69, 0x39, 0x51, 0x69, +0x52, 0x54, 0x6b, 0x78, 0x4b, 0x75, 0x72, 0x59, 0x62, 0x67, 0x50, 0x58, 0x43, 0x78, 0x4b, 0x58, +0x79, 0x57, 0x55, 0x30, 0x46, 0x41, 0x57, 0x42, 0x44, 0x63, 0x54, 0x31, 0x62, 0x53, 0x77, 0x2b, +0x6b, 0x7a, 0x30, 0x48, 0x4f, 0x79, 0x6c, 0x36, 0x2f, 0x61, 0x7a, 0x51, 0x54, 0x4a, 0x76, 0x64, +0x6d, 0x36, 0x39, 0x33, 0x33, 0x6b, 0x7a, 0x66, 0x79, 0x4d, 0x73, 0x6f, 0x66, 0x2f, 0x77, 0x65, +0x52, 0x73, 0x4b, 0x49, 0x73, 0x65, 0x69, 0x65, 0x4c, 0x46, 0x68, 0x37, 0x47, 0x43, 0x53, 0x66, +0x6b, 0x6f, 0x57, 0x52, 0x39, 0x67, 0x7a, 0x55, 0x30, 0x46, 0x59, 0x6f, 0x73, 0x46, 0x58, 0x61, +0x43, 0x78, 0x4c, 0x36, 0x65, 0x34, 0x6e, 0x38, 0x2b, 0x54, 0x47, 0x42, 0x50, 0x6b, 0x39, 0x6a, +0x64, 0x65, 0x34, 0x59, 0x53, 0x78, 0x32, 0x4b, 0x61, 0x68, 0x39, 0x2b, 0x55, 0x33, 0x48, 0x47, +0x56, 0x59, 0x73, 0x46, 0x79, 0x52, 0x53, 0x77, 0x6d, 0x65, 0x65, 0x6b, 0x68, 0x68, 0x5a, 0x61, +0x65, 0x37, 0x36, 0x66, 0x31, 0x4d, 0x43, 0x61, 0x41, 0x4d, 0x52, 0x37, 0x57, 0x42, 0x44, 0x46, +0x61, 0x45, 0x38, 0x34, 0x4d, 0x73, 0x75, 0x6f, 0x2f, 0x38, 0x45, 0x33, 0x5a, 0x70, 0x78, 0x79, +0x61, 0x64, 0x52, 0x7a, 0x35, 0x34, 0x64, 0x61, 0x55, 0x78, 0x63, 0x73, 0x6f, 0x58, 0x37, 0x47, +0x59, 0x56, 0x70, 0x6b, 0x52, 0x64, 0x6f, 0x32, 0x37, 0x41, 0x79, 0x45, 0x6b, 0x47, 0x61, 0x30, +0x79, 0x48, 0x54, 0x2f, 0x37, 0x74, 0x79, 0x75, 0x6f, 0x48, 0x58, 0x63, 0x4c, 0x62, 0x58, 0x76, +0x30, 0x59, 0x32, 0x72, 0x77, 0x58, 0x55, 0x62, 0x45, 0x54, 0x2b, 0x54, 0x48, 0x73, 0x6d, 0x2f, +0x34, 0x37, 0x73, 0x54, 0x2f, 0x30, 0x4f, 0x37, 0x51, 0x4e, 0x6d, 0x78, 0x37, 0x5a, 0x67, 0x46, +0x57, 0x61, 0x56, 0x71, 0x65, 0x63, 0x44, 0x78, 0x57, 0x47, 0x31, 0x52, 0x64, 0x58, 0x52, 0x49, +0x32, 0x6d, 0x39, 0x6d, 0x2f, 0x50, 0x2b, 0x31, 0x48, 0x6a, 0x57, 0x4c, 0x39, 0x32, 0x4c, 0x47, +0x30, 0x75, 0x2f, 0x5a, 0x61, 0x63, 0x6b, 0x38, 0x36, 0x69, 0x59, 0x32, 0x54, 0x4a, 0x76, 0x6b, +0x61, 0x67, 0x43, 0x43, 0x6b, 0x59, 0x6b, 0x52, 0x6b, 0x6a, 0x43, 0x55, 0x7a, 0x76, 0x32, 0x50, +0x39, 0x32, 0x68, 0x4c, 0x43, 0x53, 0x6f, 0x4e, 0x51, 0x43, 0x4f, 0x6b, 0x69, 0x7a, 0x33, 0x34, +0x4e, 0x53, 0x70, 0x78, 0x30, 0x64, 0x30, 0x6c, 0x4c, 0x4b, 0x42, 0x6a, 0x43, 0x43, 0x34, 0x61, +0x34, 0x64, 0x74, 0x42, 0x69, 0x4c, 0x6a, 0x6c, 0x30, 0x50, 0x70, 0x31, 0x79, 0x4e, 0x31, 0x46, +0x52, 0x31, 0x34, 0x56, 0x37, 0x68, 0x37, 0x31, 0x4a, 0x4b, 0x4b, 0x42, 0x59, 0x74, 0x72, 0x6b, +0x39, 0x31, 0x62, 0x45, 0x49, 0x55, 0x6b, 0x57, 0x54, 0x77, 0x53, 0x76, 0x37, 0x42, 0x34, 0x56, +0x74, 0x4d, 0x50, 0x54, 0x57, 0x31, 0x39, 0x58, 0x52, 0x73, 0x32, 0x64, 0x50, 0x49, 0x75, 0x6c, +0x70, 0x78, 0x47, 0x49, 0x43, 0x36, 0x75, 0x75, 0x59, 0x38, 0x74, 0x6a, 0x68, 0x34, 0x4d, 0x46, +0x74, 0x31, 0x33, 0x2f, 0x6c, 0x44, 0x4b, 0x59, 0x48, 0x39, 0x4d, 0x64, 0x61, 0x6a, 0x31, 0x57, +0x72, 0x66, 0x6b, 0x67, 0x61, 0x56, 0x51, 0x47, 0x55, 0x30, 0x6e, 0x7a, 0x77, 0x63, 0x52, 0x33, +0x6c, 0x6c, 0x55, 0x48, 0x47, 0x6e, 0x68, 0x48, 0x6c, 0x6b, 0x51, 0x33, 0x70, 0x6c, 0x4a, 0x74, +0x4d, 0x59, 0x71, 0x71, 0x65, 0x6d, 0x70, 0x6f, 0x53, 0x52, 0x41, 0x71, 0x31, 0x6e, 0x50, 0x50, +0x48, 0x4b, 0x39, 0x4a, 0x30, 0x48, 0x45, 0x6f, 0x53, 0x77, 0x37, 0x68, 0x4a, 0x58, 0x4d, 0x71, +0x2b, 0x46, 0x4f, 0x4d, 0x6a, 0x42, 0x46, 0x4f, 0x46, 0x50, 0x79, 0x55, 0x70, 0x72, 0x6b, 0x73, +0x5a, 0x6e, 0x67, 0x67, 0x45, 0x45, 0x75, 0x37, 0x77, 0x39, 0x2f, 0x45, 0x47, 0x53, 0x44, 0x2f, +0x75, 0x44, 0x4d, 0x53, 0x79, 0x62, 0x34, 0x6e, 0x30, 0x6b, 0x72, 0x53, 0x34, 0x36, 0x6a, 0x76, +0x71, 0x5a, 0x31, 0x2f, 0x43, 0x70, 0x56, 0x66, 0x64, 0x79, 0x36, 0x6d, 0x6e, 0x6e, 0x59, 0x61, +0x4d, 0x4e, 0x39, 0x44, 0x4b, 0x4a, 0x53, 0x6a, 0x6c, 0x45, 0x6b, 0x6a, 0x4b, 0x72, 0x74, 0x6d, +0x4b, 0x42, 0x63, 0x44, 0x55, 0x2f, 0x37, 0x37, 0x6c, 0x2f, 0x35, 0x4d, 0x53, 0x65, 0x6d, 0x31, +0x54, 0x67, 0x49, 0x4b, 0x36, 0x4e, 0x4a, 0x53, 0x71, 0x5a, 0x6d, 0x6c, 0x35, 0x72, 0x6a, 0x50, +0x32, 0x53, 0x63, 0x6b, 0x76, 0x50, 0x2b, 0x39, 0x69, 0x6c, 0x51, 0x41, 0x68, 0x51, 0x6b, 0x69, +0x70, 0x73, 0x46, 0x72, 0x79, 0x35, 0x61, 0x71, 0x33, 0x4f, 0x57, 0x33, 0x67, 0x78, 0x51, 0x36, +0x51, 0x34, 0x4c, 0x4f, 0x61, 0x64, 0x75, 0x71, 0x53, 0x7a, 0x73, 0x36, 0x64, 0x6b, 0x72, 0x79, +0x38, 0x4d, 0x42, 0x62, 0x4c, 0x47, 0x55, 0x2b, 0x66, 0x7a, 0x37, 0x54, 0x54, 0x30, 0x30, 0x6c, +0x72, 0x59, 0x64, 0x44, 0x45, 0x4d, 0x63, 0x72, 0x44, 0x5a, 0x4e, 0x55, 0x52, 0x54, 0x4d, 0x74, +0x6b, 0x38, 0x2f, 0x6f, 0x7a, 0x71, 0x4b, 0x68, 0x59, 0x52, 0x7a, 0x69, 0x63, 0x68, 0x37, 0x55, +0x4e, 0x67, 0x36, 0x63, 0x5a, 0x6c, 0x48, 0x69, 0x6e, 0x78, 0x50, 0x35, 0x46, 0x59, 0x43, 0x66, +0x36, 0x2b, 0x36, 0x62, 0x37, 0x4a, 0x48, 0x62, 0x7a, 0x33, 0x71, 0x48, 0x45, 0x57, 0x33, 0x59, +0x6f, 0x54, 0x6a, 0x74, 0x65, 0x55, 0x56, 0x45, 0x70, 0x4f, 0x50, 0x51, 0x41, 0x78, 0x65, 0x56, +0x6e, 0x65, 0x31, 0x78, 0x77, 0x63, 0x77, 0x7a, 0x68, 0x37, 0x37, 0x75, 0x54, 0x4c, 0x39, 0x38, +0x2f, 0x53, 0x79, 0x6e, 0x70, 0x32, 0x72, 0x57, 0x57, 0x68, 0x59, 0x73, 0x67, 0x6f, 0x38, 0x55, +0x56, 0x54, 0x42, 0x70, 0x2b, 0x46, 0x32, 0x57, 0x58, 0x56, 0x58, 0x4c, 0x57, 0x65, 0x56, 0x66, +0x51, 0x7a, 0x6f, 0x73, 0x51, 0x79, 0x31, 0x61, 0x45, 0x52, 0x49, 0x52, 0x4d, 0x46, 0x57, 0x4a, +0x58, 0x54, 0x5a, 0x53, 0x61, 0x56, 0x68, 0x36, 0x39, 0x56, 0x2b, 0x38, 0x6b, 0x2f, 0x61, 0x63, +0x4e, 0x58, 0x48, 0x46, 0x4c, 0x6b, 0x4e, 0x4b, 0x32, 0x6c, 0x68, 0x2f, 0x6d, 0x58, 0x4d, 0x4d, +0x7a, 0x6a, 0x33, 0x7a, 0x4a, 0x65, 0x34, 0x73, 0x68, 0x6f, 0x2f, 0x39, 0x42, 0x52, 0x44, 0x64, +0x75, 0x78, 0x45, 0x6a, 0x68, 0x2b, 0x50, 0x61, 0x6c, 0x6d, 0x2b, 0x6d, 0x4e, 0x6b, 0x42, 0x67, +0x68, 0x69, 0x47, 0x33, 0x61, 0x78, 0x4a, 0x5a, 0x4a, 0x6b, 0x32, 0x68, 0x33, 0x39, 0x64, 0x57, +0x55, 0x54, 0x4a, 0x31, 0x4b, 0x31, 0x73, 0x45, 0x48, 0x67, 0x37, 0x38, 0x46, 0x30, 0x48, 0x77, +0x4c, 0x2b, 0x68, 0x75, 0x73, 0x32, 0x6f, 0x68, 0x64, 0x75, 0x2b, 0x39, 0x51, 0x59, 0x6d, 0x30, +0x53, 0x56, 0x4e, 0x6f, 0x75, 0x55, 0x6e, 0x48, 0x62, 0x37, 0x68, 0x78, 0x36, 0x74, 0x74, 0x37, +0x4d, 0x34, 0x66, 0x30, 0x2b, 0x34, 0x59, 0x64, 0x66, 0x6a, 0x6b, 0x58, 0x5a, 0x41, 0x4e, 0x30, +0x4c, 0x56, 0x6a, 0x4c, 0x70, 0x39, 0x45, 0x63, 0x34, 0x2b, 0x38, 0x55, 0x48, 0x32, 0x56, 0x53, +0x56, 0x53, 0x37, 0x73, 0x4d, 0x37, 0x5a, 0x79, 0x2f, 0x74, 0x72, 0x47, 0x2f, 0x66, 0x6c, 0x2b, +0x68, 0x73, 0x4b, 0x6e, 0x2b, 0x66, 0x71, 0x55, 0x55, 0x71, 0x31, 0x66, 0x2f, 0x79, 0x4d, 0x45, +0x44, 0x42, 0x78, 0x49, 0x4d, 0x42, 0x50, 0x68, 0x4c, 0x2f, 0x45, 0x6e, 0x6b, 0x44, 0x51, 0x39, +0x68, 0x6c, 0x65, 0x53, 0x52, 0x59, 0x4a, 0x43, 0x67, 0x50, 0x52, 0x34, 0x64, 0x44, 0x4c, 0x4c, +0x38, 0x6d, 0x38, 0x56, 0x34, 0x77, 0x56, 0x43, 0x6a, 0x43, 0x55, 0x42, 0x72, 0x78, 0x66, 0x43, +0x68, 0x41, 0x55, 0x34, 0x63, 0x59, 0x6e, 0x68, 0x75, 0x59, 0x34, 0x53, 0x4e, 0x38, 0x54, 0x41, +0x78, 0x56, 0x59, 0x65, 0x79, 0x68, 0x73, 0x79, 0x73, 0x66, 0x43, 0x4c, 0x61, 0x2b, 0x48, 0x35, +0x35, 0x50, 0x2b, 0x4f, 0x74, 0x55, 0x57, 0x52, 0x6e, 0x46, 0x76, 0x67, 0x6d, 0x76, 0x50, 0x30, +0x73, 0x79, 0x6b, 0x47, 0x78, 0x55, 0x33, 0x33, 0x39, 0x43, 0x61, 0x46, 0x50, 0x6e, 0x51, 0x68, +0x63, 0x66, 0x77, 0x6f, 0x33, 0x66, 0x70, 0x42, 0x59, 0x37, 0x53, 0x61, 0x41, 0x55, 0x4c, 0x39, +0x42, 0x36, 0x4f, 0x2f, 0x6e, 0x59, 0x4b, 0x32, 0x69, 0x66, 0x6c, 0x35, 0x4c, 0x41, 0x6b, 0x65, +0x64, 0x78, 0x6c, 0x75, 0x58, 0x6e, 0x38, 0x6b, 0x2f, 0x57, 0x38, 0x64, 0x38, 0x44, 0x55, 0x41, +0x6b, 0x78, 0x34, 0x50, 0x4c, 0x78, 0x2b, 0x43, 0x32, 0x41, 0x4f, 0x6c, 0x74, 0x4a, 0x62, 0x50, +0x2b, 0x42, 0x38, 0x33, 0x66, 0x33, 0x78, 0x4a, 0x79, 0x51, 0x41, 0x54, 0x74, 0x49, 0x35, 0x47, +0x30, 0x34, 0x31, 0x36, 0x58, 0x32, 0x75, 0x64, 0x66, 0x54, 0x31, 0x41, 0x78, 0x77, 0x78, 0x30, +0x6e, 0x74, 0x4f, 0x58, 0x7a, 0x64, 0x53, 0x57, 0x73, 0x57, 0x66, 0x4d, 0x66, 0x4a, 0x67, 0x7a, +0x76, 0x79, 0x43, 0x31, 0x66, 0x4f, 0x46, 0x2f, 0x47, 0x52, 0x52, 0x65, 0x31, 0x6f, 0x57, 0x58, +0x4c, 0x6c, 0x6b, 0x6e, 0x31, 0x63, 0x64, 0x70, 0x70, 0x4e, 0x62, 0x7a, 0x78, 0x67, 0x2b, 0x61, +0x63, 0x79, 0x4f, 0x74, 0x55, 0x6e, 0x62, 0x47, 0x64, 0x7a, 0x64, 0x2b, 0x4f, 0x70, 0x76, 0x55, +0x56, 0x58, 0x61, 0x69, 0x32, 0x41, 0x7a, 0x69, 0x73, 0x38, 0x34, 0x46, 0x30, 0x37, 0x37, 0x61, +0x59, 0x76, 0x4c, 0x78, 0x30, 0x54, 0x68, 0x32, 0x52, 0x7a, 0x76, 0x72, 0x31, 0x6c, 0x57, 0x34, +0x4c, 0x49, 0x50, 0x63, 0x41, 0x70, 0x5a, 0x30, 0x6f, 0x73, 0x4e, 0x64, 0x4a, 0x62, 0x49, 0x58, +0x45, 0x76, 0x69, 0x47, 0x77, 0x62, 0x2b, 0x34, 0x46, 0x53, 0x67, 0x76, 0x4d, 0x2f, 0x6b, 0x61, +0x79, 0x6f, 0x56, 0x67, 0x77, 0x71, 0x4c, 0x2f, 0x69, 0x38, 0x72, 0x50, 0x68, 0x73, 0x69, 0x64, +0x71, 0x69, 0x5a, 0x38, 0x6e, 0x69, 0x4a, 0x2f, 0x6b, 0x49, 0x37, 0x75, 0x4d, 0x51, 0x43, 0x5a, +0x43, 0x4b, 0x61, 0x31, 0x45, 0x57, 0x55, 0x55, 0x38, 0x54, 0x63, 0x45, 0x38, 0x45, 0x44, 0x76, +0x42, 0x57, 0x4d, 0x64, 0x66, 0x39, 0x2b, 0x32, 0x77, 0x45, 0x42, 0x33, 0x58, 0x43, 0x6f, 0x35, +0x61, 0x36, 0x66, 0x46, 0x56, 0x2f, 0x78, 0x6a, 0x4c, 0x65, 0x69, 0x76, 0x47, 0x76, 0x65, 0x41, +0x78, 0x2f, 0x6f, 0x70, 0x36, 0x56, 0x6c, 0x30, 0x73, 0x47, 0x62, 0x77, 0x45, 0x78, 0x6a, 0x30, +0x62, 0x35, 0x4d, 0x34, 0x37, 0x6f, 0x31, 0x52, 0x48, 0x4b, 0x73, 0x48, 0x34, 0x6e, 0x68, 0x37, +0x70, 0x42, 0x4e, 0x30, 0x6f, 0x35, 0x63, 0x36, 0x4a, 0x7a, 0x37, 0x36, 0x71, 0x2f, 0x76, 0x4d, +0x56, 0x56, 0x39, 0x42, 0x68, 0x7a, 0x42, 0x6a, 0x79, 0x68, 0x67, 0x30, 0x6a, 0x61, 0x2b, 0x42, +0x41, 0x66, 0x72, 0x37, 0x32, 0x57, 0x69, 0x49, 0x35, 0x4f, 0x66, 0x38, 0x54, 0x4b, 0x4c, 0x55, +0x51, 0x6d, 0x72, 0x6a, 0x51, 0x78, 0x4b, 0x55, 0x47, 0x6f, 0x32, 0x69, 0x54, 0x4c, 0x70, 0x6a, +0x34, 0x78, 0x52, 0x43, 0x55, 0x4d, 0x4a, 0x77, 0x2f, 0x34, 0x45, 0x50, 0x69, 0x4b, 0x70, 0x4f, +0x53, 0x71, 0x72, 0x62, 0x38, 0x61, 0x2b, 0x48, 0x5a, 0x4c, 0x4e, 0x6e, 0x53, 0x6b, 0x6f, 0x35, +0x5a, 0x6c, 0x57, 0x34, 0x2f, 0x37, 0x32, 0x73, 0x41, 0x55, 0x36, 0x5a, 0x4d, 0x35, 0x71, 0x53, +0x54, 0x68, 0x6c, 0x4e, 0x54, 0x55, 0x35, 0x4f, 0x45, 0x38, 0x36, 0x61, 0x65, 0x55, 0x77, 0x39, +0x72, 0x62, 0x66, 0x4a, 0x2f, 0x4f, 0x54, 0x6b, 0x35, 0x54, 0x4a, 0x34, 0x38, 0x6d, 0x5a, 0x6b, +0x7a, 0x5a, 0x32, 0x4b, 0x74, 0x70, 0x66, 0x2b, 0x42, 0x42, 0x37, 0x4a, 0x73, 0x36, 0x56, 0x4b, +0x58, 0x4f, 0x43, 0x51, 0x65, 0x49, 0x79, 0x6a, 0x71, 0x73, 0x64, 0x53, 0x37, 0x67, 0x42, 0x68, +0x68, 0x45, 0x62, 0x45, 0x59, 0x4d, 0x75, 0x41, 0x52, 0x46, 0x35, 0x4c, 0x6a, 0x68, 0x78, 0x37, +0x54, 0x61, 0x42, 0x43, 0x65, 0x65, 0x62, 0x4a, 0x48, 0x6e, 0x77, 0x4d, 0x39, 0x48, 0x76, 0x34, +0x6c, 0x69, 0x2b, 0x39, 0x72, 0x51, 0x67, 0x68, 0x52, 0x78, 0x7a, 0x2b, 0x50, 0x6d, 0x55, 0x42, +0x57, 0x49, 0x49, 0x75, 0x64, 0x36, 0x37, 0x4f, 0x6f, 0x72, 0x39, 0x56, 0x6f, 0x33, 0x63, 0x41, +0x57, 0x72, 0x59, 0x30, 0x68, 0x4f, 0x79, 0x74, 0x45, 0x78, 0x31, 0x37, 0x58, 0x4d, 0x4f, 0x4f, +0x34, 0x79, 0x2f, 0x5a, 0x4c, 0x41, 0x4d, 0x72, 0x56, 0x4c, 0x34, 0x36, 0x41, 0x52, 0x54, 0x65, +0x6f, 0x2f, 0x54, 0x4a, 0x46, 0x38, 0x42, 0x50, 0x70, 0x74, 0x52, 0x50, 0x61, 0x6c, 0x35, 0x51, +0x53, 0x36, 0x54, 0x76, 0x71, 0x58, 0x66, 0x38, 0x5a, 0x57, 0x6c, 0x78, 0x39, 0x72, 0x35, 0x73, +0x49, 0x42, 0x31, 0x51, 0x79, 0x37, 0x64, 0x5a, 0x4c, 0x4f, 0x44, 0x6c, 0x59, 0x53, 0x38, 0x67, +0x54, 0x4c, 0x67, 0x63, 0x44, 0x45, 0x75, 0x73, 0x4a, 0x6a, 0x43, 0x63, 0x78, 0x66, 0x6c, 0x59, +0x6b, 0x47, 0x31, 0x42, 0x45, 0x49, 0x6f, 0x6f, 0x65, 0x2b, 0x39, 0x58, 0x79, 0x2f, 0x30, 0x30, +0x4a, 0x4a, 0x61, 0x43, 0x49, 0x43, 0x57, 0x46, 0x50, 0x4a, 0x6d, 0x4c, 0x77, 0x73, 0x38, 0x43, +0x34, 0x36, 0x43, 0x48, 0x44, 0x6d, 0x72, 0x58, 0x70, 0x39, 0x4d, 0x2f, 0x4e, 0x77, 0x52, 0x6a, +0x46, 0x36, 0x70, 0x38, 0x79, 0x45, 0x4e, 0x49, 0x35, 0x4f, 0x6c, 0x4e, 0x56, 0x53, 0x49, 0x42, +0x77, 0x77, 0x65, 0x76, 0x30, 0x36, 0x2f, 0x41, 0x6c, 0x67, 0x66, 0x43, 0x78, 0x64, 0x4f, 0x72, +0x34, 0x44, 0x71, 0x4c, 0x64, 0x46, 0x71, 0x51, 0x35, 0x67, 0x4b, 0x2b, 0x2b, 0x2f, 0x42, 0x4e, +0x64, 0x75, 0x68, 0x7a, 0x42, 0x34, 0x4d, 0x47, 0x4f, 0x34, 0x39, 0x2f, 0x7a, 0x50, 0x4a, 0x52, +0x79, 0x6d, 0x58, 0x57, 0x61, 0x51, 0x57, 0x6c, 0x44, 0x41, 0x6e, 0x75, 0x61, 0x77, 0x47, 0x37, +0x33, 0x42, 0x2f, 0x33, 0x52, 0x45, 0x70, 0x73, 0x75, 0x73, 0x62, 0x58, 0x4e, 0x6f, 0x62, 0x51, +0x41, 0x53, 0x69, 0x6f, 0x4f, 0x50, 0x55, 0x42, 0x79, 0x2b, 0x64, 0x6b, 0x65, 0x6c, 0x7a, 0x35, +0x52, 0x68, 0x7a, 0x68, 0x65, 0x45, 0x44, 0x76, 0x53, 0x5a, 0x61, 0x55, 0x52, 0x78, 0x75, 0x47, +0x6e, 0x68, 0x5a, 0x46, 0x49, 0x4b, 0x78, 0x72, 0x79, 0x46, 0x6e, 0x71, 0x4f, 0x6c, 0x46, 0x51, +0x4c, 0x2f, 0x42, 0x6c, 0x66, 0x38, 0x4d, 0x35, 0x42, 0x75, 0x7a, 0x6c, 0x76, 0x6d, 0x38, 0x64, +0x44, 0x6c, 0x30, 0x59, 0x70, 0x4c, 0x34, 0x79, 0x67, 0x74, 0x47, 0x5a, 0x52, 0x32, 0x78, 0x6a, +0x6e, 0x76, 0x71, 0x66, 0x34, 0x36, 0x63, 0x39, 0x78, 0x46, 0x68, 0x36, 0x69, 0x36, 0x62, 0x4f, +0x79, 0x6e, 0x6d, 0x68, 0x41, 0x6b, 0x32, 0x62, 0x53, 0x58, 0x53, 0x51, 0x66, 0x4a, 0x49, 0x30, +0x39, 0x79, 0x55, 0x4f, 0x49, 0x35, 0x41, 0x53, 0x67, 0x68, 0x55, 0x42, 0x75, 0x33, 0x63, 0x72, +0x50, 0x6f, 0x30, 0x5a, 0x68, 0x55, 0x71, 0x43, 0x59, 0x6f, 0x52, 0x34, 0x39, 0x6b, 0x68, 0x50, +0x41, 0x2f, 0x6b, 0x43, 0x4a, 0x59, 0x33, 0x47, 0x4e, 0x6b, 0x49, 0x36, 0x4f, 0x32, 0x32, 0x68, +0x4a, 0x54, 0x69, 0x6a, 0x4f, 0x74, 0x70, 0x70, 0x4d, 0x48, 0x70, 0x31, 0x39, 0x42, 0x4a, 0x31, +0x62, 0x62, 0x75, 0x44, 0x44, 0x31, 0x51, 0x4e, 0x5a, 0x58, 0x64, 0x4b, 0x57, 0x7a, 0x64, 0x57, +0x35, 0x46, 0x47, 0x5a, 0x55, 0x34, 0x47, 0x6d, 0x4a, 0x53, 0x54, 0x69, 0x72, 0x4c, 0x55, 0x79, +0x59, 0x63, 0x44, 0x2b, 0x37, 0x64, 0x6c, 0x57, 0x79, 0x59, 0x63, 0x4f, 0x47, 0x52, 0x71, 0x7a, +0x49, 0x4d, 0x6c, 0x56, 0x72, 0x6b, 0x6f, 0x34, 0x56, 0x57, 0x63, 0x6b, 0x47, 0x63, 0x74, 0x52, +0x75, 0x33, 0x62, 0x71, 0x78, 0x65, 0x50, 0x48, 0x69, 0x46, 0x44, 0x56, 0x65, 0x45, 0x51, 0x77, +0x45, 0x43, 0x59, 0x56, 0x43, 0x53, 0x4d, 0x38, 0x6a, 0x2f, 0x66, 0x4c, 0x62, 0x73, 0x4f, 0x55, +0x37, 0x33, 0x62, 0x34, 0x33, 0x45, 0x6f, 0x4b, 0x67, 0x52, 0x33, 0x6f, 0x6b, 0x6a, 0x62, 0x54, +0x30, 0x64, 0x4a, 0x53, 0x55, 0x68, 0x45, 0x49, 0x68, 0x6c, 0x46, 0x4b, 0x38, 0x39, 0x41, 0x44, +0x30, 0x50, 0x69, 0x7a, 0x45, 0x54, 0x59, 0x74, 0x62, 0x73, 0x4c, 0x4e, 0x4f, 0x51, 0x56, 0x68, +0x79, 0x2b, 0x36, 0x44, 0x4c, 0x2b, 0x65, 0x4b, 0x4e, 0x4d, 0x42, 0x2b, 0x2b, 0x57, 0x30, 0x6c, +0x4a, 0x2b, 0x58, 0x59, 0x33, 0x4a, 0x76, 0x33, 0x45, 0x49, 0x41, 0x6c, 0x71, 0x38, 0x42, 0x34, +0x39, 0x4d, 0x76, 0x6a, 0x75, 0x75, 0x35, 0x6c, 0x30, 0x58, 0x35, 0x58, 0x71, 0x54, 0x64, 0x6e, +0x33, 0x55, 0x76, 0x37, 0x38, 0x4c, 0x7a, 0x35, 0x70, 0x5a, 0x6d, 0x4f, 0x68, 0x54, 0x77, 0x68, +0x2b, 0x34, 0x70, 0x7a, 0x49, 0x43, 0x79, 0x69, 0x56, 0x52, 0x4f, 0x4a, 0x73, 0x56, 0x67, 0x33, +0x46, 0x51, 0x34, 0x6f, 0x6f, 0x6e, 0x33, 0x78, 0x2b, 0x4a, 0x56, 0x63, 0x2b, 0x58, 0x75, 0x6e, +0x47, 0x72, 0x78, 0x55, 0x4e, 0x58, 0x41, 0x71, 0x70, 0x58, 0x67, 0x41, 0x63, 0x33, 0x34, 0x4c, +0x6e, 0x61, 0x51, 0x5a, 0x4f, 0x33, 0x4b, 0x2b, 0x6d, 0x2f, 0x30, 0x39, 0x4b, 0x43, 0x41, 0x52, +0x53, 0x47, 0x67, 0x6f, 0x4c, 0x4d, 0x33, 0x46, 0x5a, 0x58, 0x33, 0x31, 0x4e, 0x77, 0x4b, 0x66, +0x6a, 0x64, 0x6c, 0x6c, 0x62, 0x4e, 0x50, 0x39, 0x36, 0x2f, 0x69, 0x69, 0x55, 0x73, 0x6d, 0x67, +0x64, 0x51, 0x47, 0x76, 0x68, 0x67, 0x68, 0x46, 0x6f, 0x55, 0x41, 0x48, 0x42, 0x54, 0x51, 0x49, +0x5a, 0x36, 0x62, 0x6b, 0x63, 0x33, 0x66, 0x63, 0x63, 0x77, 0x47, 0x4b, 0x79, 0x2f, 0x6b, 0x4d, +0x38, 0x76, 0x70, 0x30, 0x66, 0x66, 0x6d, 0x68, 0x46, 0x55, 0x5a, 0x45, 0x6d, 0x45, 0x4f, 0x69, +0x50, 0x35, 0x77, 0x56, 0x4a, 0x4e, 0x64, 0x4d, 0x59, 0x66, 0x67, 0x58, 0x4b, 0x57, 0x4a, 0x51, +0x43, 0x5a, 0x63, 0x78, 0x51, 0x30, 0x4b, 0x49, 0x35, 0x6c, 0x42, 0x47, 0x67, 0x58, 0x77, 0x2f, +0x46, 0x4f, 0x63, 0x4d, 0x36, 0x63, 0x63, 0x63, 0x72, 0x39, 0x52, 0x53, 0x65, 0x6d, 0x34, 0x73, +0x38, 0x77, 0x49, 0x64, 0x79, 0x52, 0x74, 0x78, 0x71, 0x4c, 0x34, 0x30, 0x37, 0x75, 0x32, 0x7a, +0x46, 0x4f, 0x75, 0x6e, 0x66, 0x54, 0x59, 0x41, 0x79, 0x74, 0x46, 0x62, 0x6b, 0x5a, 0x37, 0x62, +0x6a, 0x6c, 0x61, 0x66, 0x7a, 0x57, 0x56, 0x4d, 0x55, 0x5a, 0x32, 0x4d, 0x76, 0x53, 0x32, 0x73, +0x6a, 0x4f, 0x58, 0x4f, 0x61, 0x59, 0x47, 0x65, 0x66, 0x4b, 0x42, 0x2b, 0x63, 0x47, 0x75, 0x54, +0x67, 0x4c, 0x66, 0x56, 0x63, 0x2b, 0x59, 0x72, 0x48, 0x33, 0x50, 0x35, 0x52, 0x75, 0x71, 0x53, +0x44, 0x78, 0x55, 0x43, 0x74, 0x44, 0x39, 0x6d, 0x52, 0x69, 0x6f, 0x6a, 0x66, 0x66, 0x75, 0x50, +0x54, 0x68, 0x79, 0x55, 0x6e, 0x41, 0x31, 0x2b, 0x34, 0x6a, 0x56, 0x4c, 0x75, 0x4f, 0x75, 0x46, +0x71, 0x30, 0x30, 0x6c, 0x6d, 0x2f, 0x2f, 0x32, 0x43, 0x63, 0x73, 0x61, 0x6c, 0x78, 0x47, 0x6f, +0x42, 0x4f, 0x6f, 0x59, 0x31, 0x7a, 0x6b, 0x44, 0x57, 0x4f, 0x69, 0x31, 0x47, 0x4d, 0x47, 0x43, +0x5a, 0x39, 0x4f, 0x55, 0x51, 0x56, 0x70, 0x57, 0x31, 0x77, 0x66, 0x4d, 0x67, 0x50, 0x36, 0x32, +0x47, 0x6b, 0x46, 0x56, 0x4a, 0x72, 0x4c, 0x7a, 0x72, 0x41, 0x2b, 0x63, 0x6d, 0x6b, 0x31, 0x4c, +0x52, 0x72, 0x6c, 0x32, 0x37, 0x42, 0x76, 0x5a, 0x6a, 0x36, 0x54, 0x50, 0x68, 0x71, 0x68, 0x52, +0x47, 0x5a, 0x43, 0x6c, 0x64, 0x56, 0x4a, 0x30, 0x2f, 0x41, 0x61, 0x53, 0x43, 0x76, 0x42, 0x79, +0x32, 0x50, 0x6b, 0x54, 0x6e, 0x72, 0x6c, 0x32, 0x6f, 0x72, 0x71, 0x6f, 0x6d, 0x4e, 0x79, 0x2b, +0x58, 0x38, 0x50, 0x42, 0x68, 0x61, 0x50, 0x39, 0x2f, 0x48, 0x68, 0x41, 0x4d, 0x42, 0x43, 0x67, +0x76, 0x4c, 0x36, 0x64, 0x50, 0x33, 0x7a, 0x35, 0x45, 0x30, 0x68, 0x6f, 0x79, 0x4e, 0x5a, 0x6b, +0x52, 0x63, 0x4d, 0x39, 0x33, 0x57, 0x57, 0x51, 0x47, 0x67, 0x68, 0x7a, 0x52, 0x75, 0x54, 0x55, +0x58, 0x74, 0x44, 0x2b, 0x54, 0x7a, 0x31, 0x37, 0x4d, 0x59, 0x4e, 0x6d, 0x4b, 0x57, 0x72, 0x4a, +0x61, 0x51, 0x4f, 0x66, 0x4d, 0x44, 0x48, 0x39, 0x63, 0x75, 0x68, 0x42, 0x57, 0x37, 0x64, 0x73, +0x38, 0x74, 0x45, 0x39, 0x6f, 0x49, 0x6a, 0x66, 0x58, 0x37, 0x38, 0x39, 0x47, 0x49, 0x42, 0x74, +0x2f, 0x41, 0x53, 0x6a, 0x49, 0x4b, 0x6b, 0x6a, 0x52, 0x41, 0x6c, 0x51, 0x6a, 0x59, 0x36, 0x41, +0x32, 0x6d, 0x6c, 0x43, 0x6e, 0x47, 0x67, 0x4a, 0x35, 0x63, 0x64, 0x70, 0x62, 0x54, 0x57, 0x34, +0x43, 0x4b, 0x77, 0x43, 0x6b, 0x70, 0x36, 0x64, 0x54, 0x55, 0x31, 0x2f, 0x4c, 0x63, 0x35, 0x2b, +0x4f, 0x70, 0x74, 0x32, 0x41, 0x56, 0x72, 0x79, 0x2b, 0x6f, 0x55, 0x58, 0x53, 0x35, 0x32, 0x2b, +0x4d, 0x52, 0x46, 0x74, 0x2f, 0x41, 0x74, 0x47, 0x70, 0x75, 0x41, 0x43, 0x6e, 0x66, 0x64, 0x33, +0x31, 0x44, 0x74, 0x67, 0x70, 0x2b, 0x39, 0x48, 0x36, 0x2f, 0x30, 0x48, 0x78, 0x34, 0x47, 0x71, +0x62, 0x53, 0x6e, 0x4c, 0x59, 0x48, 0x4b, 0x37, 0x55, 0x46, 0x4d, 0x4b, 0x55, 0x43, 0x6e, 0x45, +0x4b, 0x73, 0x47, 0x50, 0x48, 0x6f, 0x6a, 0x30, 0x69, 0x2f, 0x46, 0x49, 0x48, 0x53, 0x65, 0x49, +0x36, 0x77, 0x51, 0x71, 0x6a, 0x55, 0x76, 0x78, 0x6d, 0x2f, 0x51, 0x59, 0x50, 0x33, 0x69, 0x38, +0x6f, 0x59, 0x77, 0x39, 0x67, 0x34, 0x56, 0x4e, 0x77, 0x35, 0x43, 0x6a, 0x67, 0x57, 0x4f, 0x43, +0x61, 0x6c, 0x4f, 0x59, 0x6c, 0x6d, 0x74, 0x34, 0x55, 0x6e, 0x59, 0x56, 0x2f, 0x6a, 0x74, 0x42, +0x41, 0x33, 0x4c, 0x6f, 0x33, 0x4e, 0x75, 0x4f, 0x6d, 0x7a, 0x4c, 0x61, 0x70, 0x76, 0x77, 0x32, +0x38, 0x39, 0x70, 0x32, 0x44, 0x71, 0x44, 0x5a, 0x39, 0x4d, 0x36, 0x6d, 0x66, 0x55, 0x36, 0x75, +0x6c, 0x6f, 0x75, 0x6a, 0x53, 0x67, 0x66, 0x76, 0x32, 0x38, 0x6d, 0x79, 0x2f, 0x39, 0x2f, 0x6c, +0x50, 0x4f, 0x6d, 0x6b, 0x71, 0x57, 0x73, 0x56, 0x42, 0x78, 0x39, 0x30, 0x71, 0x59, 0x35, 0x71, +0x43, 0x6c, 0x52, 0x74, 0x4b, 0x4b, 0x71, 0x4f, 0x7a, 0x77, 0x36, 0x67, 0x48, 0x32, 0x4c, 0x70, +0x67, 0x37, 0x42, 0x36, 0x2f, 0x2b, 0x33, 0x74, 0x4c, 0x65, 0x58, 0x6c, 0x35, 0x6b, 0x33, 0x35, +0x33, 0x72, 0x6d, 0x48, 0x6c, 0x6f, 0x2f, 0x2b, 0x55, 0x62, 0x36, 0x77, 0x55, 0x66, 0x70, 0x61, +0x6b, 0x51, 0x43, 0x6a, 0x55, 0x47, 0x41, 0x72, 0x37, 0x37, 0x30, 0x4e, 0x41, 0x51, 0x64, 0x73, +0x6a, 0x6a, 0x75, 0x62, 0x65, 0x33, 0x43, 0x6d, 0x4d, 0x4f, 0x72, 0x63, 0x4d, 0x5a, 0x39, 0x31, +0x4c, 0x50, 0x4f, 0x6d, 0x76, 0x64, 0x32, 0x43, 0x6e, 0x6a, 0x7a, 0x2f, 0x59, 0x44, 0x6b, 0x6c, +0x6e, 0x78, 0x4c, 0x36, 0x57, 0x33, 0x5a, 0x76, 0x2f, 0x73, 0x37, 0x42, 0x39, 0x73, 0x37, 0x35, +0x75, 0x4f, 0x74, 0x77, 0x46, 0x4c, 0x46, 0x6a, 0x75, 0x43, 0x47, 0x7a, 0x37, 0x2b, 0x68, 0x57, +0x2f, 0x39, 0x57, 0x38, 0x61, 0x32, 0x72, 0x47, 0x4a, 0x7a, 0x75, 0x30, 0x37, 0x77, 0x30, 0x67, +0x63, 0x33, 0x6e, 0x6b, 0x76, 0x39, 0x66, 0x63, 0x6f, 0x50, 0x74, 0x6c, 0x67, 0x66, 0x2f, 0x6a, +0x2f, 0x69, 0x77, 0x54, 0x38, 0x50, 0x30, 0x6c, 0x4e, 0x55, 0x77, 0x6b, 0x72, 0x70, 0x45, 0x46, +0x6b, 0x41, 0x41, 0x41, 0x41, 0x41, 0x45, 0x6c, 0x46, 0x54, 0x6b, 0x53, 0x75, 0x51, 0x6d, 0x43, +0x43, 0x22, 0x29, 0x20, 0x6e, 0x6f, 0x2d, 0x72, 0x65, 0x70, 0x65, 0x61, 0x74, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x61, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, +0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x66, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, +0x34, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x61, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x30, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x6c, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, +0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x61, 0x6e, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x30, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x6f, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, +0x30, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x61, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x30, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x74, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, +0x30, 0x38, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x61, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, +0x30, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x61, 0x7a, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x30, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, +0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x62, 0x62, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, +0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x62, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x65, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x66, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x67, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x68, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, +0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x6a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, +0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x62, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, +0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x62, 0x6e, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, +0x20, 0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x62, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x62, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, +0x31, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x62, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, +0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, +0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x76, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x77, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, +0x36, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x62, 0x7a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, +0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x63, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, +0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x63, 0x61, 0x74, 0x61, 0x6c, 0x6f, 0x6e, 0x69, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, +0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x63, 0x66, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, +0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x63, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x63, 0x68, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, +0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x63, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x32, +0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, +0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x6c, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x6d, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x6e, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x6f, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x72, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x32, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x30, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x63, 0x76, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x63, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x33, +0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, +0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x63, 0x7a, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x64, 0x65, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x64, 0x6a, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x64, 0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, +0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x64, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, +0x38, 0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x64, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, +0x70, 0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x64, 0x7a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, +0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x65, 0x63, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, +0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x65, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x65, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, +0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x65, 0x68, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x33, +0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x65, +0x6e, 0x67, 0x6c, 0x61, 0x6e, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, +0x78, 0x20, 0x2d, 0x33, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x65, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x34, 0x34, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x65, 0x73, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x65, 0x74, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x65, 0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x66, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, +0x34, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x66, 0x6a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, +0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x66, 0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x66, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, +0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x66, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x34, +0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x66, +0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x61, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x62, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x64, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x65, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x66, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x34, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x68, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, +0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x67, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, +0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x67, 0x6c, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x6d, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x6e, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x70, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x71, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, +0x32, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x67, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, +0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x67, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, +0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x67, 0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, +0x20, 0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x67, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x67, 0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, +0x35, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x68, 0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x35, +0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x68, +0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x68, 0x6e, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x35, 0x35, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x68, 0x72, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x68, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, +0x36, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x68, 0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, +0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x69, 0x63, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, +0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x69, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x36, +0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, +0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x6c, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x6d, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x6e, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x71, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, +0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, +0x32, 0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x69, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, +0x70, 0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x6a, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, +0x78, 0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x6a, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, +0x20, 0x2d, 0x36, 0x36, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x6a, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6a, 0x70, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6b, 0x65, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6b, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6b, 0x68, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, +0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x6b, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, +0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x6b, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, +0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x6b, 0x6e, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x37, +0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6b, +0x70, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6b, 0x72, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6b, 0x75, 0x72, +0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, +0x78, 0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x6b, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, +0x20, 0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x6b, 0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x6b, 0x7a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, +0x37, 0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x6c, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x37, +0x37, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, +0x62, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x37, 0x37, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x63, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, +0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, +0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x6c, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, +0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x6c, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x75, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x76, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6c, 0x79, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x61, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x63, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, +0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, +0x38, 0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x68, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, +0x70, 0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, +0x78, 0x20, 0x2d, 0x38, 0x38, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x6d, 0x6c, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x39, 0x39, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x6d, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x6e, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x70, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, +0x34, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x71, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, +0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x6d, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x6d, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, +0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x6d, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x39, +0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, +0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x76, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x77, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x78, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x79, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6d, 0x7a, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, +0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, +0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x39, 0x39, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x63, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, +0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x6e, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x31, 0x30, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x6e, 0x66, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, +0x31, 0x31, 0x30, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2d, 0x6e, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, +0x31, 0x30, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x6e, 0x69, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, +0x30, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, +0x6c, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x6f, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x70, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x72, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x75, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6e, 0x7a, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x6f, 0x6d, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x61, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x65, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x66, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x67, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x31, 0x30, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x68, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x6b, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x6c, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, +0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, +0x70, 0x78, 0x20, 0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x70, 0x6e, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, +0x78, 0x20, 0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x70, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, +0x20, 0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x70, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x70, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x70, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x70, 0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x71, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x72, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x72, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x72, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x72, 0x75, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x72, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x32, 0x31, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x73, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x62, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x63, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x63, 0x6f, 0x74, 0x6c, +0x61, 0x6e, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, +0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, +0x33, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x73, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, +0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, +0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x67, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x68, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x69, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x6b, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x6c, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x6d, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x6e, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x6f, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x6f, 0x6d, +0x61, 0x6c, 0x69, 0x6c, 0x61, 0x6e, 0x64, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, +0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, +0x70, 0x78, 0x20, 0x2d, 0x31, 0x33, 0x32, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x31, +0x34, 0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x73, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, +0x33, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, +0x76, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, +0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, +0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x78, +0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, +0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x79, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x73, 0x7a, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x63, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x64, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x66, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x67, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x68, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x69, 0x62, 0x65, 0x74, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x6a, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x6b, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x6c, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x6d, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x34, 0x33, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x6e, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x6f, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, +0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, +0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, +0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x33, +0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x74, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, +0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x34, 0x38, +0x70, 0x78, 0x20, 0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2d, 0x74, 0x76, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, +0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, +0x78, 0x20, 0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, +0x6c, 0x61, 0x67, 0x2d, 0x74, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, +0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, +0x20, 0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, +0x61, 0x67, 0x2d, 0x74, 0x7a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, +0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x75, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x75, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x75, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x75, 0x73, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x75, 0x79, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x75, 0x7a, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x76, 0x61, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x76, 0x63, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x32, 0x34, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x76, 0x65, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x34, 0x30, 0x70, 0x78, 0x20, +0x2d, 0x31, 0x35, 0x34, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, +0x67, 0x2d, 0x76, 0x67, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, +0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x30, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, +0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x76, 0x69, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x76, 0x6e, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x33, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x76, 0x75, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x34, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x77, 0x61, 0x6c, 0x65, 0x73, 0x7b, +0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, +0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x36, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, +0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x77, 0x66, 0x7b, 0x62, +0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, +0x6f, 0x6e, 0x3a, 0x2d, 0x38, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, +0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x77, 0x73, 0x7b, 0x62, 0x61, +0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, +0x6e, 0x3a, 0x2d, 0x39, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x78, 0x6b, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x31, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x79, 0x65, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x32, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x79, 0x74, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x34, 0x34, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x7a, 0x61, 0x7b, 0x62, 0x61, 0x63, +0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, +0x3a, 0x2d, 0x31, 0x36, 0x30, 0x70, 0x78, 0x20, 0x2d, 0x31, 0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, +0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x7a, 0x61, 0x6e, 0x7a, 0x69, 0x62, +0x61, 0x72, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x37, 0x36, 0x70, 0x78, 0x20, 0x2d, 0x31, +0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x7a, 0x6d, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x31, 0x39, 0x32, 0x70, 0x78, 0x20, 0x2d, 0x31, +0x36, 0x35, 0x70, 0x78, 0x7d, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2e, 0x66, 0x6c, 0x61, 0x67, 0x2d, +0x7a, 0x77, 0x7b, 0x62, 0x61, 0x63, 0x6b, 0x67, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x2d, 0x70, 0x6f, +0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x3a, 0x2d, 0x32, 0x30, 0x38, 0x70, 0x78, 0x20, 0x2d, 0x31, +0x36, 0x35, 0x70, 0x78, 0x7d, 0x3c, 0x2f, 0x73, 0x74, 0x79, 0x6c, 0x65, 0x3e, 0x3c, 0x2f, 0x68, +0x65, 0x61, 0x64, 0x3e, 0x3c, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x68, 0x31, 0x3e, 0x20, 0x4e, +0x67, 0x69, 0x6e, 0x78, 0x20, 0x56, 0x68, 0x6f, 0x73, 0x74, 0x20, 0x54, 0x72, 0x61, 0x66, 0x66, +0x69, 0x63, 0x20, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x3c, 0x2f, 0x68, 0x31, 0x3e, 0x3c, 0x64, +0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x3e, 0x3c, 0x2f, +0x64, 0x69, 0x76, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x75, 0x70, 0x64, 0x61, +0x74, 0x65, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3e, +0x20, 0x3c, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x3e, 0x75, 0x70, 0x64, 0x61, 0x74, 0x65, 0x20, +0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x3a, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x6f, 0x6e, +0x67, 0x3e, 0x20, 0x3c, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x20, 0x69, 0x64, 0x3d, 0x72, 0x65, +0x66, 0x72, 0x65, 0x73, 0x68, 0x20, 0x6f, 0x6e, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x3d, 0x76, +0x74, 0x73, 0x53, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x28, 0x74, 0x68, +0x69, 0x73, 0x2e, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x31, 0x30, 0x30, 0x30, 0x29, 0x3e, 0x3c, +0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x31, 0x3e, 0x31, +0x3c, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x3c, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, +0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x32, 0x3e, 0x32, 0x3c, 0x2f, 0x6f, 0x70, 0x74, 0x69, +0x6f, 0x6e, 0x3e, 0x3c, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, +0x3d, 0x33, 0x3e, 0x33, 0x3c, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x3c, 0x6f, 0x70, +0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x34, 0x3e, 0x34, 0x3c, 0x2f, +0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x3c, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, +0x61, 0x6c, 0x75, 0x65, 0x3d, 0x35, 0x3e, 0x35, 0x3c, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, +0x3e, 0x3c, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x36, +0x3e, 0x36, 0x3c, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x3c, 0x6f, 0x70, 0x74, 0x69, +0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3d, 0x37, 0x3e, 0x37, 0x3c, 0x2f, 0x6f, 0x70, +0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x3c, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x61, 0x6c, +0x75, 0x65, 0x3d, 0x38, 0x3e, 0x38, 0x3c, 0x2f, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x3e, 0x20, +0x3c, 0x2f, 0x73, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x3e, 0x20, 0x3c, 0x73, 0x74, 0x72, 0x6f, 0x6e, +0x67, 0x3e, 0x73, 0x65, 0x63, 0x3c, 0x2f, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x3e, 0x3c, 0x2f, +0x64, 0x69, 0x76, 0x3e, 0x3c, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x66, 0x6f, 0x6f, 0x74, +0x65, 0x72, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x66, 0x6f, 0x6f, 0x74, 0x65, 0x72, 0x3e, +0x20, 0x3c, 0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x25, 0x56, 0x2f, 0x66, 0x6f, 0x72, 0x6d, +0x61, 0x74, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x20, 0x69, 0x64, 0x3d, 0x6a, 0x73, 0x6f, 0x6e, 0x55, +0x72, 0x69, 0x3e, 0x3c, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x3e, 0x4a, 0x53, 0x4f, 0x4e, 0x3c, +0x2f, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x3e, 0x3c, 0x2f, 0x61, 0x3e, 0x20, 0x7c, 0x20, 0x3c, +0x61, 0x20, 0x68, 0x72, 0x65, 0x66, 0x3d, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, +0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x76, 0x6f, 0x7a, 0x6c, 0x74, 0x2f, +0x6e, 0x67, 0x69, 0x6e, 0x78, 0x2d, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x2d, 0x76, 0x74, 0x73, +0x3e, 0x3c, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x3e, 0x47, 0x49, 0x54, 0x48, 0x55, 0x42, 0x3c, +0x2f, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x3e, 0x3c, 0x2f, 0x61, 0x3e, 0x3c, 0x2f, 0x64, 0x69, +0x76, 0x3e, 0x20, 0x3c, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, 0x53, 0x74, 0x72, 0x69, 0x6e, +0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x66, 0x6f, 0x72, 0x6d, +0x61, 0x74, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x76, 0x61, +0x72, 0x20, 0x62, 0x3d, 0x30, 0x2c, 0x61, 0x3d, 0x61, 0x72, 0x67, 0x75, 0x6d, 0x65, 0x6e, 0x74, +0x73, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x72, 0x65, +0x70, 0x6c, 0x61, 0x63, 0x65, 0x28, 0x2f, 0x7b, 0x7d, 0x2f, 0x67, 0x2c, 0x66, 0x75, 0x6e, 0x63, +0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x79, +0x70, 0x65, 0x6f, 0x66, 0x20, 0x61, 0x5b, 0x62, 0x5d, 0x21, 0x3d, 0x22, 0x75, 0x6e, 0x64, 0x65, +0x66, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x3f, 0x61, 0x5b, 0x62, 0x2b, 0x2b, 0x5d, 0x3a, 0x22, 0x22, +0x7d, 0x29, 0x7d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, +0x73, 0x55, 0x52, 0x49, 0x3d, 0x22, 0x25, 0x56, 0x2f, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x2f, +0x6a, 0x73, 0x6f, 0x6e, 0x22, 0x2c, 0x76, 0x74, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x49, +0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x3d, 0x31, 0x30, 0x30, 0x30, 0x2c, 0x76, 0x74, 0x73, +0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x76, 0x74, 0x73, 0x53, 0x74, +0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x3d, 0x7b, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x73, +0x3a, 0x7b, 0x6d, 0x61, 0x69, 0x6e, 0x3a, 0x22, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x20, 0x6d, +0x61, 0x69, 0x6e, 0x22, 0x2c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x22, 0x53, 0x65, 0x72, +0x76, 0x65, 0x72, 0x20, 0x7a, 0x6f, 0x6e, 0x65, 0x73, 0x22, 0x2c, 0x66, 0x69, 0x6c, 0x74, 0x65, +0x72, 0x3a, 0x22, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x73, 0x22, 0x2c, 0x75, 0x70, 0x73, 0x74, +0x72, 0x65, 0x61, 0x6d, 0x3a, 0x22, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x73, 0x22, +0x2c, 0x63, 0x61, 0x63, 0x68, 0x65, 0x3a, 0x22, 0x43, 0x61, 0x63, 0x68, 0x65, 0x73, 0x22, 0x7d, +0x2c, 0x69, 0x64, 0x73, 0x3a, 0x7b, 0x6d, 0x61, 0x69, 0x6e, 0x3a, 0x22, 0x6d, 0x61, 0x69, 0x6e, +0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x22, 0x2c, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x3a, 0x22, 0x73, +0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x22, 0x2c, 0x66, 0x69, 0x6c, 0x74, +0x65, 0x72, 0x3a, 0x22, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x22, +0x2c, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x3a, 0x22, 0x75, 0x70, 0x73, 0x74, 0x72, +0x65, 0x61, 0x6d, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x22, 0x2c, 0x63, 0x61, 0x63, 0x68, 0x65, 0x3a, +0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x22, 0x7d, 0x7d, 0x3b, 0x76, +0x61, 0x72, 0x20, 0x61, 0x50, 0x73, 0x3d, 0x28, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, +0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x5b, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, +0x62, 0x3d, 0x7b, 0x6c, 0x61, 0x73, 0x74, 0x3a, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, +0x64, 0x2c, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x3a, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, +0x65, 0x64, 0x7d, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x7b, 0x67, 0x65, 0x74, 0x56, 0x61, +0x6c, 0x75, 0x65, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x63, 0x2c, 0x64, +0x29, 0x7b, 0x69, 0x66, 0x28, 0x74, 0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x61, 0x5b, 0x63, 0x5d, +0x3d, 0x3d, 0x3d, 0x22, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, 0x64, 0x22, 0x29, 0x7b, +0x61, 0x5b, 0x63, 0x5d, 0x3d, 0x64, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x22, 0x6e, 0x2f, +0x61, 0x22, 0x7d, 0x65, 0x6c, 0x73, 0x65, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x64, 0x2d, +0x61, 0x5b, 0x63, 0x5d, 0x3b, 0x61, 0x5b, 0x63, 0x5d, 0x3d, 0x64, 0x3b, 0x72, 0x65, 0x74, 0x75, +0x72, 0x6e, 0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x65, 0x2a, +0x31, 0x30, 0x30, 0x30, 0x2f, 0x62, 0x2e, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x29, 0x7d, 0x7d, +0x2c, 0x72, 0x65, 0x66, 0x72, 0x65, 0x73, 0x68, 0x3a, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, +0x6e, 0x28, 0x63, 0x29, 0x7b, 0x62, 0x2e, 0x70, 0x65, 0x72, 0x69, 0x6f, 0x64, 0x3d, 0x63, 0x2d, +0x62, 0x2e, 0x6c, 0x61, 0x73, 0x74, 0x3b, 0x62, 0x2e, 0x6c, 0x61, 0x73, 0x74, 0x3d, 0x63, 0x7d, +0x7d, 0x7d, 0x29, 0x28, 0x29, 0x3b, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6d, +0x54, 0x68, 0x28, 0x62, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x31, 0x30, 0x30, 0x30, +0x2c, 0x63, 0x3d, 0x36, 0x30, 0x2c, 0x66, 0x3d, 0x63, 0x2a, 0x63, 0x2c, 0x67, 0x3d, 0x66, 0x2a, +0x32, 0x34, 0x2c, 0x6c, 0x3d, 0x22, 0x22, 0x3b, 0x69, 0x66, 0x28, 0x62, 0x3c, 0x61, 0x29, 0x7b, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x62, 0x2b, 0x22, 0x6d, 0x73, 0x22, 0x7d, 0x69, 0x66, +0x28, 0x62, 0x3c, 0x28, 0x61, 0x2a, 0x63, 0x29, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, +0x20, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x62, 0x2f, 0x61, 0x29, +0x2b, 0x22, 0x2e, 0x22, 0x2b, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, +0x28, 0x62, 0x25, 0x25, 0x61, 0x29, 0x2f, 0x31, 0x30, 0x29, 0x2b, 0x22, 0x73, 0x22, 0x7d, 0x76, +0x61, 0x72, 0x20, 0x6b, 0x3d, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, +0x62, 0x2f, 0x28, 0x67, 0x2a, 0x61, 0x29, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x6b, 0x29, 0x7b, 0x6c, +0x2b, 0x3d, 0x6b, 0x2b, 0x22, 0x64, 0x20, 0x22, 0x7d, 0x76, 0x61, 0x72, 0x20, 0x69, 0x3d, 0x4d, +0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, 0x28, 0x62, 0x25, 0x25, 0x28, 0x67, +0x2a, 0x61, 0x29, 0x29, 0x2f, 0x28, 0x66, 0x2a, 0x61, 0x29, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x6b, +0x7c, 0x7c, 0x69, 0x29, 0x7b, 0x6c, 0x2b, 0x3d, 0x69, 0x2b, 0x22, 0x68, 0x20, 0x22, 0x7d, 0x76, +0x61, 0x72, 0x20, 0x65, 0x3d, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, 0x72, 0x28, +0x28, 0x28, 0x62, 0x25, 0x25, 0x28, 0x67, 0x2a, 0x61, 0x29, 0x29, 0x25, 0x25, 0x28, 0x66, 0x2a, +0x61, 0x29, 0x29, 0x2f, 0x28, 0x63, 0x2a, 0x61, 0x29, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x6b, 0x7c, +0x7c, 0x69, 0x7c, 0x7c, 0x65, 0x29, 0x7b, 0x6c, 0x2b, 0x3d, 0x65, 0x2b, 0x22, 0x6d, 0x20, 0x22, +0x7d, 0x76, 0x61, 0x72, 0x20, 0x6a, 0x3d, 0x4d, 0x61, 0x74, 0x68, 0x2e, 0x66, 0x6c, 0x6f, 0x6f, +0x72, 0x28, 0x28, 0x28, 0x28, 0x62, 0x25, 0x25, 0x28, 0x67, 0x2a, 0x61, 0x29, 0x29, 0x25, 0x25, +0x28, 0x66, 0x2a, 0x61, 0x29, 0x29, 0x25, 0x25, 0x28, 0x63, 0x2a, 0x61, 0x29, 0x29, 0x2f, 0x61, +0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x2b, 0x6a, 0x2b, 0x22, 0x73, 0x22, +0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x54, 0x68, 0x28, 0x61, 0x29, +0x7b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x31, 0x30, 0x32, 0x34, 0x3b, 0x69, 0x66, 0x28, 0x74, +0x79, 0x70, 0x65, 0x6f, 0x66, 0x20, 0x61, 0x21, 0x3d, 0x3d, 0x22, 0x6e, 0x75, 0x6d, 0x62, 0x65, +0x72, 0x22, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x7d, 0x69, 0x66, 0x28, +0x61, 0x3c, 0x63, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x2b, 0x22, 0x20, +0x42, 0x22, 0x7d, 0x69, 0x66, 0x28, 0x61, 0x3c, 0x28, 0x63, 0x2a, 0x63, 0x29, 0x29, 0x7b, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6e, 0x28, 0x61, 0x2f, 0x63, 0x29, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, +0x65, 0x64, 0x28, 0x31, 0x29, 0x2b, 0x22, 0x20, 0x4b, 0x69, 0x42, 0x22, 0x7d, 0x69, 0x66, 0x28, +0x61, 0x3c, 0x28, 0x63, 0x2a, 0x63, 0x2a, 0x63, 0x29, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6e, 0x28, 0x61, 0x2f, 0x28, 0x63, 0x2a, 0x63, 0x29, 0x29, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, +0x65, 0x64, 0x28, 0x31, 0x29, 0x2b, 0x22, 0x20, 0x4d, 0x69, 0x42, 0x22, 0x7d, 0x69, 0x66, 0x28, +0x61, 0x3c, 0x28, 0x63, 0x2a, 0x63, 0x2a, 0x63, 0x2a, 0x63, 0x29, 0x29, 0x7b, 0x72, 0x65, 0x74, +0x75, 0x72, 0x6e, 0x28, 0x61, 0x2f, 0x28, 0x63, 0x2a, 0x63, 0x2a, 0x63, 0x29, 0x29, 0x2e, 0x74, +0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x32, 0x29, 0x2b, 0x22, 0x20, 0x47, 0x69, 0x42, 0x22, +0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x28, 0x61, 0x2f, 0x28, 0x63, 0x2a, 0x63, 0x2a, 0x63, +0x2a, 0x63, 0x29, 0x29, 0x2e, 0x74, 0x6f, 0x46, 0x69, 0x78, 0x65, 0x64, 0x28, 0x36, 0x29, 0x2b, +0x22, 0x20, 0x54, 0x69, 0x42, 0x22, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, +0x73, 0x54, 0x68, 0x28, 0x61, 0x2c, 0x65, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3b, 0x69, +0x66, 0x28, 0x21, 0x61, 0x26, 0x26, 0x21, 0x65, 0x29, 0x7b, 0x63, 0x3d, 0x22, 0x75, 0x70, 0x22, +0x7d, 0x65, 0x6c, 0x73, 0x65, 0x7b, 0x69, 0x66, 0x28, 0x65, 0x29, 0x7b, 0x63, 0x3d, 0x22, 0x64, +0x6f, 0x77, 0x6e, 0x22, 0x7d, 0x65, 0x6c, 0x73, 0x65, 0x7b, 0x63, 0x3d, 0x22, 0x62, 0x61, 0x63, +0x6b, 0x75, 0x70, 0x22, 0x7d, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x63, 0x7d, 0x66, +0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x73, 0x48, 0x65, 0x28, 0x62, 0x2c, 0x61, 0x29, +0x7b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x62, 0x2e, 0x73, 0x70, 0x6c, 0x69, 0x74, 0x28, 0x22, +0x20, 0x22, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x22, 0x3c, 0x22, 0x2b, 0x62, 0x2b, +0x22, 0x3e, 0x22, 0x2b, 0x28, 0x61, 0x29, 0x2b, 0x22, 0x3c, 0x2f, 0x22, 0x2b, 0x63, 0x5b, 0x30, +0x5d, 0x2b, 0x22, 0x3e, 0x22, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x61, +0x48, 0x65, 0x28, 0x63, 0x2c, 0x61, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x62, 0x3b, 0x76, 0x61, +0x72, 0x20, 0x64, 0x3d, 0x22, 0x22, 0x3b, 0x69, 0x66, 0x28, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, +0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x74, 0x6f, 0x53, 0x74, 0x72, +0x69, 0x6e, 0x67, 0x2e, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x61, 0x29, 0x3d, 0x3d, 0x3d, 0x22, 0x5b, +0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x41, 0x72, 0x72, 0x61, 0x79, 0x5d, 0x22, 0x29, 0x7b, +0x66, 0x6f, 0x72, 0x28, 0x62, 0x3d, 0x30, 0x3b, 0x62, 0x3c, 0x61, 0x2e, 0x6c, 0x65, 0x6e, 0x67, +0x74, 0x68, 0x3b, 0x62, 0x2b, 0x2b, 0x29, 0x7b, 0x64, 0x2b, 0x3d, 0x73, 0x48, 0x65, 0x28, 0x63, +0x2c, 0x61, 0x5b, 0x62, 0x5d, 0x29, 0x7d, 0x7d, 0x65, 0x6c, 0x73, 0x65, 0x7b, 0x64, 0x3d, 0x73, +0x48, 0x65, 0x28, 0x63, 0x2c, 0x61, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, +0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, +0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x28, 0x61, +0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x62, 0x3d, 0x5b, 0x5d, 0x3b, 0x62, 0x5b, 0x30, 0x5d, 0x3d, +0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, +0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, +0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0x29, 0x2c, 0x61, +0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, +0x33, 0x22, 0x27, 0x2c, 0x22, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x29, 0x2c, +0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, +0x22, 0x36, 0x22, 0x27, 0x2c, 0x22, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, +0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, +0x6e, 0x3d, 0x22, 0x34, 0x22, 0x27, 0x2c, 0x22, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x22, +0x29, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x61, 0x29, 0x7b, 0x62, 0x5b, 0x30, 0x5d, 0x3d, 0x22, 0x7b, +0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x62, 0x5b, 0x30, 0x5d, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, +0x3d, 0x22, 0x39, 0x22, 0x27, 0x2c, 0x22, 0x43, 0x61, 0x63, 0x68, 0x65, 0x22, 0x29, 0x29, 0x7d, +0x62, 0x5b, 0x31, 0x5d, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x22, 0x2c, 0x5b, 0x22, +0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x22, 0x52, 0x65, 0x71, 0x2f, 0x73, 0x22, 0x2c, 0x22, +0x54, 0x69, 0x6d, 0x65, 0x22, 0x2c, 0x22, 0x31, 0x78, 0x78, 0x22, 0x2c, 0x22, 0x32, 0x78, 0x78, +0x22, 0x2c, 0x22, 0x33, 0x78, 0x78, 0x22, 0x2c, 0x22, 0x34, 0x78, 0x78, 0x22, 0x2c, 0x22, 0x35, +0x78, 0x78, 0x22, 0x2c, 0x22, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x6e, +0x74, 0x22, 0x2c, 0x22, 0x52, 0x63, 0x76, 0x64, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x6e, 0x74, 0x2f, +0x73, 0x22, 0x2c, 0x22, 0x52, 0x63, 0x76, 0x64, 0x2f, 0x73, 0x22, 0x5d, 0x29, 0x3b, 0x69, 0x66, +0x28, 0x61, 0x29, 0x7b, 0x62, 0x5b, 0x31, 0x5d, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, +0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x62, 0x5b, 0x31, 0x5d, 0x2c, 0x61, 0x48, 0x65, 0x28, +0x22, 0x74, 0x68, 0x22, 0x2c, 0x5b, 0x22, 0x4d, 0x69, 0x73, 0x73, 0x22, 0x2c, 0x22, 0x42, 0x79, +0x70, 0x61, 0x73, 0x73, 0x22, 0x2c, 0x22, 0x45, 0x78, 0x70, 0x69, 0x72, 0x65, 0x64, 0x22, 0x2c, +0x22, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x55, 0x70, 0x64, 0x61, 0x74, 0x69, 0x6e, +0x67, 0x22, 0x2c, 0x22, 0x52, 0x65, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x22, +0x2c, 0x22, 0x48, 0x69, 0x74, 0x22, 0x2c, 0x22, 0x53, 0x63, 0x61, 0x72, 0x63, 0x65, 0x22, 0x2c, +0x22, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x5d, 0x29, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, +0x6e, 0x20, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x65, 0x61, 0x64, 0x22, 0x2c, 0x22, 0x7b, +0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, +0x22, 0x74, 0x72, 0x22, 0x2c, 0x62, 0x5b, 0x30, 0x5d, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, +0x74, 0x72, 0x22, 0x2c, 0x62, 0x5b, 0x31, 0x5d, 0x29, 0x29, 0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, +0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x55, 0x70, 0x73, +0x74, 0x72, 0x65, 0x61, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x28, 0x29, 0x7b, 0x76, 0x61, +0x72, 0x20, 0x61, 0x3d, 0x5b, 0x5d, 0x3b, 0x61, 0x5b, 0x30, 0x5d, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, +0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, +0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, +0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x53, 0x65, +0x72, 0x76, 0x65, 0x72, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, +0x6f, 0x77, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x53, 0x74, 0x61, +0x74, 0x65, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, +0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x52, 0x65, 0x73, 0x70, 0x6f, +0x6e, 0x73, 0x65, 0x20, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, +0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, +0x22, 0x57, 0x65, 0x69, 0x67, 0x68, 0x74, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, +0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, +0x4d, 0x61, 0x78, 0x46, 0x61, 0x69, 0x6c, 0x73, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, +0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, +0x22, 0x46, 0x61, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x22, 0x29, 0x2c, 0x61, +0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, +0x33, 0x22, 0x27, 0x2c, 0x22, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x22, 0x29, 0x2c, +0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, +0x22, 0x36, 0x22, 0x27, 0x2c, 0x22, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x22, +0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, +0x6e, 0x3d, 0x22, 0x34, 0x22, 0x27, 0x2c, 0x22, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x22, +0x29, 0x29, 0x3b, 0x61, 0x5b, 0x31, 0x5d, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x22, +0x2c, 0x5b, 0x22, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x22, 0x52, 0x65, 0x71, 0x2f, 0x73, +0x22, 0x2c, 0x22, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x2c, 0x22, 0x31, 0x78, 0x78, 0x22, 0x2c, 0x22, +0x32, 0x78, 0x78, 0x22, 0x2c, 0x22, 0x33, 0x78, 0x78, 0x22, 0x2c, 0x22, 0x34, 0x78, 0x78, 0x22, +0x2c, 0x22, 0x35, 0x78, 0x78, 0x22, 0x2c, 0x22, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x2c, 0x22, +0x53, 0x65, 0x6e, 0x74, 0x22, 0x2c, 0x22, 0x52, 0x63, 0x76, 0x64, 0x22, 0x2c, 0x22, 0x53, 0x65, +0x6e, 0x74, 0x2f, 0x73, 0x22, 0x2c, 0x22, 0x52, 0x63, 0x76, 0x64, 0x2f, 0x73, 0x22, 0x5d, 0x29, +0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x65, +0x61, 0x64, 0x22, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, +0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x61, 0x5b, 0x30, 0x5d, 0x29, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x61, 0x5b, 0x31, 0x5d, 0x29, 0x29, +0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, +0x61, 0x74, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x28, 0x29, +0x7b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x5b, 0x5d, 0x3b, 0x61, 0x5b, 0x30, 0x5d, 0x3d, 0x22, +0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, +0x28, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, 0x6e, +0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x5a, 0x6f, 0x6e, 0x65, 0x22, 0x29, 0x2c, 0x61, 0x48, +0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, +0x22, 0x27, 0x2c, 0x22, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, +0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x27, 0x2c, +0x22, 0x54, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, +0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x39, 0x22, 0x27, 0x2c, +0x22, 0x43, 0x61, 0x63, 0x68, 0x65, 0x22, 0x29, 0x29, 0x3b, 0x61, 0x5b, 0x31, 0x5d, 0x3d, 0x61, +0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x22, 0x2c, 0x5b, 0x22, 0x43, 0x61, 0x70, 0x61, 0x63, 0x69, +0x74, 0x79, 0x22, 0x2c, 0x22, 0x55, 0x73, 0x65, 0x64, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x6e, 0x74, +0x22, 0x2c, 0x22, 0x52, 0x63, 0x76, 0x64, 0x22, 0x2c, 0x22, 0x53, 0x65, 0x6e, 0x74, 0x2f, 0x73, +0x22, 0x2c, 0x22, 0x52, 0x63, 0x76, 0x64, 0x2f, 0x73, 0x22, 0x2c, 0x22, 0x4d, 0x69, 0x73, 0x73, +0x22, 0x2c, 0x22, 0x42, 0x79, 0x70, 0x61, 0x73, 0x73, 0x22, 0x2c, 0x22, 0x45, 0x78, 0x70, 0x69, +0x72, 0x65, 0x64, 0x22, 0x2c, 0x22, 0x53, 0x74, 0x61, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x55, 0x70, +0x64, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x22, 0x52, 0x65, 0x76, 0x61, 0x6c, 0x69, 0x64, +0x61, 0x74, 0x65, 0x64, 0x22, 0x2c, 0x22, 0x48, 0x69, 0x74, 0x22, 0x2c, 0x22, 0x53, 0x63, 0x61, +0x72, 0x63, 0x65, 0x22, 0x2c, 0x22, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x5d, 0x29, 0x3b, 0x72, +0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x65, 0x61, 0x64, +0x22, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x61, 0x5b, 0x30, 0x5d, 0x29, 0x2c, 0x61, +0x48, 0x65, 0x28, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x61, 0x5b, 0x31, 0x5d, 0x29, 0x29, 0x29, 0x7d, +0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, +0x65, 0x4d, 0x61, 0x69, 0x6e, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x64, 0x29, 0x7b, 0x76, 0x61, 0x72, +0x20, 0x66, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x22, 0x22, 0x3b, 0x76, +0x61, 0x72, 0x20, 0x61, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x5b, 0x5d, +0x3b, 0x76, 0x61, 0x72, 0x20, 0x62, 0x3d, 0x5b, 0x5d, 0x3b, 0x65, 0x5b, 0x30, 0x5d, 0x3d, 0x22, +0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, +0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, +0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x48, 0x6f, 0x73, 0x74, 0x22, +0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, +0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, +0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x72, 0x6f, 0x77, 0x73, 0x70, 0x61, +0x6e, 0x3d, 0x22, 0x32, 0x22, 0x27, 0x2c, 0x22, 0x55, 0x70, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x29, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, 0x73, 0x70, 0x61, 0x6e, +0x3d, 0x22, 0x34, 0x22, 0x27, 0x2c, 0x22, 0x43, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, +0x6e, 0x73, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, 0x6c, +0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x27, 0x2c, 0x22, 0x52, 0x65, 0x71, 0x75, 0x65, +0x73, 0x74, 0x73, 0x22, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x68, 0x20, 0x63, 0x6f, +0x6c, 0x73, 0x70, 0x61, 0x6e, 0x3d, 0x22, 0x34, 0x22, 0x27, 0x2c, 0x22, 0x53, 0x68, 0x61, 0x72, +0x65, 0x64, 0x20, 0x6d, 0x65, 0x6d, 0x6f, 0x72, 0x79, 0x22, 0x29, 0x29, 0x3b, 0x65, 0x5b, 0x31, +0x5d, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x22, 0x2c, 0x5b, 0x22, 0x61, 0x63, 0x74, +0x69, 0x76, 0x65, 0x22, 0x2c, 0x22, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x22, +0x77, 0x72, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x22, 0x2c, 0x22, 0x77, 0x61, 0x69, 0x74, 0x69, 0x6e, +0x67, 0x22, 0x2c, 0x22, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x22, 0x2c, 0x22, 0x68, +0x61, 0x6e, 0x64, 0x6c, 0x65, 0x64, 0x22, 0x2c, 0x22, 0x54, 0x6f, 0x74, 0x61, 0x6c, 0x22, 0x2c, +0x22, 0x52, 0x65, 0x71, 0x2f, 0x73, 0x22, 0x2c, 0x22, 0x6e, 0x61, 0x6d, 0x65, 0x22, 0x2c, 0x22, +0x6d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x22, 0x2c, 0x22, 0x75, 0x73, 0x65, 0x64, 0x53, 0x69, +0x7a, 0x65, 0x22, 0x2c, 0x22, 0x75, 0x73, 0x65, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x22, 0x5d, 0x29, +0x3b, 0x63, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x65, 0x61, 0x64, 0x22, 0x2c, 0x22, +0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, +0x28, 0x22, 0x74, 0x72, 0x22, 0x2c, 0x65, 0x5b, 0x30, 0x5d, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, +0x22, 0x74, 0x72, 0x22, 0x2c, 0x65, 0x5b, 0x31, 0x5d, 0x29, 0x29, 0x29, 0x3b, 0x62, 0x5b, 0x30, +0x5d, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x5b, 0x61, 0x48, 0x65, 0x28, +0x22, 0x73, 0x74, 0x72, 0x6f, 0x6e, 0x67, 0x22, 0x2c, 0x64, 0x2e, 0x68, 0x6f, 0x73, 0x74, 0x4e, +0x61, 0x6d, 0x65, 0x29, 0x2c, 0x64, 0x2e, 0x6e, 0x67, 0x69, 0x6e, 0x78, 0x56, 0x65, 0x72, 0x73, +0x69, 0x6f, 0x6e, 0x2c, 0x6d, 0x54, 0x68, 0x28, 0x64, 0x2e, 0x6e, 0x6f, 0x77, 0x4d, 0x73, 0x65, +0x63, 0x2d, 0x64, 0x2e, 0x6c, 0x6f, 0x61, 0x64, 0x4d, 0x73, 0x65, 0x63, 0x29, 0x2c, 0x64, 0x2e, +0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x61, 0x63, 0x74, 0x69, +0x76, 0x65, 0x2c, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, +0x2e, 0x72, 0x65, 0x61, 0x64, 0x69, 0x6e, 0x67, 0x2c, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x77, 0x72, 0x69, 0x74, 0x69, 0x6e, 0x67, 0x2c, 0x64, +0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x77, 0x61, 0x69, +0x74, 0x69, 0x6e, 0x67, 0x2c, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, +0x6e, 0x73, 0x2e, 0x61, 0x63, 0x63, 0x65, 0x70, 0x74, 0x65, 0x64, 0x2c, 0x64, 0x2e, 0x63, 0x6f, +0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, +0x64, 0x2c, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, +0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x2c, 0x61, 0x50, 0x73, 0x2e, 0x67, 0x65, 0x74, +0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x6d, 0x61, 0x69, 0x6e, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, +0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, +0x22, 0x2c, 0x64, 0x2e, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, +0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x73, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x73, +0x74, 0x72, 0x6f, 0x6e, 0x67, 0x22, 0x2c, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5a, +0x6f, 0x6e, 0x65, 0x73, 0x2e, 0x6e, 0x61, 0x6d, 0x65, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x64, +0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x78, +0x53, 0x69, 0x7a, 0x65, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x72, +0x65, 0x64, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x2e, 0x75, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, +0x29, 0x2c, 0x64, 0x2e, 0x73, 0x68, 0x61, 0x72, 0x65, 0x64, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x2e, +0x75, 0x73, 0x65, 0x64, 0x4e, 0x6f, 0x64, 0x65, 0x5d, 0x29, 0x3b, 0x61, 0x3d, 0x61, 0x48, 0x65, +0x28, 0x22, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x72, +0x22, 0x2c, 0x62, 0x5b, 0x30, 0x5d, 0x29, 0x29, 0x3b, 0x66, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, +0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x22, 0x68, 0x32, +0x22, 0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, +0x74, 0x69, 0x74, 0x6c, 0x65, 0x73, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x29, 0x2c, 0x61, 0x48, 0x65, +0x28, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, +0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x63, 0x2c, 0x61, 0x29, 0x29, 0x29, 0x3b, 0x66, 0x3d, +0x61, 0x48, 0x65, 0x28, 0x27, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x22, +0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, +0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x6d, 0x61, 0x69, 0x6e, 0x29, +0x2c, 0x66, 0x29, 0x3b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x66, 0x7d, 0x66, 0x75, 0x6e, +0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, +0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x66, 0x2c, 0x65, 0x2c, 0x6b, 0x2c, 0x68, +0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x6d, 0x3d, 0x30, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x67, 0x3d, +0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x3d, 0x22, 0x22, 0x3b, 0x66, 0x6f, 0x72, 0x28, +0x76, 0x61, 0x72, 0x20, 0x76, 0x20, 0x69, 0x6e, 0x20, 0x66, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, +0x72, 0x3d, 0x66, 0x5b, 0x76, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6a, 0x3d, 0x22, 0x7b, 0x7d, +0x2e, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6b, +0x2c, 0x65, 0x2c, 0x76, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x62, 0x3d, 0x22, 0x22, 0x3b, 0x76, +0x61, 0x72, 0x20, 0x71, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x64, 0x3d, 0x30, 0x3b, +0x76, 0x61, 0x72, 0x20, 0x75, 0x3d, 0x30, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x30, 0x3b, +0x76, 0x61, 0x72, 0x20, 0x74, 0x3d, 0x30, 0x3b, 0x62, 0x3d, 0x28, 0x6d, 0x2b, 0x2b, 0x25, 0x25, +0x32, 0x29, 0x3f, 0x22, 0x6f, 0x64, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x3b, 0x71, 0x3d, 0x28, 0x65, +0x2e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x4f, 0x66, 0x28, 0x22, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x72, +0x79, 0x22, 0x29, 0x21, 0x3d, 0x2d, 0x31, 0x26, 0x26, 0x76, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, +0x68, 0x3d, 0x3d, 0x32, 0x29, 0x3f, 0x27, 0x3c, 0x69, 0x6d, 0x67, 0x20, 0x63, 0x6c, 0x61, 0x73, +0x73, 0x3d, 0x22, 0x66, 0x6c, 0x61, 0x67, 0x20, 0x66, 0x6c, 0x61, 0x67, 0x2d, 0x7b, 0x7d, 0x22, +0x20, 0x2f, 0x3e, 0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x76, 0x2e, 0x74, 0x6f, +0x4c, 0x6f, 0x77, 0x65, 0x72, 0x43, 0x61, 0x73, 0x65, 0x28, 0x29, 0x29, 0x3a, 0x22, 0x22, 0x3b, +0x67, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x22, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, +0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x71, 0x2c, 0x76, 0x29, 0x29, 0x2c, 0x61, 0x48, 0x65, +0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x5b, 0x28, 0x72, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, +0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x2b, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, +0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, +0x53, 0x69, 0x7a, 0x65, 0x2a, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, +0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, +0x29, 0x2c, 0x61, 0x50, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, +0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6a, 0x2c, +0x22, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, +0x29, 0x2c, 0x72, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, +0x65, 0x72, 0x29, 0x2c, 0x6d, 0x54, 0x68, 0x28, 0x72, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, +0x74, 0x4d, 0x73, 0x65, 0x63, 0x29, 0x5d, 0x29, 0x29, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, +0x72, 0x20, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, +0x65, 0x73, 0x29, 0x7b, 0x64, 0x3d, 0x72, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, +0x73, 0x5b, 0x61, 0x5d, 0x2b, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, +0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, +0x2a, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5b, 0x61, 0x5d, +0x3b, 0x75, 0x2b, 0x3d, 0x64, 0x3b, 0x67, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, +0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x67, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, +0x2c, 0x64, 0x29, 0x29, 0x3b, 0x69, 0x66, 0x28, 0x61, 0x3d, 0x3d, 0x22, 0x35, 0x78, 0x78, 0x22, +0x29, 0x7b, 0x62, 0x72, 0x65, 0x61, 0x6b, 0x7d, 0x7d, 0x67, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, +0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x67, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, +0x74, 0x64, 0x22, 0x2c, 0x5b, 0x75, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x72, 0x2e, 0x6f, 0x75, 0x74, +0x42, 0x79, 0x74, 0x65, 0x73, 0x2b, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, +0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, +0x65, 0x2a, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6f, +0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x72, 0x2e, 0x69, +0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2b, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, +0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x53, 0x69, +0x7a, 0x65, 0x2a, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, +0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x61, 0x50, 0x73, +0x2e, 0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, +0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6a, 0x2c, 0x22, 0x6f, 0x75, 0x74, 0x42, +0x79, 0x74, 0x65, 0x73, 0x22, 0x29, 0x2c, 0x72, 0x2e, 0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, +0x73, 0x29, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x61, 0x50, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x56, +0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, +0x6d, 0x61, 0x74, 0x28, 0x6a, 0x2c, 0x22, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x29, +0x2c, 0x72, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x29, 0x5d, 0x29, 0x29, 0x3b, +0x69, 0x66, 0x28, 0x68, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x70, 0x3d, 0x30, 0x3b, 0x66, 0x6f, +0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x2e, 0x72, 0x65, 0x73, +0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x29, 0x7b, 0x69, 0x66, 0x28, 0x70, 0x2b, 0x2b, 0x3c, 0x35, +0x29, 0x7b, 0x63, 0x6f, 0x6e, 0x74, 0x69, 0x6e, 0x75, 0x65, 0x7d, 0x63, 0x3d, 0x28, 0x72, 0x2e, +0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x5b, 0x61, 0x5d, 0x2b, 0x72, 0x2e, 0x6f, +0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, +0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x72, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, +0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5b, 0x61, 0x5d, 0x29, 0x3b, 0x74, 0x2b, 0x3d, 0x63, 0x3b, 0x67, +0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x67, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x63, 0x29, 0x29, 0x7d, 0x67, 0x3d, +0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x67, 0x2c, +0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x74, 0x29, 0x29, 0x7d, 0x6c, 0x3d, 0x22, +0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6c, 0x2c, 0x61, +0x48, 0x65, 0x28, 0x27, 0x74, 0x72, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x7b, 0x7d, +0x22, 0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x62, 0x29, 0x2c, 0x67, 0x29, 0x29, +0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x6c, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, +0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x55, 0x70, 0x73, 0x74, 0x72, +0x65, 0x61, 0x6d, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x63, 0x2c, 0x69, 0x2c, 0x62, 0x29, 0x7b, 0x76, +0x61, 0x72, 0x20, 0x65, 0x3d, 0x30, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x3d, 0x22, 0x22, 0x3b, +0x76, 0x61, 0x72, 0x20, 0x64, 0x3d, 0x22, 0x22, 0x3b, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x28, 0x65, +0x3c, 0x63, 0x2e, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x66, +0x3d, 0x63, 0x5b, 0x65, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x3d, 0x22, 0x7b, 0x7d, 0x2e, +0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x62, 0x2c, +0x69, 0x2c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, +0x6a, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x67, 0x3d, 0x30, 0x3b, 0x76, 0x61, 0x72, +0x20, 0x68, 0x3d, 0x30, 0x3b, 0x6a, 0x3d, 0x28, 0x65, 0x2b, 0x2b, 0x25, 0x25, 0x32, 0x29, 0x3f, +0x22, 0x6f, 0x64, 0x64, 0x22, 0x3a, 0x22, 0x22, 0x3b, 0x6c, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, +0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, +0x22, 0x2c, 0x66, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, +0x22, 0x74, 0x64, 0x22, 0x2c, 0x5b, 0x73, 0x54, 0x68, 0x28, 0x66, 0x2e, 0x62, 0x61, 0x63, 0x6b, +0x75, 0x70, 0x2c, 0x66, 0x2e, 0x64, 0x6f, 0x77, 0x6e, 0x29, 0x2c, 0x6d, 0x54, 0x68, 0x28, 0x66, +0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x4d, 0x73, 0x65, 0x63, 0x29, 0x2c, 0x66, +0x2e, 0x77, 0x65, 0x69, 0x67, 0x68, 0x74, 0x2c, 0x66, 0x2e, 0x6d, 0x61, 0x78, 0x46, 0x61, 0x69, +0x6c, 0x73, 0x2c, 0x66, 0x2e, 0x66, 0x61, 0x69, 0x6c, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, +0x2c, 0x28, 0x66, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, +0x65, 0x72, 0x2b, 0x66, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, +0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x66, +0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x72, 0x65, 0x71, 0x75, +0x65, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x29, 0x2c, 0x61, 0x50, 0x73, 0x2e, +0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, +0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6b, 0x2c, 0x22, 0x72, 0x65, 0x71, 0x75, 0x65, +0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x22, 0x29, 0x2c, 0x66, 0x2e, 0x72, 0x65, +0x71, 0x75, 0x65, 0x73, 0x74, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x65, 0x72, 0x29, 0x2c, 0x6d, 0x54, +0x68, 0x28, 0x66, 0x2e, 0x72, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x4d, 0x73, 0x65, 0x63, 0x29, +0x5d, 0x29, 0x29, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x61, 0x20, 0x69, 0x6e, +0x20, 0x66, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x29, 0x7b, 0x67, 0x3d, +0x66, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x5b, 0x61, 0x5d, 0x2b, 0x66, +0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, +0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x66, 0x2e, 0x6f, 0x76, 0x65, +0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5b, 0x61, 0x5d, 0x3b, 0x68, 0x2b, 0x3d, 0x67, 0x3b, +0x6c, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +0x6c, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x67, 0x29, 0x29, 0x7d, 0x6c, +0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6c, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x5b, 0x68, 0x2c, 0x62, 0x54, 0x68, +0x28, 0x66, 0x2e, 0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2b, 0x66, 0x2e, 0x6f, 0x76, +0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, +0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x66, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, +0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x2c, 0x62, +0x54, 0x68, 0x28, 0x66, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2b, 0x66, 0x2e, 0x6f, +0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, +0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x66, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, +0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x2c, 0x62, +0x54, 0x68, 0x28, 0x61, 0x50, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, +0x22, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6b, +0x2c, 0x22, 0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x29, 0x2c, 0x66, 0x2e, 0x6f, +0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x61, 0x50, +0x73, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x7b, 0x7d, 0x2e, 0x7b, +0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6b, 0x2c, 0x22, 0x69, 0x6e, 0x42, +0x79, 0x74, 0x65, 0x73, 0x22, 0x29, 0x2c, 0x66, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, +0x29, 0x29, 0x5d, 0x29, 0x29, 0x3b, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, +0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x64, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x72, 0x20, +0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x7b, 0x7d, 0x22, 0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, +0x61, 0x74, 0x28, 0x6a, 0x29, 0x2c, 0x6c, 0x29, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, +0x20, 0x64, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, +0x6c, 0x61, 0x74, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x64, 0x2c, +0x69, 0x2c, 0x63, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x66, 0x3d, 0x30, 0x3b, 0x76, 0x61, 0x72, +0x20, 0x6d, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x65, 0x3d, 0x22, 0x22, 0x3b, 0x66, +0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x61, 0x20, 0x69, 0x6e, 0x20, 0x64, 0x29, 0x7b, 0x76, +0x61, 0x72, 0x20, 0x67, 0x3d, 0x64, 0x5b, 0x61, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6c, 0x3d, +0x22, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, +0x74, 0x28, 0x63, 0x2c, 0x69, 0x2c, 0x61, 0x29, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6b, 0x3d, 0x22, +0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x68, 0x3d, 0x30, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x6a, 0x3d, +0x30, 0x3b, 0x6b, 0x3d, 0x28, 0x66, 0x2b, 0x2b, 0x25, 0x25, 0x32, 0x29, 0x3f, 0x22, 0x6f, 0x64, +0x64, 0x22, 0x3a, 0x22, 0x22, 0x3b, 0x6d, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, +0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x68, 0x22, 0x2c, 0x61, +0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x5b, 0x62, 0x54, 0x68, 0x28, +0x67, 0x2e, 0x6d, 0x61, 0x78, 0x53, 0x69, 0x7a, 0x65, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x67, +0x2e, 0x75, 0x73, 0x65, 0x64, 0x53, 0x69, 0x7a, 0x65, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x67, +0x2e, 0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2b, 0x67, 0x2e, 0x6f, 0x76, 0x65, 0x72, +0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, 0x65, +0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x67, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, +0x74, 0x73, 0x2e, 0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x2c, 0x62, 0x54, 0x68, +0x28, 0x67, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x2b, 0x67, 0x2e, 0x6f, 0x76, 0x65, +0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, 0x6e, 0x74, 0x65, 0x67, +0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x67, 0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, +0x6e, 0x74, 0x73, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x2c, 0x62, 0x54, 0x68, +0x28, 0x61, 0x50, 0x73, 0x2e, 0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x7b, +0x7d, 0x2e, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6c, 0x2c, 0x22, +0x6f, 0x75, 0x74, 0x42, 0x79, 0x74, 0x65, 0x73, 0x22, 0x29, 0x2c, 0x67, 0x2e, 0x6f, 0x75, 0x74, +0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x29, 0x2c, 0x62, 0x54, 0x68, 0x28, 0x61, 0x50, 0x73, 0x2e, +0x67, 0x65, 0x74, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x28, 0x22, 0x7b, 0x7d, 0x2e, 0x7b, 0x7d, 0x22, +0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6c, 0x2c, 0x22, 0x69, 0x6e, 0x42, 0x79, 0x74, +0x65, 0x73, 0x22, 0x29, 0x2c, 0x67, 0x2e, 0x69, 0x6e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x29, 0x29, +0x5d, 0x29, 0x29, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, 0x62, 0x20, 0x69, 0x6e, +0x20, 0x67, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x29, 0x7b, 0x68, 0x3d, +0x67, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x5b, 0x62, 0x5d, 0x2b, 0x67, +0x2e, 0x6f, 0x76, 0x65, 0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x2e, 0x6d, 0x61, 0x78, 0x49, +0x6e, 0x74, 0x65, 0x67, 0x65, 0x72, 0x53, 0x69, 0x7a, 0x65, 0x2a, 0x67, 0x2e, 0x6f, 0x76, 0x65, +0x72, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x73, 0x5b, 0x62, 0x5d, 0x3b, 0x6a, 0x2b, 0x3d, 0x68, 0x3b, +0x6d, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +0x6d, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x68, 0x29, 0x29, 0x7d, 0x6d, +0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6d, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x64, 0x22, 0x2c, 0x6a, 0x29, 0x29, 0x3b, 0x65, 0x3d, +0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x65, 0x2c, +0x61, 0x48, 0x65, 0x28, 0x27, 0x74, 0x72, 0x20, 0x63, 0x6c, 0x61, 0x73, 0x73, 0x3d, 0x22, 0x7b, +0x7d, 0x22, 0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x6b, 0x29, 0x2c, 0x6d, 0x29, +0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x65, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, +0x69, 0x6f, 0x6e, 0x20, 0x68, 0x61, 0x76, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x28, 0x62, 0x29, +0x7b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x22, 0x2a, 0x22, 0x3b, 0x69, 0x66, 0x28, 0x74, 0x79, +0x70, 0x65, 0x6f, 0x66, 0x20, 0x62, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, +0x65, 0x73, 0x5b, 0x61, 0x5d, 0x3d, 0x3d, 0x22, 0x75, 0x6e, 0x64, 0x65, 0x66, 0x69, 0x6e, 0x65, +0x64, 0x22, 0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x72, 0x75, 0x65, 0x7d, +0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x6b, 0x65, +0x79, 0x73, 0x28, 0x62, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x73, +0x5b, 0x61, 0x5d, 0x2e, 0x72, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x73, 0x29, 0x2e, 0x6c, +0x65, 0x6e, 0x67, 0x74, 0x68, 0x3e, 0x35, 0x3f, 0x74, 0x72, 0x75, 0x65, 0x3a, 0x66, 0x61, 0x6c, +0x73, 0x65, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x65, 0x6d, 0x70, +0x6c, 0x61, 0x74, 0x65, 0x28, 0x65, 0x29, 0x7b, 0x61, 0x50, 0x73, 0x2e, 0x72, 0x65, 0x66, 0x72, +0x65, 0x73, 0x68, 0x28, 0x65, 0x2e, 0x6e, 0x6f, 0x77, 0x4d, 0x73, 0x65, 0x63, 0x29, 0x3b, 0x76, +0x61, 0x72, 0x20, 0x64, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x66, 0x3d, 0x22, 0x22, +0x3b, 0x76, 0x61, 0x72, 0x20, 0x68, 0x3d, 0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x67, 0x3d, +0x22, 0x22, 0x3b, 0x76, 0x61, 0x72, 0x20, 0x63, 0x3d, 0x5b, 0x5d, 0x3b, 0x76, 0x61, 0x72, 0x20, +0x61, 0x3d, 0x74, 0x72, 0x75, 0x65, 0x3b, 0x64, 0x3d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, +0x65, 0x4d, 0x61, 0x69, 0x6e, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x65, 0x29, 0x3b, 0x61, 0x3d, 0x68, +0x61, 0x76, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x28, 0x65, 0x29, 0x3b, 0x68, 0x3d, 0x74, 0x65, +0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, +0x65, 0x72, 0x28, 0x61, 0x29, 0x3b, 0x63, 0x5b, 0x30, 0x5d, 0x3d, 0x74, 0x65, 0x6d, 0x70, 0x6c, +0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x65, 0x2e, +0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x2c, 0x22, 0x73, 0x65, 0x72, +0x76, 0x65, 0x72, 0x22, 0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, +0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2c, 0x61, 0x29, +0x3b, 0x67, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x2c, 0x63, +0x5b, 0x30, 0x5d, 0x29, 0x3b, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, +0x72, 0x6d, 0x61, 0x74, 0x28, 0x64, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x64, 0x69, 0x76, 0x20, +0x69, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x22, 0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, 0x64, +0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x29, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, +0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x22, 0x68, 0x32, 0x22, +0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x74, +0x69, 0x74, 0x6c, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x29, 0x2c, 0x61, 0x48, +0x65, 0x28, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, +0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x68, 0x2c, 0x67, 0x29, 0x29, 0x29, 0x29, 0x29, +0x3b, 0x69, 0x66, 0x28, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, +0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, +0x65, 0x29, 0x7b, 0x66, 0x3d, 0x22, 0x22, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, 0x20, +0x69, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x5a, 0x6f, 0x6e, +0x65, 0x73, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x62, 0x3d, 0x65, 0x2e, 0x66, 0x69, 0x6c, 0x74, +0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x3b, 0x68, 0x3d, 0x74, 0x65, 0x6d, +0x70, 0x6c, 0x61, 0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x48, 0x65, 0x61, 0x64, 0x65, +0x72, 0x28, 0x61, 0x29, 0x3b, 0x63, 0x5b, 0x30, 0x5d, 0x3d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, +0x74, 0x65, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x62, 0x2c, 0x69, +0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, +0x64, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x2c, 0x61, 0x29, 0x3b, 0x67, 0x3d, 0x61, +0x48, 0x65, 0x28, 0x22, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x2c, 0x63, 0x5b, 0x30, 0x5d, 0x29, +0x3b, 0x66, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, +0x61, 0x74, 0x28, 0x66, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x68, 0x33, 0x22, 0x2c, 0x69, 0x29, +0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x7b, 0x7d, +0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x68, 0x2c, 0x67, 0x29, 0x29, +0x29, 0x7d, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, +0x74, 0x28, 0x64, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x27, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, +0x22, 0x7b, 0x7d, 0x22, 0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x76, 0x74, 0x73, +0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x66, +0x69, 0x6c, 0x74, 0x65, 0x72, 0x29, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, +0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, 0x48, 0x65, 0x28, 0x22, 0x68, 0x32, 0x22, 0x2c, 0x76, 0x74, +0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x74, 0x69, 0x74, 0x6c, +0x65, 0x73, 0x2e, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x29, 0x2c, 0x66, 0x29, 0x29, 0x29, 0x7d, +0x69, 0x66, 0x28, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, +0x2e, 0x69, 0x64, 0x73, 0x2e, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x20, 0x69, 0x6e, +0x20, 0x65, 0x29, 0x7b, 0x66, 0x3d, 0x22, 0x22, 0x3b, 0x66, 0x6f, 0x72, 0x28, 0x76, 0x61, 0x72, +0x20, 0x69, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x2e, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, +0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x62, 0x3d, 0x65, 0x2e, 0x75, +0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x5b, 0x69, 0x5d, 0x3b, +0x68, 0x3d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, +0x61, 0x6d, 0x48, 0x65, 0x61, 0x64, 0x65, 0x72, 0x28, 0x29, 0x3b, 0x63, 0x5b, 0x30, 0x5d, 0x3d, +0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x55, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, +0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x62, 0x2c, 0x69, 0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, +0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x75, 0x70, 0x73, 0x74, 0x72, +0x65, 0x61, 0x6d, 0x29, 0x3b, 0x67, 0x3d, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x62, 0x6f, 0x64, +0x79, 0x22, 0x2c, 0x63, 0x5b, 0x30, 0x5d, 0x29, 0x3b, 0x66, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, +0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x66, 0x2c, 0x61, 0x48, 0x65, +0x28, 0x22, 0x68, 0x33, 0x22, 0x2c, 0x69, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x61, +0x62, 0x6c, 0x65, 0x22, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, +0x61, 0x74, 0x28, 0x68, 0x2c, 0x67, 0x29, 0x29, 0x29, 0x7d, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x7b, +0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x64, 0x2c, 0x61, 0x48, 0x65, 0x28, +0x27, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x22, 0x27, 0x2e, 0x66, 0x6f, +0x72, 0x6d, 0x61, 0x74, 0x28, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, +0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x75, 0x70, 0x73, 0x74, 0x72, 0x65, 0x61, 0x6d, 0x29, +0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x61, +0x48, 0x65, 0x28, 0x22, 0x68, 0x32, 0x22, 0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, +0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x73, 0x2e, 0x75, 0x70, 0x73, +0x74, 0x72, 0x65, 0x61, 0x6d, 0x29, 0x2c, 0x66, 0x29, 0x29, 0x29, 0x7d, 0x69, 0x66, 0x28, 0x76, +0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, +0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x29, 0x7b, 0x68, 0x3d, 0x74, +0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x48, 0x65, 0x61, 0x64, +0x65, 0x72, 0x28, 0x29, 0x3b, 0x63, 0x5b, 0x30, 0x5d, 0x3d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, +0x74, 0x65, 0x43, 0x61, 0x63, 0x68, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x28, 0x65, 0x2e, 0x63, 0x61, +0x63, 0x68, 0x65, 0x5a, 0x6f, 0x6e, 0x65, 0x73, 0x2c, 0x22, 0x63, 0x61, 0x63, 0x68, 0x65, 0x22, +0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, +0x64, 0x73, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, 0x29, 0x3b, 0x67, 0x3d, 0x61, 0x48, 0x65, 0x28, +0x22, 0x74, 0x62, 0x6f, 0x64, 0x79, 0x22, 0x2c, 0x63, 0x5b, 0x30, 0x5d, 0x29, 0x3b, 0x64, 0x3d, +0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x64, 0x2c, +0x61, 0x48, 0x65, 0x28, 0x27, 0x64, 0x69, 0x76, 0x20, 0x69, 0x64, 0x3d, 0x22, 0x7b, 0x7d, 0x22, +0x27, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, +0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x69, 0x64, 0x73, 0x2e, 0x63, 0x61, 0x63, 0x68, 0x65, +0x29, 0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, +0x61, 0x48, 0x65, 0x28, 0x22, 0x68, 0x32, 0x22, 0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, +0x75, 0x73, 0x56, 0x61, 0x72, 0x73, 0x2e, 0x74, 0x69, 0x74, 0x6c, 0x65, 0x73, 0x2e, 0x63, 0x61, +0x63, 0x68, 0x65, 0x29, 0x2c, 0x61, 0x48, 0x65, 0x28, 0x22, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x22, +0x2c, 0x22, 0x7b, 0x7d, 0x7b, 0x7d, 0x22, 0x2e, 0x66, 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x28, 0x68, +0x2c, 0x67, 0x29, 0x29, 0x29, 0x29, 0x29, 0x7d, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x64, +0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x74, 0x73, 0x47, 0x65, 0x74, +0x44, 0x61, 0x74, 0x61, 0x28, 0x29, 0x7b, 0x76, 0x61, 0x72, 0x20, 0x61, 0x3d, 0x64, 0x6f, 0x63, +0x75, 0x6d, 0x65, 0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, +0x42, 0x79, 0x49, 0x64, 0x28, 0x22, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x22, 0x29, 0x3b, +0x76, 0x61, 0x72, 0x20, 0x62, 0x3d, 0x6e, 0x65, 0x77, 0x20, 0x58, 0x4d, 0x4c, 0x48, 0x74, 0x74, +0x70, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x3b, 0x62, 0x2e, 0x6f, 0x6e, 0x6c, 0x6f, 0x61, +0x64, 0x3d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x28, 0x29, 0x7b, 0x69, 0x66, 0x28, +0x74, 0x68, 0x69, 0x73, 0x2e, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x21, 0x3d, 0x32, 0x30, 0x30, +0x29, 0x7b, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x7d, 0x61, 0x2e, 0x69, 0x6e, 0x6e, 0x65, 0x72, +0x48, 0x54, 0x4d, 0x4c, 0x3d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x28, 0x4a, 0x53, +0x4f, 0x4e, 0x2e, 0x70, 0x61, 0x72, 0x73, 0x65, 0x28, 0x74, 0x68, 0x69, 0x73, 0x2e, 0x72, 0x65, +0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x54, 0x65, 0x78, 0x74, 0x29, 0x29, 0x7d, 0x3b, 0x62, 0x2e, +0x6f, 0x70, 0x65, 0x6e, 0x28, 0x22, 0x47, 0x45, 0x54, 0x22, 0x2c, 0x76, 0x74, 0x73, 0x53, 0x74, +0x61, 0x74, 0x75, 0x73, 0x55, 0x52, 0x49, 0x29, 0x3b, 0x62, 0x2e, 0x73, 0x65, 0x6e, 0x64, 0x28, +0x29, 0x7d, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x76, 0x74, 0x73, 0x53, 0x65, +0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x28, 0x61, 0x29, 0x7b, 0x63, 0x6c, 0x65, +0x61, 0x72, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x28, 0x76, 0x74, 0x73, 0x55, 0x70, +0x64, 0x61, 0x74, 0x65, 0x29, 0x3b, 0x76, 0x74, 0x73, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x3d, +0x73, 0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x28, 0x76, 0x74, 0x73, 0x47, +0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x2c, 0x61, 0x29, 0x7d, 0x64, 0x6f, 0x63, 0x75, 0x6d, 0x65, +0x6e, 0x74, 0x2e, 0x67, 0x65, 0x74, 0x45, 0x6c, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x42, 0x79, 0x49, +0x64, 0x28, 0x22, 0x6a, 0x73, 0x6f, 0x6e, 0x55, 0x72, 0x69, 0x22, 0x29, 0x2e, 0x68, 0x72, 0x65, +0x66, 0x3d, 0x76, 0x74, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x55, 0x52, 0x49, 0x3b, 0x76, +0x74, 0x73, 0x47, 0x65, 0x74, 0x44, 0x61, 0x74, 0x61, 0x28, 0x29, 0x3b, 0x76, 0x74, 0x73, 0x53, +0x65, 0x74, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x28, 0x76, 0x74, 0x73, 0x55, 0x70, +0x64, 0x61, 0x74, 0x65, 0x49, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x29, 0x3b, 0x3c, 0x2f, +0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x3e, 0x3c, 0x2f, 0x62, 0x6f, 0x64, 0x79, 0x3e, 0x3c, 0x2f, +0x68, 0x74, 0x6d, 0x6c, 0x3e, 0x0a, 0x00 +}; + + +#endif /* _NGX_HTTP_VTS_MODULE_HTML_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.c new file mode 100644 index 0000000..1688bee --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.c @@ -0,0 +1,704 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_filter.h" +#include "ngx_http_vhost_traffic_status_shm.h" +#include "ngx_http_vhost_traffic_status_node.h" + + +ngx_int_t +ngx_http_vhost_traffic_status_node_generate_key(ngx_pool_t *pool, + ngx_str_t *buf, ngx_str_t *dst, unsigned type) +{ + size_t len; + u_char *p; + + len = ngx_strlen(ngx_http_vhost_traffic_status_group_to_string(type)); + + buf->len = len + sizeof("@") - 1 + dst->len; + buf->data = ngx_pcalloc(pool, buf->len); + if (buf->data == NULL) { + *buf = *dst; + return NGX_ERROR; + } + + p = buf->data; + + p = ngx_cpymem(p, ngx_http_vhost_traffic_status_group_to_string(type), len); + *p++ = NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR; + p = ngx_cpymem(p, dst->data, dst->len); + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_node_position_key(ngx_str_t *buf, size_t pos) +{ + size_t n, c, len; + u_char *p, *s; + + n = buf->len + 1; + c = len = 0; + p = s = buf->data; + + while (--n) { + if (*p == NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR) { + if (pos == c) { + break; + } + s = (p + 1); + c++; + } + p++; + len = (p - s); + } + + if (pos > c || len == 0) { + return NGX_ERROR; + } + + buf->data = s; + buf->len = len; + + return NGX_OK; +} + + +void +ngx_http_vhost_traffic_status_find_name(ngx_http_request_t *r, + ngx_str_t *buf) +{ + ngx_http_core_srv_conf_t *cscf; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (vtscf->filter && vtscf->filter_host && r->headers_in.server.len) { + /* set the key by host header */ + *buf = r->headers_in.server; + + } else { + /* set the key by server_name variable */ + *buf = cscf->server_name; + + if (buf->len == 0) { + buf->len = 1; + buf->data = (u_char *) "_"; + } + } +} + + +ngx_rbtree_node_t * +ngx_http_vhost_traffic_status_find_node(ngx_http_request_t *r, + ngx_str_t *key, unsigned type, uint32_t key_hash) +{ + uint32_t hash; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + hash = key_hash; + + if (hash == 0) { + hash = ngx_crc32_short(key->data, key->len); + } + + if (vtscf->node_caches[type] != NULL) { + if (vtscf->node_caches[type]->key == hash) { + node = vtscf->node_caches[type]; + goto found; + } + } + + node = ngx_http_vhost_traffic_status_node_lookup(ctx->rbtree, key, hash); + +found: + + return node; +} + + +ngx_rbtree_node_t * +ngx_http_vhost_traffic_status_find_lru(ngx_http_request_t *r) +{ + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_shm_info_t *shm_info; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + node = NULL; + + /* disabled */ + if (ctx->filter_max_node == 0) { + return NULL; + } + + shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + + if (shm_info == NULL) { + return NULL; + } + + ngx_http_vhost_traffic_status_shm_info(r, shm_info); + + /* find */ + if (shm_info->filter_used_node >= ctx->filter_max_node) { + node = ngx_http_vhost_traffic_status_find_lru_node(r, NULL, ctx->rbtree->root); + } + + return node; +} + + +ngx_rbtree_node_t * +ngx_http_vhost_traffic_status_find_lru_node(ngx_http_request_t *r, + ngx_rbtree_node_t *a, ngx_rbtree_node_t *b) +{ + ngx_str_t filter; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (b != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &b->color; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) { + filter.data = vtsn->data; + filter.len = vtsn->len; + + (void) ngx_http_vhost_traffic_status_node_position_key(&filter, 1); + + if (ngx_http_vhost_traffic_status_filter_max_node_match(r, &filter) == NGX_OK) { + a = ngx_http_vhost_traffic_status_find_lru_node_cmp(r, a, b); + } + } + + a = ngx_http_vhost_traffic_status_find_lru_node(r, a, b->left); + a = ngx_http_vhost_traffic_status_find_lru_node(r, a, b->right); + } + + return a; +} + + +ngx_rbtree_node_t * +ngx_http_vhost_traffic_status_find_lru_node_cmp(ngx_http_request_t *r, + ngx_rbtree_node_t *a, ngx_rbtree_node_t *b) +{ + ngx_int_t ai, bi; + ngx_http_vhost_traffic_status_node_t *avtsn, *bvtsn; + ngx_http_vhost_traffic_status_node_time_queue_t *aq, *bq; + + if (a == NULL) { + return b; + } + + avtsn = (ngx_http_vhost_traffic_status_node_t *) &a->color; + bvtsn = (ngx_http_vhost_traffic_status_node_t *) &b->color; + + aq = &avtsn->stat_request_times; + bq = &bvtsn->stat_request_times; + + if (aq->front == aq->rear) { + return a; + } + + if (bq->front == bq->rear) { + return b; + } + + ai = ngx_http_vhost_traffic_status_node_time_queue_rear(aq); + bi = ngx_http_vhost_traffic_status_node_time_queue_rear(bq); + + return (aq->times[ai].time < bq->times[bi].time) ? a : b; +} + + +ngx_rbtree_node_t * +ngx_http_vhost_traffic_status_node_lookup(ngx_rbtree_t *rbtree, ngx_str_t *key, + uint32_t hash) +{ + ngx_int_t rc; + ngx_rbtree_node_t *node, *sentinel; + ngx_http_vhost_traffic_status_node_t *vtsn; + + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + + if (hash < node->key) { + node = node->left; + continue; + } + + if (hash > node->key) { + node = node->right; + continue; + } + + /* hash == node->key */ + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + rc = ngx_memn2cmp(key->data, vtsn->data, key->len, (size_t) vtsn->len); + if (rc == 0) { + return node; + } + + node = (rc < 0) ? node->left : node->right; + } + + return NULL; +} + + +void +ngx_http_vhost_traffic_status_node_zero(ngx_http_vhost_traffic_status_node_t *vtsn) +{ + vtsn->stat_request_counter = 0; + vtsn->stat_in_bytes = 0; + vtsn->stat_out_bytes = 0; + vtsn->stat_1xx_counter = 0; + vtsn->stat_2xx_counter = 0; + vtsn->stat_3xx_counter = 0; + vtsn->stat_4xx_counter = 0; + vtsn->stat_5xx_counter = 0; + + vtsn->stat_request_time_counter = 0; + vtsn->stat_request_time = 0; + + vtsn->stat_request_counter_oc = 0; + vtsn->stat_in_bytes_oc = 0; + vtsn->stat_out_bytes_oc = 0; + vtsn->stat_1xx_counter_oc = 0; + vtsn->stat_2xx_counter_oc = 0; + vtsn->stat_3xx_counter_oc = 0; + vtsn->stat_4xx_counter_oc = 0; + vtsn->stat_5xx_counter_oc = 0; + vtsn->stat_request_time_counter_oc = 0; + vtsn->stat_response_time_counter_oc = 0; + +#if (NGX_HTTP_CACHE) + vtsn->stat_cache_miss_counter = 0; + vtsn->stat_cache_bypass_counter = 0; + vtsn->stat_cache_expired_counter = 0; + vtsn->stat_cache_stale_counter = 0; + vtsn->stat_cache_updating_counter = 0; + vtsn->stat_cache_revalidated_counter = 0; + vtsn->stat_cache_hit_counter = 0; + vtsn->stat_cache_scarce_counter = 0; + + vtsn->stat_cache_miss_counter_oc = 0; + vtsn->stat_cache_bypass_counter_oc = 0; + vtsn->stat_cache_expired_counter_oc = 0; + vtsn->stat_cache_stale_counter_oc = 0; + vtsn->stat_cache_updating_counter_oc = 0; + vtsn->stat_cache_revalidated_counter_oc = 0; + vtsn->stat_cache_hit_counter_oc = 0; + vtsn->stat_cache_scarce_counter_oc = 0; +#endif + +} + + +void +ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_uint_t status = r->headers_out.status; + + /* init serverZone */ + ngx_http_vhost_traffic_status_node_zero(vtsn); + ngx_http_vhost_traffic_status_node_time_queue_init(&vtsn->stat_request_times); + ngx_http_vhost_traffic_status_node_histogram_bucket_init(r, &vtsn->stat_request_buckets); + + /* init upstreamZone */ + vtsn->stat_upstream.type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + vtsn->stat_upstream.response_time_counter = 0; + vtsn->stat_upstream.response_time = 0; + ngx_http_vhost_traffic_status_node_time_queue_init(&vtsn->stat_upstream.response_times); + ngx_http_vhost_traffic_status_node_histogram_bucket_init(r, + &vtsn->stat_upstream.response_buckets); + + /* set serverZone */ + vtsn->stat_request_counter = 1; + vtsn->stat_in_bytes = (ngx_atomic_uint_t) r->request_length; + vtsn->stat_out_bytes = (ngx_atomic_uint_t) r->connection->sent; + + ngx_http_vhost_traffic_status_add_rc(status, vtsn); + + vtsn->stat_request_time = (ngx_msec_t) ngx_http_vhost_traffic_status_request_time(r); + vtsn->stat_request_time_counter = (ngx_atomic_uint_t) vtsn->stat_request_time; + + ngx_http_vhost_traffic_status_node_time_queue_insert(&vtsn->stat_request_times, + vtsn->stat_request_time); + +#if (NGX_HTTP_CACHE) + if (r->upstream != NULL && r->upstream->cache_status != 0) { + ngx_http_vhost_traffic_status_add_cc(r->upstream->cache_status, vtsn); + } +#endif + +} + + +void +ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn) +{ + ngx_uint_t status; + ngx_msec_int_t ms; + ngx_http_vhost_traffic_status_node_t ovtsn; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + status = r->headers_out.status; + ovtsn = *vtsn; + + vtsn->stat_request_counter++; + vtsn->stat_in_bytes += (ngx_atomic_uint_t) r->request_length; + vtsn->stat_out_bytes += (ngx_atomic_uint_t) r->connection->sent; + + ngx_http_vhost_traffic_status_add_rc(status, vtsn); + + ms = ngx_http_vhost_traffic_status_request_time(r); + + vtsn->stat_request_time_counter += (ngx_atomic_uint_t) ms; + + ngx_http_vhost_traffic_status_node_time_queue_insert(&vtsn->stat_request_times, + ms); + + ngx_http_vhost_traffic_status_node_histogram_observe(&vtsn->stat_request_buckets, + ms); + + vtsn->stat_request_time = ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_request_times, vtscf->average_method, + vtscf->average_period); + +#if (NGX_HTTP_CACHE) + if (r->upstream != NULL && r->upstream->cache_status != 0) { + ngx_http_vhost_traffic_status_add_cc(r->upstream->cache_status, vtsn); + } +#endif + + ngx_http_vhost_traffic_status_add_oc((&ovtsn), vtsn); +} + + +void +ngx_http_vhost_traffic_status_node_time_queue_zero( + ngx_http_vhost_traffic_status_node_time_queue_t *q) +{ + ngx_memzero(q, sizeof(ngx_http_vhost_traffic_status_node_time_queue_t)); +} + + +void +ngx_http_vhost_traffic_status_node_time_queue_init( + ngx_http_vhost_traffic_status_node_time_queue_t *q) +{ + ngx_http_vhost_traffic_status_node_time_queue_zero(q); + q->rear = NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN - 1; + q->len = NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_node_time_queue_push( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_int_t x) +{ + if ((q->rear + 1) % q->len == q->front) { + return NGX_ERROR; + } + + q->times[q->rear].time = ngx_http_vhost_traffic_status_current_msec(); + q->times[q->rear].msec = x; + q->rear = (q->rear + 1) % q->len; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_node_time_queue_pop( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_http_vhost_traffic_status_node_time_t *x) +{ + if (q->front == q->rear) { + return NGX_ERROR; + } + + *x = q->times[q->front]; + q->front = (q->front + 1) % q->len; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_node_time_queue_rear( + ngx_http_vhost_traffic_status_node_time_queue_t *q) +{ + return (q->rear > 0) ? (q->rear - 1) : (NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN - 1); +} + + +void +ngx_http_vhost_traffic_status_node_time_queue_insert( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_int_t x) +{ + ngx_int_t rc; + ngx_http_vhost_traffic_status_node_time_t rx; + rc = ngx_http_vhost_traffic_status_node_time_queue_pop(q, &rx) + | ngx_http_vhost_traffic_status_node_time_queue_push(q, x); + + if (rc != NGX_OK) { + ngx_http_vhost_traffic_status_node_time_queue_init(q); + } +} + + +ngx_msec_t +ngx_http_vhost_traffic_status_node_time_queue_average( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_int_t method, ngx_msec_t period) +{ + ngx_msec_t avg; + + if (method == NGX_HTTP_VHOST_TRAFFIC_STATUS_AVERAGE_METHOD_AMM) { + avg = ngx_http_vhost_traffic_status_node_time_queue_amm(q, period); + } else { + avg = ngx_http_vhost_traffic_status_node_time_queue_wma(q, period); + } + + return avg; +} + + +ngx_msec_t +ngx_http_vhost_traffic_status_node_time_queue_amm( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_t period) +{ + ngx_int_t i, j, k; + ngx_msec_t x, current_msec; + + current_msec = ngx_http_vhost_traffic_status_current_msec(); + + x = period ? (current_msec - period) : 0; + + for (i = q->front, j = 1, k = 0; i != q->rear; i = (i + 1) % q->len, j++) { + if (x < q->times[i].time) { + k += (ngx_int_t) q->times[i].msec; + } + } + + if (j != q->len) { + ngx_http_vhost_traffic_status_node_time_queue_init(q); + } + + return (ngx_msec_t) (k / (q->len - 1)); +} + + +ngx_msec_t +ngx_http_vhost_traffic_status_node_time_queue_wma( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_t period) +{ + ngx_int_t i, j, k; + ngx_msec_t x, current_msec; + + current_msec = ngx_http_vhost_traffic_status_current_msec(); + + x = period ? (current_msec - period) : 0; + + for (i = q->front, j = 1, k = 0; i != q->rear; i = (i + 1) % q->len, j++) { + if (x < q->times[i].time) { + k += (ngx_int_t) q->times[i].msec * j; + } + } + + if (j != q->len) { + ngx_http_vhost_traffic_status_node_time_queue_init(q); + } + + return (ngx_msec_t) + (k / (ngx_int_t) ngx_http_vhost_traffic_status_triangle((q->len - 1))); +} + + +void +ngx_http_vhost_traffic_status_node_time_queue_merge( + ngx_http_vhost_traffic_status_node_time_queue_t *a, + ngx_http_vhost_traffic_status_node_time_queue_t *b, + ngx_msec_t period) +{ + ngx_int_t i; + ngx_msec_t x, current_msec; + + current_msec = ngx_http_vhost_traffic_status_current_msec(); + + x = period ? (current_msec - period) : 0; + + for (i = a->front; i != a->rear; i = (i + 1) % a->len) { + a->times[i].time = (a->times[i].time > b->times[i].time) + ? a->times[i].time + : b->times[i].time; + + if (x < a->times[i].time) { + a->times[i].msec = (a->times[i].msec + b->times[i].msec) / 2 + + (a->times[i].msec + b->times[i].msec) % 2; + + } else { + a->times[i].msec = 0; + } + } +} + + +void +ngx_http_vhost_traffic_status_node_histogram_bucket_init(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b) +{ + ngx_uint_t i, n; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_node_histogram_t *buckets; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (vtscf->histogram_buckets == NULL) { + b->len = 0; + return; + } + + buckets = vtscf->histogram_buckets->elts; + n = vtscf->histogram_buckets->nelts; + b->len = n; + + for (i = 0; i < n; i++) { + b->buckets[i].msec = buckets[i].msec; + b->buckets[i].counter = 0; + } +} + + +void +ngx_http_vhost_traffic_status_node_histogram_observe( + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b, + ngx_msec_int_t x) +{ + ngx_uint_t i, n; + + n = b->len; + + for (i = 0; i < n; i++) { + if (x <= b->buckets[i].msec) { + b->buckets[i].counter++; + } + } +} + + +ngx_int_t +ngx_http_vhost_traffic_status_node_member_cmp(ngx_str_t *member, const char *name) +{ + if (member->len == ngx_strlen(name) && ngx_strncmp(name, member->data, member->len) == 0) { + return 0; + } + + return 1; +} + + +ngx_atomic_uint_t +ngx_http_vhost_traffic_status_node_member(ngx_http_vhost_traffic_status_node_t *vtsn, + ngx_str_t *member) +{ + if (ngx_http_vhost_traffic_status_node_member_cmp(member, "request") == 0) + { + return vtsn->stat_request_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "in") == 0) + { + return vtsn->stat_in_bytes; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "out") == 0) + { + return vtsn->stat_out_bytes; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "1xx") == 0) + { + return vtsn->stat_1xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "2xx") == 0) + { + return vtsn->stat_2xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "3xx") == 0) + { + return vtsn->stat_3xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "4xx") == 0) + { + return vtsn->stat_4xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "5xx") == 0) + { + return vtsn->stat_5xx_counter; + } + +#if (NGX_HTTP_CACHE) + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_miss") == 0) + { + return vtsn->stat_cache_miss_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_bypass") == 0) + { + return vtsn->stat_cache_bypass_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_expired") == 0) + { + return vtsn->stat_cache_expired_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_stale") == 0) + { + return vtsn->stat_cache_stale_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_updating") == 0) + { + return vtsn->stat_cache_updating_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_revalidated") == 0) + { + return vtsn->stat_cache_revalidated_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_hit") == 0) + { + return vtsn->stat_cache_hit_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cache_scarce") == 0) + { + return vtsn->stat_cache_scarce_counter; + } +#endif + + return 0; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.h new file mode 100644 index 0000000..9ea6f23 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_node.h @@ -0,0 +1,178 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_NODE_H_INCLUDED_ +#define _NGX_HTTP_VTS_NODE_H_INCLUDED_ + + +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN 64 +#define NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN 32 + + +typedef struct { + ngx_msec_t time; + ngx_msec_int_t msec; +} ngx_http_vhost_traffic_status_node_time_t; + + +typedef struct { + ngx_http_vhost_traffic_status_node_time_t times[NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_QUEUE_LEN]; + ngx_int_t front; + ngx_int_t rear; + ngx_int_t len; +} ngx_http_vhost_traffic_status_node_time_queue_t; + + +typedef struct { + ngx_msec_int_t msec; + ngx_atomic_t counter; +} ngx_http_vhost_traffic_status_node_histogram_t; + + +typedef struct { + ngx_http_vhost_traffic_status_node_histogram_t buckets[NGX_HTTP_VHOST_TRAFFIC_STATUS_DEFAULT_BUCKET_LEN]; + ngx_int_t len; +} ngx_http_vhost_traffic_status_node_histogram_bucket_t; + + +typedef struct { + /* unsigned type:5 */ + unsigned type; + ngx_atomic_t response_time_counter; + ngx_msec_t response_time; + ngx_http_vhost_traffic_status_node_time_queue_t response_times; + ngx_http_vhost_traffic_status_node_histogram_bucket_t response_buckets; +} ngx_http_vhost_traffic_status_node_upstream_t; + + +typedef struct { + u_char color; + ngx_atomic_t stat_request_counter; + ngx_atomic_t stat_in_bytes; + ngx_atomic_t stat_out_bytes; + ngx_atomic_t stat_1xx_counter; + ngx_atomic_t stat_2xx_counter; + ngx_atomic_t stat_3xx_counter; + ngx_atomic_t stat_4xx_counter; + ngx_atomic_t stat_5xx_counter; + + ngx_atomic_t stat_request_time_counter; + ngx_msec_t stat_request_time; + ngx_http_vhost_traffic_status_node_time_queue_t stat_request_times; + ngx_http_vhost_traffic_status_node_histogram_bucket_t stat_request_buckets; + + /* deals with the overflow of variables */ + ngx_atomic_t stat_request_counter_oc; + ngx_atomic_t stat_in_bytes_oc; + ngx_atomic_t stat_out_bytes_oc; + ngx_atomic_t stat_1xx_counter_oc; + ngx_atomic_t stat_2xx_counter_oc; + ngx_atomic_t stat_3xx_counter_oc; + ngx_atomic_t stat_4xx_counter_oc; + ngx_atomic_t stat_5xx_counter_oc; + ngx_atomic_t stat_request_time_counter_oc; + ngx_atomic_t stat_response_time_counter_oc; + +#if (NGX_HTTP_CACHE) + ngx_atomic_t stat_cache_max_size; + ngx_atomic_t stat_cache_used_size; + ngx_atomic_t stat_cache_miss_counter; + ngx_atomic_t stat_cache_bypass_counter; + ngx_atomic_t stat_cache_expired_counter; + ngx_atomic_t stat_cache_stale_counter; + ngx_atomic_t stat_cache_updating_counter; + ngx_atomic_t stat_cache_revalidated_counter; + ngx_atomic_t stat_cache_hit_counter; + ngx_atomic_t stat_cache_scarce_counter; + + /* deals with the overflow of variables */ + ngx_atomic_t stat_cache_miss_counter_oc; + ngx_atomic_t stat_cache_bypass_counter_oc; + ngx_atomic_t stat_cache_expired_counter_oc; + ngx_atomic_t stat_cache_stale_counter_oc; + ngx_atomic_t stat_cache_updating_counter_oc; + ngx_atomic_t stat_cache_revalidated_counter_oc; + ngx_atomic_t stat_cache_hit_counter_oc; + ngx_atomic_t stat_cache_scarce_counter_oc; +#endif + + ngx_http_vhost_traffic_status_node_upstream_t stat_upstream; + u_short len; + u_char data[1]; +} ngx_http_vhost_traffic_status_node_t; + + +ngx_int_t ngx_http_vhost_traffic_status_node_generate_key(ngx_pool_t *pool, + ngx_str_t *buf, ngx_str_t *dst, unsigned type); +ngx_int_t ngx_http_vhost_traffic_status_node_position_key(ngx_str_t *buf, + size_t pos); + +ngx_rbtree_node_t *ngx_http_vhost_traffic_status_node_lookup( + ngx_rbtree_t *rbtree, ngx_str_t *key, uint32_t hash); +void ngx_http_vhost_traffic_status_node_zero( + ngx_http_vhost_traffic_status_node_t *vtsn); +void ngx_http_vhost_traffic_status_node_init(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn); +void ngx_http_vhost_traffic_status_node_set(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn); + +void ngx_http_vhost_traffic_status_node_time_queue_zero( + ngx_http_vhost_traffic_status_node_time_queue_t *q); +void ngx_http_vhost_traffic_status_node_time_queue_init( + ngx_http_vhost_traffic_status_node_time_queue_t *q); +void ngx_http_vhost_traffic_status_node_time_queue_insert( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_int_t x); +ngx_int_t ngx_http_vhost_traffic_status_node_time_queue_push( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_int_t x); +ngx_int_t ngx_http_vhost_traffic_status_node_time_queue_pop( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_http_vhost_traffic_status_node_time_t *x); +ngx_int_t ngx_http_vhost_traffic_status_node_time_queue_rear( + ngx_http_vhost_traffic_status_node_time_queue_t *q); + +ngx_msec_t ngx_http_vhost_traffic_status_node_time_queue_average( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_int_t method, ngx_msec_t period); +ngx_msec_t ngx_http_vhost_traffic_status_node_time_queue_amm( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_t period); +ngx_msec_t ngx_http_vhost_traffic_status_node_time_queue_wma( + ngx_http_vhost_traffic_status_node_time_queue_t *q, + ngx_msec_t period); +void ngx_http_vhost_traffic_status_node_time_queue_merge( + ngx_http_vhost_traffic_status_node_time_queue_t *a, + ngx_http_vhost_traffic_status_node_time_queue_t *b, + ngx_msec_t period); + +void ngx_http_vhost_traffic_status_node_histogram_bucket_init( + ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b); +void ngx_http_vhost_traffic_status_node_histogram_observe( + ngx_http_vhost_traffic_status_node_histogram_bucket_t *b, + ngx_msec_int_t x); + +void ngx_http_vhost_traffic_status_find_name(ngx_http_request_t *r, + ngx_str_t *buf); +ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_node(ngx_http_request_t *r, + ngx_str_t *key, unsigned type, uint32_t key_hash); + +ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_lru(ngx_http_request_t *r); +ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_lru_node(ngx_http_request_t *r, + ngx_rbtree_node_t *a, ngx_rbtree_node_t *b); +ngx_rbtree_node_t *ngx_http_vhost_traffic_status_find_lru_node_cmp(ngx_http_request_t *r, + ngx_rbtree_node_t *a, ngx_rbtree_node_t *b); + +ngx_int_t ngx_http_vhost_traffic_status_node_member_cmp(ngx_str_t *member, const char *name); +ngx_atomic_uint_t ngx_http_vhost_traffic_status_node_member( + ngx_http_vhost_traffic_status_node_t *vtsn, + ngx_str_t *member); + + +#endif /* _NGX_HTTP_VTS_NODE_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.c new file mode 100644 index 0000000..26167bb --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.c @@ -0,0 +1,544 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_control.h" +#include "ngx_http_vhost_traffic_status_set.h" + + +static ngx_int_t ngx_http_vhost_traffic_status_set_init(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_control_t *control); + +static ngx_atomic_uint_t ngx_http_vhost_traffic_status_set_by_filter_node_member( + ngx_http_vhost_traffic_status_control_t *control, + ngx_http_vhost_traffic_status_node_t *vtsn, + ngx_http_upstream_server_t *us); +static ngx_int_t ngx_http_vhost_traffic_status_set_by_filter_init( + ngx_http_vhost_traffic_status_control_t *control, ngx_str_t *uri); +static ngx_int_t ngx_http_vhost_traffic_status_set_by_filter_node( + ngx_http_vhost_traffic_status_control_t *control, ngx_str_t *buf); +static ngx_int_t ngx_http_vhost_traffic_status_set_by_filter_variable( + ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_vhost_traffic_status_set_by_filter_variables( + ngx_http_request_t *r); + + +ngx_int_t +ngx_http_vhost_traffic_status_set_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (!ctx->enable || !vtscf->filter) { + return NGX_DECLINED; + } + + rc = ngx_http_vhost_traffic_status_set_by_filter_variables(r); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "set_handler::set_by_filter_variables() failed"); + } + + return NGX_DECLINED; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_set_init(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_control_t *control) +{ + control->r = r; + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_NONE; + control->group = -2; + control->zone = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); + control->arg_group = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); + control->arg_zone = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); + control->arg_name = ngx_pcalloc(r->pool, sizeof(ngx_str_t)); + control->range = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_RANGE_NONE; + control->count = 0; + + if (control->zone == NULL || control->arg_group == NULL + || control->arg_zone == NULL || control->arg_name == NULL) + { + return NGX_ERROR; + } + + return NGX_OK; +} + + +static ngx_atomic_uint_t +ngx_http_vhost_traffic_status_set_by_filter_node_member( + ngx_http_vhost_traffic_status_control_t *control, + ngx_http_vhost_traffic_status_node_t *vtsn, + ngx_http_upstream_server_t *us) +{ + ngx_str_t *member; + + member = control->arg_name; + + if (ngx_http_vhost_traffic_status_node_member_cmp(member, "requestCounter") == 0) + { + return vtsn->stat_request_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "requestMsecCounter") == 0) + { + return vtsn->stat_request_time_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "requestMsec") == 0) + { + return vtsn->stat_request_time; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "responseMsecCounter") == 0) + { + return vtsn->stat_upstream.response_time_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "responseMsec") == 0) + { + return vtsn->stat_upstream.response_time; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "inBytes") == 0) + { + return vtsn->stat_in_bytes; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "outBytes") == 0) + { + return vtsn->stat_out_bytes; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "1xx") == 0) + { + return vtsn->stat_1xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "2xx") == 0) + { + return vtsn->stat_2xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "3xx") == 0) + { + return vtsn->stat_3xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "4xx") == 0) + { + return vtsn->stat_4xx_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "5xx") == 0) + { + return vtsn->stat_5xx_counter; + } + +#if (NGX_HTTP_CACHE) + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheMaxSize") == 0) + { + return vtsn->stat_cache_max_size; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheUsedSize") == 0) + { + return vtsn->stat_cache_used_size; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheMiss") == 0) + { + return vtsn->stat_cache_miss_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheBypass") == 0) + { + return vtsn->stat_cache_bypass_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheExpired") == 0) + { + return vtsn->stat_cache_expired_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheStale") == 0) + { + return vtsn->stat_cache_stale_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheUpdating") == 0) + { + return vtsn->stat_cache_updating_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheRevalidated") == 0) + { + return vtsn->stat_cache_revalidated_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheHit") == 0) + { + return vtsn->stat_cache_hit_counter; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "cacheScarce") == 0) + { + return vtsn->stat_cache_scarce_counter; + } +#endif + + switch (control->group) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG: + + if (ngx_http_vhost_traffic_status_node_member_cmp(member, "weight") == 0) + { + return us->weight; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "maxFails") == 0) + { + return us->max_fails; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "failTimeout") == 0) + { + return us->fail_timeout; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "backup") == 0) + { + return us->backup; + } + else if (ngx_http_vhost_traffic_status_node_member_cmp(member, "down") == 0) + { + return us->down; + } + + break; + } + + return 0; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_set_by_filter_init( + ngx_http_vhost_traffic_status_control_t *control, + ngx_str_t *uri) +{ + u_char *p; + ngx_int_t rc; + ngx_str_t *arg_group, *arg_zone, *arg_name, alpha, slash; + ngx_http_request_t *r; + + control->command = NGX_HTTP_VHOST_TRAFFIC_STATUS_CONTROL_CMD_STATUS; + arg_group = control->arg_group; + arg_zone = control->arg_zone; + arg_name = control->arg_name; + + r = control->r; + + /* parse: group */ + p = (u_char *) ngx_strchr(uri->data, '/'); + if (p == NULL) { + return NGX_ERROR; + } + + arg_group->data = uri->data; + arg_group->len = p - uri->data; + + /* parse: zone */ + arg_zone->data = p + 1; + p = (u_char *) ngx_strchr(arg_zone->data, '/'); + if (p == NULL) { + return NGX_ERROR; + } + + arg_zone->len = p - arg_zone->data; + + /* parse: name */ + arg_name->data = p + 1; + arg_name->len = uri->data + uri->len - arg_name->data; + + /* set: control->group */ + if (arg_group->len == 6 + && ngx_strncasecmp(arg_group->data, (u_char *) "server", 6) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + } + else if (arg_group->len == 14 + && ngx_strncasecmp(arg_group->data, (u_char *) "upstream@alone", 14) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA; + } + else if (arg_group->len == 14 + && ngx_strncasecmp(arg_group->data, (u_char *) "upstream@group", 14) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG; + } + else if (arg_group->len == 5 + && ngx_strncasecmp(arg_group->data, (u_char *) "cache", 5) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC; + } + else if (arg_group->len == 6 + && ngx_strncasecmp(arg_group->data, (u_char *) "filter", 6) == 0) + { + control->group = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG; + } + else { + return NGX_ERROR; + } + + /* set: control->zone */ + rc = ngx_http_vhost_traffic_status_copy_str(r->pool, control->zone, arg_zone); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_control::copy_str() failed"); + } + + (void) ngx_http_vhost_traffic_status_replace_chrc(control->zone, '@', + NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR); + + ngx_str_set(&alpha, "[:alpha:]"); + rc = ngx_http_vhost_traffic_status_replace_strc(control->zone, &alpha, '@'); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_control::replace_strc() failed"); + } + + ngx_str_set(&slash, "[:slash:]"); + rc = ngx_http_vhost_traffic_status_replace_strc(control->zone, &slash, '/'); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "display_handler_control::replace_strc() failed"); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_set_by_filter_node( + ngx_http_vhost_traffic_status_control_t *control, + ngx_str_t *buf) +{ + u_char *p; + ngx_int_t rc; + ngx_str_t key; + ngx_rbtree_node_t *node; + ngx_http_request_t *r; + ngx_http_upstream_server_t us; + ngx_http_vhost_traffic_status_node_t *vtsn; + + r = control->r; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, control->zone, + control->group); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "node_status_zone::node_generate_key(\"%V\") failed", &key); + + return NGX_ERROR; + } + + node = ngx_http_vhost_traffic_status_find_node(r, &key, control->group, 0); + if (node == NULL) { + return NGX_ERROR; + } + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + buf->data = p; + + ngx_memzero(&us, sizeof(ngx_http_upstream_server_t)); + + switch (control->group) { + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG: + buf->len = ngx_sprintf(p, "%uA", ngx_http_vhost_traffic_status_set_by_filter_node_member( + control, vtsn, &us)) - p; + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG: + ngx_http_vhost_traffic_status_node_upstream_lookup(control, &us); + if (control->count) { + buf->len = ngx_sprintf(p, "%uA", ngx_http_vhost_traffic_status_set_by_filter_node_member( + control, vtsn, &us)) - p; + } else { + return NGX_ERROR; + } + break; + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_set_by_filter_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "vts filter variable"); + + v->not_found = 1; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_set_by_filter_variables(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_str_t val, buf; + ngx_http_variable_t *v; + ngx_http_variable_value_t *vv; + ngx_http_vhost_traffic_status_control_t *control; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_filter_variable_t *fv, *last; + ngx_http_core_main_conf_t *cmcf; + + control = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_control_t)); + if (control == NULL) { + return NGX_ERROR; + } + + rc = ngx_http_vhost_traffic_status_set_init(r, control); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "vts set filter variables"); + + if (vtscf->filter_vars == NULL) { + return NGX_OK; + } + + cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module); + v = cmcf->variables.elts; + + fv = vtscf->filter_vars->elts; + last = fv + vtscf->filter_vars->nelts; + + while (fv < last) { + + vv = &r->variables[fv->index]; + + if (ngx_http_complex_value(r, &fv->value, &val) + != NGX_OK) + { + return NGX_ERROR; + } + + rc = ngx_http_vhost_traffic_status_set_by_filter_init(control, &val); + + if (rc != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "set_by_filter_variables::filter_init() failed"); + + goto not_found; + } + + ngx_memzero(&buf, sizeof(ngx_str_t)); + + rc = ngx_http_vhost_traffic_status_set_by_filter_node(control, &buf); + if (rc != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "set_by_filter_variables::filter_node() node not found"); + + goto not_found; + } + + vv->valid = 1; + vv->not_found = 0; + + vv->data = buf.data; + vv->len = buf.len; + + goto found; + +not_found: + + vv->not_found = 1; + +found: + + if (fv->set_handler) { + fv->set_handler(r, vv, v[fv->index].data); + } + + fv++; + } + + return NGX_OK; +} + + +char * +ngx_http_vhost_traffic_status_set_by_filter(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf) +{ + ngx_http_vhost_traffic_status_loc_conf_t *vtscf = conf; + + ngx_str_t *value; + ngx_http_variable_t *v; + ngx_http_vhost_traffic_status_filter_variable_t *fv; + ngx_http_compile_complex_value_t ccv; + + value = cf->args->elts; + + if (value[1].data[0] != '$') { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid variable name \"%V\"", &value[1]); + return NGX_CONF_ERROR; + } + + value[1].len--; + value[1].data++; + + if (vtscf->filter_vars == NGX_CONF_UNSET_PTR) { + vtscf->filter_vars = ngx_array_create(cf->pool, 1, + sizeof(ngx_http_vhost_traffic_status_filter_variable_t)); + if (vtscf->filter_vars == NULL) { + return NGX_CONF_ERROR; + } + } + + fv = ngx_array_push(vtscf->filter_vars); + if (fv == NULL) { + return NGX_CONF_ERROR; + } + + v = ngx_http_add_variable(cf, &value[1], NGX_HTTP_VAR_CHANGEABLE); + if (v == NULL) { + return NGX_CONF_ERROR; + } + + fv->index = ngx_http_get_variable_index(cf, &value[1]); + if (fv->index == NGX_ERROR) { + return NGX_CONF_ERROR; + } + + if (v->get_handler == NULL) { + v->get_handler = ngx_http_vhost_traffic_status_set_by_filter_variable; + v->data = (uintptr_t) fv; + } + + fv->set_handler = v->set_handler; + + ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = &fv->value; + + if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.h new file mode 100644 index 0000000..ad08b0c --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_set.h @@ -0,0 +1,25 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_SET_H_INCLUDED_ +#define _NGX_HTTP_VTS_SET_H_INCLUDED_ + + +typedef struct { + ngx_int_t index; + ngx_http_complex_value_t value; + ngx_http_set_variable_pt set_handler; +} ngx_http_vhost_traffic_status_filter_variable_t; + + +ngx_int_t ngx_http_vhost_traffic_status_set_handler(ngx_http_request_t *r); +char *ngx_http_vhost_traffic_status_set_by_filter(ngx_conf_t *cf, + ngx_command_t *cmd, void *conf); + + +#endif /* _NGX_HTTP_VTS_SET_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.c new file mode 100644 index 0000000..8066fc0 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.c @@ -0,0 +1,551 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_filter.h" +#include "ngx_http_vhost_traffic_status_shm.h" + + +static ngx_int_t ngx_http_vhost_traffic_status_shm_add_node(ngx_http_request_t *r, + ngx_str_t *key, unsigned type); +static ngx_int_t ngx_http_vhost_traffic_status_shm_add_node_upstream(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn, unsigned init); + +#if (NGX_HTTP_CACHE) +static ngx_int_t ngx_http_vhost_traffic_status_shm_add_node_cache(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn, unsigned init); +#endif + +static ngx_int_t ngx_http_vhost_traffic_status_shm_add_filter_node(ngx_http_request_t *r, + ngx_array_t *filter_keys); + + +void +ngx_http_vhost_traffic_status_shm_info_node(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_shm_info_t *shm_info, + ngx_rbtree_node_t *node) +{ + ngx_str_t filter; + ngx_uint_t size; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + if (node != ctx->rbtree->sentinel) { + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + size = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_vhost_traffic_status_node_t, data) + + vtsn->len; + + shm_info->used_size += size; + shm_info->used_node++; + + if (vtsn->stat_upstream.type == NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG) { + filter.data = vtsn->data; + filter.len = vtsn->len; + + (void) ngx_http_vhost_traffic_status_node_position_key(&filter, 1); + + if (ngx_http_vhost_traffic_status_filter_max_node_match(r, &filter) == NGX_OK) { + shm_info->filter_used_size += size; + shm_info->filter_used_node++; + } + } + + ngx_http_vhost_traffic_status_shm_info_node(r, shm_info, node->left); + ngx_http_vhost_traffic_status_shm_info_node(r, shm_info, node->right); + } +} + + +void +ngx_http_vhost_traffic_status_shm_info(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_shm_info_t *shm_info) +{ + ngx_http_vhost_traffic_status_ctx_t *ctx; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + ngx_memzero(shm_info, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + + shm_info->name = &ctx->shm_name; + shm_info->max_size = ctx->shm_size; + + ngx_http_vhost_traffic_status_shm_info_node(r, shm_info, ctx->rbtree->root); +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_shm_add_node(ngx_http_request_t *r, + ngx_str_t *key, unsigned type) +{ + size_t size; + unsigned init; + uint32_t hash; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node, *lrun; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + ngx_http_vhost_traffic_status_shm_info_t *shm_info; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (key->len == 0) { + return NGX_ERROR; + } + + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + /* find node */ + hash = ngx_crc32_short(key->data, key->len); + + node = ngx_http_vhost_traffic_status_find_node(r, key, type, hash); + + /* set common */ + if (node == NULL) { + init = NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_NONE; + + /* delete lru node */ + lrun = ngx_http_vhost_traffic_status_find_lru(r); + if (lrun != NULL) { + ngx_rbtree_delete(ctx->rbtree, lrun); + ngx_slab_free_locked(shpool, lrun); + } + + size = offsetof(ngx_rbtree_node_t, color) + + offsetof(ngx_http_vhost_traffic_status_node_t, data) + + key->len; + + node = ngx_slab_alloc_locked(shpool, size); + if (node == NULL) { + shm_info = ngx_pcalloc(r->pool, sizeof(ngx_http_vhost_traffic_status_shm_info_t)); + if (shm_info == NULL) { + return NGX_ERROR; + } + + ngx_http_vhost_traffic_status_shm_info(r, shm_info); + + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_node::ngx_slab_alloc_locked() failed: " + "used_size[%ui], used_node[%ui]", + shm_info->used_size, shm_info->used_node); + + ngx_shmtx_unlock(&shpool->mutex); + return NGX_ERROR; + } + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + node->key = hash; + vtsn->len = (u_char) key->len; + ngx_http_vhost_traffic_status_node_init(r, vtsn); + vtsn->stat_upstream.type = type; + ngx_memcpy(vtsn->data, key->data, key->len); + + ngx_rbtree_insert(ctx->rbtree, node); + + } else { + init = NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_FIND; + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + ngx_http_vhost_traffic_status_node_set(r, vtsn); + } + + /* set addition */ + switch(type) { + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO: + break; + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA: + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG: + (void) ngx_http_vhost_traffic_status_shm_add_node_upstream(r, vtsn, init); + break; + +#if (NGX_HTTP_CACHE) + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC: + (void) ngx_http_vhost_traffic_status_shm_add_node_cache(r, vtsn, init); + break; +#endif + + case NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG: + break; + } + + vtscf->node_caches[type] = node; + + ngx_shmtx_unlock(&shpool->mutex); + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_vhost_traffic_status_shm_add_node_upstream(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn, unsigned init) +{ + ngx_msec_int_t ms; + ngx_http_vhost_traffic_status_node_t ovtsn; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + ovtsn = *vtsn; + ms = ngx_http_vhost_traffic_status_upstream_response_time(r); + + ngx_http_vhost_traffic_status_node_time_queue_insert(&vtsn->stat_upstream.response_times, + ms); + ngx_http_vhost_traffic_status_node_histogram_observe(&vtsn->stat_upstream.response_buckets, + ms); + + if (init == NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_NONE) { + vtsn->stat_upstream.response_time_counter = (ngx_atomic_uint_t) ms; + vtsn->stat_upstream.response_time = (ngx_msec_t) ms; + + } else { + vtsn->stat_upstream.response_time_counter += (ngx_atomic_uint_t) ms; + vtsn->stat_upstream.response_time = ngx_http_vhost_traffic_status_node_time_queue_average( + &vtsn->stat_upstream.response_times, + vtscf->average_method, vtscf->average_period); + + if (ovtsn.stat_upstream.response_time_counter > vtsn->stat_upstream.response_time_counter) + { + vtsn->stat_response_time_counter_oc++; + } + } + + return NGX_OK; +} + + +#if (NGX_HTTP_CACHE) + +static ngx_int_t +ngx_http_vhost_traffic_status_shm_add_node_cache(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_node_t *vtsn, unsigned init) +{ + ngx_http_cache_t *c; + ngx_http_upstream_t *u; + ngx_http_file_cache_t *cache; + + u = r->upstream; + + if (u != NULL && u->cache_status != 0 && r->cache != NULL) { + c = r->cache; + cache = c->file_cache; + + } else { + return NGX_OK; + } + + if (init == NGX_HTTP_VHOST_TRAFFIC_STATUS_NODE_NONE) { + vtsn->stat_cache_max_size = (ngx_atomic_uint_t) (cache->max_size * cache->bsize); + + } else { + ngx_shmtx_lock(&cache->shpool->mutex); + + vtsn->stat_cache_used_size = (ngx_atomic_uint_t) (cache->sh->size * cache->bsize); + + ngx_shmtx_unlock(&cache->shpool->mutex); + } + + return NGX_OK; +} + +#endif + + +static ngx_int_t +ngx_http_vhost_traffic_status_shm_add_filter_node(ngx_http_request_t *r, + ngx_array_t *filter_keys) +{ + u_char *p; + unsigned type; + ngx_int_t rc; + ngx_str_t key, dst, filter_key, filter_name; + ngx_uint_t i, n; + ngx_http_vhost_traffic_status_filter_t *filters; + + if (filter_keys == NULL) { + return NGX_OK; + } + + filters = filter_keys->elts; + n = filter_keys->nelts; + + for (i = 0; i < n; i++) { + if (filters[i].filter_key.value.len <= 0) { + continue; + } + + if (ngx_http_complex_value(r, &filters[i].filter_key, &filter_key) != NGX_OK) { + return NGX_ERROR; + } + + if (ngx_http_complex_value(r, &filters[i].filter_name, &filter_name) != NGX_OK) { + return NGX_ERROR; + } + + if (filter_key.len == 0) { + continue; + } + + if (filter_name.len == 0) { + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &filter_key, type); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + } else { + type = filter_name.len + ? NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_FG + : NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + + dst.len = filter_name.len + sizeof("@") - 1 + filter_key.len; + dst.data = ngx_pnalloc(r->pool, dst.len); + if (dst.data == NULL) { + return NGX_ERROR; + } + + p = dst.data; + p = ngx_cpymem(p, filter_name.data, filter_name.len); + *p++ = NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR; + p = ngx_cpymem(p, filter_key.data, filter_key.len); + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type); + if (rc != NGX_OK) { + return NGX_ERROR; + } + } + + rc = ngx_http_vhost_traffic_status_shm_add_node(r, &key, type); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_filter_node::shm_add_node(\"%V\") failed", &key); + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_shm_add_server(ngx_http_request_t *r) +{ + unsigned type; + ngx_int_t rc; + ngx_str_t key, dst; + ngx_http_core_srv_conf_t *cscf; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); + + if (vtscf->filter && vtscf->filter_host && r->headers_in.server.len) { + /* set the key by host header */ + dst = r->headers_in.server; + + } else { + /* set the key by server_name variable */ + dst = cscf->server_name; + if (dst.len == 0) { + dst.len = 1; + dst.data = (u_char *) "_"; + } + } + + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + return ngx_http_vhost_traffic_status_shm_add_node(r, &key, type); +} + + +ngx_int_t +ngx_http_vhost_traffic_status_shm_add_filter(ngx_http_request_t *r) +{ + ngx_int_t rc; + ngx_http_vhost_traffic_status_ctx_t *ctx; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + ctx = ngx_http_get_module_main_conf(r, ngx_http_vhost_traffic_status_module); + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + if (!vtscf->filter) { + return NGX_OK; + } + + if (ctx->filter_keys != NULL) { + rc = ngx_http_vhost_traffic_status_shm_add_filter_node(r, ctx->filter_keys); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_filter::shm_add_filter_node(\"http\") failed"); + } + } + + if (vtscf->filter_keys != NULL) { + rc = ngx_http_vhost_traffic_status_shm_add_filter_node(r, vtscf->filter_keys); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_filter::shm_add_filter_node(\"server\") failed"); + } + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_shm_add_upstream(ngx_http_request_t *r) +{ + u_char *p; + unsigned type; + ngx_int_t rc; + ngx_str_t *host, key, dst; + ngx_uint_t i; + ngx_http_upstream_t *u; + ngx_http_upstream_state_t *state; + ngx_http_upstream_srv_conf_t *uscf, **uscfp; + ngx_http_upstream_main_conf_t *umcf; + + if (r->upstream_states == NULL || r->upstream_states->nelts == 0 + || r->upstream->state == NULL) + { + return NGX_OK; + } + + u = r->upstream; + + if (u->resolved == NULL) { + uscf = u->conf->upstream; + + } else { + host = &u->resolved->host; + + umcf = ngx_http_get_module_main_conf(r, ngx_http_upstream_module); + + uscfp = umcf->upstreams.elts; + + for (i = 0; i < umcf->upstreams.nelts; i++) { + + uscf = uscfp[i]; + + if (uscf->host.len == host->len + && ((uscf->port == 0 && u->resolved->no_port) + || uscf->port == u->resolved->port) + && ngx_strncasecmp(uscf->host.data, host->data, host->len) == 0) + { + goto found; + } + } + + /* routine for proxy_pass|fastcgi_pass|... $variables */ + uscf = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_srv_conf_t)); + if (uscf == NULL) { + return NGX_ERROR; + } + + uscf->host = u->resolved->host; + uscf->port = u->resolved->port; + } + +found: + + state = r->upstream_states->elts; + if (state[0].peer == NULL) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_upstream::peer failed"); + return NGX_ERROR; + } + + dst.len = (uscf->port ? 0 : uscf->host.len + sizeof("@") - 1) + state[0].peer->len; + dst.data = ngx_pnalloc(r->pool, dst.len); + if (dst.data == NULL) { + return NGX_ERROR; + } + + p = dst.data; + if (uscf->port) { + p = ngx_cpymem(p, state[0].peer->data, state[0].peer->len); + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UA; + + } else { + p = ngx_cpymem(p, uscf->host.data, uscf->host.len); + *p++ = NGX_HTTP_VHOST_TRAFFIC_STATUS_KEY_SEPARATOR; + p = ngx_cpymem(p, state[0].peer->data, state[0].peer->len); + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_UG; + } + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + rc = ngx_http_vhost_traffic_status_shm_add_node(r, &key, type); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_upstream::shm_add_node(\"%V\") failed", &key); + } + + return NGX_OK; +} + + +#if (NGX_HTTP_CACHE) + +ngx_int_t +ngx_http_vhost_traffic_status_shm_add_cache(ngx_http_request_t *r) +{ + unsigned type; + ngx_int_t rc; + ngx_str_t key; + ngx_http_cache_t *c; + ngx_http_upstream_t *u; + ngx_http_file_cache_t *cache; + + u = r->upstream; + + if (u != NULL && u->cache_status != 0 && r->cache != NULL) { + c = r->cache; + cache = c->file_cache; + + } else { + return NGX_OK; + } + + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_CC; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &cache->shm_zone->shm.name, + type); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + rc = ngx_http_vhost_traffic_status_shm_add_node(r, &key, type); + if (rc != NGX_OK) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "shm_add_cache::shm_add_node(\"%V\") failed", &key); + } + + return NGX_OK; +} + +#endif + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.h new file mode 100644 index 0000000..bbc9d97 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_shm.h @@ -0,0 +1,38 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_SHM_H_INCLUDED_ +#define _NGX_HTTP_VTS_SHM_H_INCLUDED_ + + +typedef struct { + ngx_str_t *name; + ngx_uint_t max_size; + ngx_uint_t used_size; + ngx_uint_t used_node; + + ngx_uint_t filter_used_size; + ngx_uint_t filter_used_node; +} ngx_http_vhost_traffic_status_shm_info_t; + + +ngx_int_t ngx_http_vhost_traffic_status_shm_add_server(ngx_http_request_t *r); +ngx_int_t ngx_http_vhost_traffic_status_shm_add_filter(ngx_http_request_t *r); +ngx_int_t ngx_http_vhost_traffic_status_shm_add_upstream(ngx_http_request_t *r); + +#if (NGX_HTTP_CACHE) +ngx_int_t ngx_http_vhost_traffic_status_shm_add_cache(ngx_http_request_t *r); +#endif + +void ngx_http_vhost_traffic_status_shm_info_node(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_shm_info_t *shm_info, ngx_rbtree_node_t *node); +void ngx_http_vhost_traffic_status_shm_info(ngx_http_request_t *r, + ngx_http_vhost_traffic_status_shm_info_t *shm_info); + + +#endif /* _NGX_HTTP_VTS_SHM_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.c new file mode 100644 index 0000000..800c058 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.c @@ -0,0 +1,167 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include +#include + +#include "ngx_http_vhost_traffic_status_string.h" + + +#if !defined(nginx_version) || nginx_version < 1007009 + +/* from src/core/ngx_string.c in v1.7.9 */ +uintptr_t +ngx_http_vhost_traffic_status_escape_json(u_char *dst, u_char *src, size_t size) +{ + u_char ch; + ngx_uint_t len; + + if (dst == NULL) { + len = 0; + + while (size) { + ch = *src++; + + if (ch == '\\' || ch == '"') { + len++; + + } else if (ch <= 0x1f) { + len += sizeof("\\u001F") - 2; + } + + size--; + } + + return (uintptr_t) len; + } + + while (size) { + ch = *src++; + + if (ch > 0x1f) { + + if (ch == '\\' || ch == '"') { + *dst++ = '\\'; + } + + *dst++ = ch; + + } else { + *dst++ = '\\'; *dst++ = 'u'; *dst++ = '0'; *dst++ = '0'; + *dst++ = '0' + (ch >> 4); + + ch &= 0xf; + + *dst++ = (ch < 10) ? ('0' + ch) : ('A' + ch - 10); + } + + size--; + } + + return (uintptr_t) dst; +} + +#endif + + +ngx_int_t +ngx_http_vhost_traffic_status_escape_json_pool(ngx_pool_t *pool, + ngx_str_t *buf, ngx_str_t *dst) +{ + u_char *p; + + buf->len = dst->len * 6; + buf->data = ngx_pcalloc(pool, buf->len); + if (buf->data == NULL) { + *buf = *dst; + return NGX_ERROR; + } + + p = buf->data; + +#if !defined(nginx_version) || nginx_version < 1007009 + p = (u_char *) ngx_http_vhost_traffic_status_escape_json(p, dst->data, dst->len); +#else + p = (u_char *) ngx_escape_json(p, dst->data, dst->len); +#endif + + buf->len = ngx_strlen(buf->data); + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_copy_str(ngx_pool_t *pool, + ngx_str_t *buf, ngx_str_t *dst) +{ + u_char *p; + + buf->len = dst->len; + buf->data = ngx_pcalloc(pool, dst->len + 1); /* 1 byte for terminating '\0' */ + if (buf->data == NULL) { + return NGX_ERROR; + } + + p = buf->data; + + ngx_memcpy(p, dst->data, dst->len); + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_replace_chrc(ngx_str_t *buf, + u_char in, u_char to) +{ + size_t len; + u_char *p; + + p = buf->data; + + len = buf->len; + + while(len--) { + if (*p == in) { + *p = to; + } + p++; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_replace_strc(ngx_str_t *buf, + ngx_str_t *dst, u_char c) +{ + size_t n, len; + u_char *p, *o; + p = o = buf->data; + n = 0; + + /* we need the buf's last '\0' for ngx_strstrn() */ + if (*(buf->data + buf->len) != 0) { + return NGX_ERROR; + } + + while ((p = ngx_strstrn(p, (char *) dst->data, dst->len - 1)) != NULL) { + n++; + len = buf->len - (p - o) - (n * dst->len) + n - 1; + *p++ = c; + ngx_memmove(p, p + dst->len - 1, len); + } + + if (n > 0) { + buf->len = buf->len - (n * dst->len) + n; + } + + return NGX_OK; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.h new file mode 100644 index 0000000..20f3f4b --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_string.h @@ -0,0 +1,26 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_STRING_H_INCLUDED_ +#define _NGX_HTTP_VTS_STRING_H_INCLUDED_ + + +#if !defined(nginx_version) || nginx_version < 1007009 +uintptr_t ngx_http_vhost_traffic_status_escape_json(u_char *dst, u_char *src, size_t size); +#endif +ngx_int_t ngx_http_vhost_traffic_status_escape_json_pool(ngx_pool_t *pool, + ngx_str_t *buf, ngx_str_t *dst); +ngx_int_t ngx_http_vhost_traffic_status_copy_str(ngx_pool_t *pool, + ngx_str_t *buf, ngx_str_t *dst); +ngx_int_t ngx_http_vhost_traffic_status_replace_chrc(ngx_str_t *buf, + u_char in, u_char to); +ngx_int_t ngx_http_vhost_traffic_status_replace_strc(ngx_str_t *buf, + ngx_str_t *dst, u_char c); + + +#endif /* _NGX_HTTP_VTS_STRING_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.c b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.c new file mode 100644 index 0000000..73738e0 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.c @@ -0,0 +1,194 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#include "ngx_http_vhost_traffic_status_module.h" +#include "ngx_http_vhost_traffic_status_variables.h" + + +static ngx_http_variable_t ngx_http_vhost_traffic_status_vars[] = { + + { ngx_string("vts_request_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_request_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_in_bytes"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_in_bytes), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_out_bytes"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_out_bytes), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_1xx_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_1xx_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_2xx_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_2xx_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_3xx_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_3xx_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_4xx_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_4xx_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_5xx_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_5xx_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_request_time_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_request_time_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_request_time"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_request_time), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + +#if (NGX_HTTP_CACHE) + { ngx_string("vts_cache_miss_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_miss_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_bypass_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_bypass_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_expired_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_expired_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_stale_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_stale_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_updating_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_updating_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_revalidated_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_revalidated_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_hit_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_hit_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, + + { ngx_string("vts_cache_scarce_counter"), NULL, + ngx_http_vhost_traffic_status_node_variable, + offsetof(ngx_http_vhost_traffic_status_node_t, stat_cache_scarce_counter), + NGX_HTTP_VAR_NOCACHEABLE, 0 }, +#endif + + { ngx_null_string, NULL, NULL, 0, 0, 0 } +}; + + +ngx_int_t +ngx_http_vhost_traffic_status_node_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + unsigned type; + ngx_int_t rc; + ngx_str_t key, dst; + ngx_slab_pool_t *shpool; + ngx_rbtree_node_t *node; + ngx_http_vhost_traffic_status_node_t *vtsn; + ngx_http_vhost_traffic_status_loc_conf_t *vtscf; + + vtscf = ngx_http_get_module_loc_conf(r, ngx_http_vhost_traffic_status_module); + + ngx_http_vhost_traffic_status_find_name(r, &dst); + + type = NGX_HTTP_VHOST_TRAFFIC_STATUS_UPSTREAM_NO; + + rc = ngx_http_vhost_traffic_status_node_generate_key(r->pool, &key, &dst, type); + if (rc != NGX_OK) { + return NGX_ERROR; + } + + if (key.len == 0) { + return NGX_ERROR; + } + + shpool = (ngx_slab_pool_t *) vtscf->shm_zone->shm.addr; + + ngx_shmtx_lock(&shpool->mutex); + + node = ngx_http_vhost_traffic_status_find_node(r, &key, type, 0); + + if (node == NULL) { + goto not_found; + } + + p = ngx_pnalloc(r->pool, NGX_ATOMIC_T_LEN); + if (p == NULL) { + goto not_found; + } + + vtsn = (ngx_http_vhost_traffic_status_node_t *) &node->color; + + v->len = ngx_sprintf(p, "%uA", *((ngx_atomic_t *) ((char *) vtsn + data))) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + goto done; + +not_found: + + v->not_found = 1; + +done: + + vtscf->node_caches[type] = node; + + ngx_shmtx_unlock(&shpool->mutex); + + return NGX_OK; +} + + +ngx_int_t +ngx_http_vhost_traffic_status_add_variables(ngx_conf_t *cf) +{ + ngx_http_variable_t *var, *v; + + for (v = ngx_http_vhost_traffic_status_vars; v->name.len; v++) { + var = ngx_http_add_variable(cf, &v->name, v->flags); + if (var == NULL) { + return NGX_ERROR; + } + + var->get_handler = v->get_handler; + var->data = v->data; + } + + return NGX_OK; +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.h b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.h new file mode 100644 index 0000000..a5547b1 --- /dev/null +++ b/modules/ngx_http_vts/src/ngx_http_vhost_traffic_status_variables.h @@ -0,0 +1,18 @@ + +/* + * Copyright (C) YoungJoo Kim (vozlt) + */ + + +#ifndef _NGX_HTTP_VTS_VARIABLES_H_INCLUDED_ +#define _NGX_HTTP_VTS_VARIABLES_H_INCLUDED_ + + +ngx_int_t ngx_http_vhost_traffic_status_node_variable(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); +ngx_int_t ngx_http_vhost_traffic_status_add_variables(ngx_conf_t *cf); + + +#endif /* _NGX_HTTP_VTS_VARIABLES_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/ngx_http_vts/t/000.display_html.t b/modules/ngx_http_vts/t/000.display_html.t new file mode 100644 index 0000000..95433b7 --- /dev/null +++ b/modules/ngx_http_vts/t/000.display_html.t @@ -0,0 +1,37 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each(2) * blocks() * 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/format/html +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } +--- request +GET /status/format/html +--- response_headers_like +Content-Type: text/html + + + +=== TEST 2: /status +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format html; + } +--- request +GET /status +--- response_headers_like +Content-Type: text/html diff --git a/modules/ngx_http_vts/t/001.display_json.t b/modules/ngx_http_vts/t/001.display_json.t new file mode 100644 index 0000000..b4efaa7 --- /dev/null +++ b/modules/ngx_http_vts/t/001.display_json.t @@ -0,0 +1,37 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each(2) * blocks() * 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/format/json +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + } +--- request +GET /status/format/json +--- response_headers_like +Content-Type: application/json + + + +=== TEST 2: /status +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + } +--- request +GET /status +--- response_headers_like +Content-Type: application/json diff --git a/modules/ngx_http_vts/t/002.check_json_syntax.t b/modules/ngx_http_vts/t/002.check_json_syntax.t new file mode 100644 index 0000000..4abf477 --- /dev/null +++ b/modules/ngx_http_vts/t/002.check_json_syntax.t @@ -0,0 +1,113 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_response_body_check( + sub { + my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_; + system("echo '$body' | python -m json.tool > /dev/null") == 0 or + bail_out "JSON Syntax error($body)"; + } +); + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 24; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: check_json_syntax +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name _; + vhost_traffic_status_filter_by_host on; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_set_header Host one.example.org; + proxy_pass http://backend; + } + location /two { + proxy_set_header Host two.example.org; + proxy_pass http://backend; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } + location /alone { + proxy_pass http://localhost:1981; + } + location /cache_one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /cache_two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\n{\"upstream\@alone\":\"OK\"}" +--- user_files eval +[ + ['one/file.txt' => '{"one.example.org":"OK"}'], + ['two/file.txt' => '{"two.example.org":"OK"}'], + ['storage/vol0/file.txt' => '{"vol0":"OK"}'], + ['storage/vol1/file.txt' => '{"vol1":"OK"}'], + ['cache_one/file.txt' => '{"cache_one":"OK"}'], + ['cache_two/file.txt' => '{"cache_two":"OK"}'] +] +--- request eval +[ + 'GET /status/format/json', + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/format/json', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol1/file.txt', + 'GET /status/format/json', + 'GET /alone/file.txt', + 'GET /status/format/json', + 'GET /cache_one/file.txt', + 'GET /cache_two/file.txt', + 'GET /status/format/json' +] +--- response_body_like eval +[ + 'nginxVersion', + 'OK', + 'OK', + '(one|two).example.org', + 'OK', + 'OK', + 'filterZones.*(vol0|vol1)', + 'OK', + '::nogroups', + 'OK', + 'OK', + 'cacheZone' +] diff --git a/modules/ngx_http_vts/t/003.filter_by_host.t b/modules/ngx_http_vts/t/003.filter_by_host.t new file mode 100644 index 0000000..4b874d0 --- /dev/null +++ b/modules/ngx_http_vts/t/003.filter_by_host.t @@ -0,0 +1,100 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 8; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: vhost_traffic_status_filter_by_host on +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name _; + vhost_traffic_status_filter_by_host on; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_set_header Host one.example.org; + proxy_pass http://backend; + } + location /two { + proxy_set_header Host two.example.org; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'one.example.org:OK'], + ['two/file.txt' => 'two.example.org:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=status&group=server&zone=one.example.org', + 'GET /status/control?cmd=status&group=server&zone=two.example.org' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'one.example.org', + 'two.example.org' +] + + + +=== TEST 2: vhost_traffic_status_filter off +--- http_config + vhost_traffic_status_zone; + vhost_traffic_status_filter off; + upstream backend { + server localhost; + } + server { + server_name _; + vhost_traffic_status_filter_by_host on; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_set_header Host one.example.org; + proxy_pass http://backend; + } + location /two { + proxy_set_header Host two.example.org; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'one.example.org:OK'], + ['two/file.txt' => 'two.example.org:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=status&group=server&zone=one.example.org', + 'GET /status/control?cmd=status&group=server&zone=two.example.org' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '{}', + '{}' +] diff --git a/modules/ngx_http_vts/t/004.filter_by_set_key.t b/modules/ngx_http_vts/t/004.filter_by_set_key.t new file mode 100644 index 0000000..2e99273 --- /dev/null +++ b/modules/ngx_http_vts/t/004.filter_by_set_key.t @@ -0,0 +1,47 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 12; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: filter_by_set_key +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/vol1/file.txt' => 'vol1:OK'], + ['storage/vol2/file.txt' => 'vol2:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol1/file.txt', + 'GET /storage/vol2/file.txt', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol1', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol2', +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'vol0', + 'vol1', + 'vol2' +] diff --git a/modules/ngx_http_vts/t/005.filter_check_duplicate.t b/modules/ngx_http_vts/t/005.filter_check_duplicate.t new file mode 100644 index 0000000..22151c5 --- /dev/null +++ b/modules/ngx_http_vts/t/005.filter_check_duplicate.t @@ -0,0 +1,91 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 12; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: filter_check_duplicate on +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_check_duplicate on; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/vol1/file.txt' => 'vol1:OK'], + ['storage/vol2/file.txt' => 'vol2:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol1/file.txt', + 'GET /storage/vol2/file.txt', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol1', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol2', +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'vol0.*"requestCounter":1', + 'vol1.*"requestCounter":1', + 'vol2.*"requestCounter":1' +] + + + +=== TEST 2: filter_check_duplicate off +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_check_duplicate off; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/vol1/file.txt' => 'vol1:OK'], + ['storage/vol2/file.txt' => 'vol2:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol1/file.txt', + 'GET /storage/vol2/file.txt', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol1', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol2', +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'vol0.*"requestCounter":2', + 'vol1.*"requestCounter":2', + 'vol2.*"requestCounter":2' +] diff --git a/modules/ngx_http_vts/t/006.control_status_fully.t b/modules/ngx_http_vts/t/006.control_status_fully.t new file mode 100644 index 0000000..9498658 --- /dev/null +++ b/modules/ngx_http_vts/t/006.control_status_fully.t @@ -0,0 +1,38 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 4; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=status&group=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=status&group=*', +] +--- response_body_like eval +[ + 'OK', + 'nginxVersion' +] + diff --git a/modules/ngx_http_vts/t/007.control_status_group.t b/modules/ngx_http_vts/t/007.control_status_group.t new file mode 100644 index 0000000..b1f3ae3 --- /dev/null +++ b/modules/ngx_http_vts/t/007.control_status_group.t @@ -0,0 +1,211 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 4 + 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=status&group=server&zone=::main +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + 'GET /status/control?cmd=status&group=server&zone=::main', +] +--- response_body_like eval +[ + 'OK', + 'hostName' +] + + + +=== TEST 2: /status/control?cmd=status&group=server&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + 'GET /status/control?cmd=status&group=server&zone=*', +] +--- response_body_like eval +[ + 'OK', + '{"serverZones.*localhost' +] + + + +=== TEST 3: /status/control?cmd=status&group=filter&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'filter:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=status&group=filter&zone=*', +] +--- response_body_like eval +[ + 'OK', + '{"filterZones.*storage::' +] + + + +=== TEST 4: /status/control?cmd=status&group=upstream@group&zone=* +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['backend/file.txt' => 'upstream@group:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=status&group=upstream@group&zone=*', +] +--- response_body_like eval +[ + 'OK', + '{"upstreamZones.*backend' +] + + + +=== TEST 5: /status/control?cmd=status&group=upstream@alone&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://localhost:1981; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK" +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=status&group=upstream@alone&zone=*', +] +--- response_body_like eval +[ + 'OK', + '{"::nogroups"' +] + + + +=== TEST 6: /status/control?cmd=status&group=cache&zone=* +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'cache_one:OK'], + ['two/file.txt' => 'cache_two:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=status&group=cache&zone=*' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '{"cacheZones.*cache_(one|two)' +] diff --git a/modules/ngx_http_vts/t/008.control_status_zone.t b/modules/ngx_http_vts/t/008.control_status_zone.t new file mode 100644 index 0000000..c35a952 --- /dev/null +++ b/modules/ngx_http_vts/t/008.control_status_zone.t @@ -0,0 +1,185 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 4 + 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=status&group=server&zone=localhost +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + 'GET /status/control?cmd=status&group=server&zone=localhost', +] +--- response_body_like eval +[ + 'OK', + '{"localhost"' +] + + + +=== TEST 2: /status/control?cmd=status&group=filter&zone=storage::localhost@vol0 +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'filter:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=status&group=filter&zone=storage::localhost@vol0', +] +--- response_body_like eval +[ + 'OK', + '{"vol0"' +] + + + +=== TEST 3: /status/control?cmd=status&group=upstream@group&zone=backend@127.0.0.1:80 +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['backend/file.txt' => 'upstream@group:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=status&group=upstream@group&zone=backend@127.0.0.1:80', +] +--- response_body_like eval +[ + 'OK', + '{"server":"127.0.0.1:80"' +] + + + +=== TEST 4: /status/control?cmd=status&group=upstream@alone&zone=127.0.0.1:1981 +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://localhost:1981; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK" +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=status&group=upstream@alone&zone=127.0.0.1:1981', +] +--- response_body_like eval +[ + 'OK', + '{"server":"127.0.0.1:1981"' +] + + + +=== TEST 5: /status/control?cmd=status&group=cache&zone=cache_one +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'cache_one:OK'], + ['two/file.txt' => 'cache_two:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=status&group=cache&zone=cache_one' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '{"cache_one"' +] diff --git a/modules/ngx_http_vts/t/009.control_reset_fully.t b/modules/ngx_http_vts/t/009.control_reset_fully.t new file mode 100644 index 0000000..dc1b691 --- /dev/null +++ b/modules/ngx_http_vts/t/009.control_reset_fully.t @@ -0,0 +1,38 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 4; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=reset&group=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=reset&group=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + diff --git a/modules/ngx_http_vts/t/010.control_reset_group.t b/modules/ngx_http_vts/t/010.control_reset_group.t new file mode 100644 index 0000000..adf4854 --- /dev/null +++ b/modules/ngx_http_vts/t/010.control_reset_group.t @@ -0,0 +1,185 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 4 + 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=reset&group=server&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + "GET /status/control?cmd=reset&group=server&zone=*", +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 2: /status/control?cmd=reset&group=filter&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'filter:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=reset&group=filter&zone=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 3: /status/control?cmd=reset&group=upstream@group&zone=* +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['backend/file.txt' => 'upstream@group:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=reset&group=upstream@group&zone=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 4: /status/control?cmd=reset&group=upstream@alone&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://localhost:1981; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK" +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=reset&group=upstream@alone&zone=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 5: /status/control?cmd=reset&group=cache&zone=* +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'cache_one:OK'], + ['two/file.txt' => 'cache_two:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=reset&group=cache&zone=*' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '"processingCounts":[1-9]' +] diff --git a/modules/ngx_http_vts/t/011.control_reset_zone.t b/modules/ngx_http_vts/t/011.control_reset_zone.t new file mode 100644 index 0000000..9a62701 --- /dev/null +++ b/modules/ngx_http_vts/t/011.control_reset_zone.t @@ -0,0 +1,185 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 4 + 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=reset&group=server&zone=localhost +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + 'GET /status/control?cmd=reset&group=server&zone=localhost', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 2: /status/control?cmd=reset&group=filter&zone=storage::localhost@vol0 +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'filter:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=reset&group=filter&zone=storage::localhost@vol0', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 3: /status/control?cmd=reset&group=upstream@group&zone=backend@127.0.0.1:80 +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['backend/file.txt' => 'upstream@group:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=reset&group=upstream@group&zone=backend@127.0.0.1:80', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 4: /status/control?cmd=reset&group=upstream@alone&zone=127.0.0.1:1981 +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://localhost:1981; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK" +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=reset&group=upstream@alone&zone=127.0.0.1:1981', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 5: /status/control?cmd=reset&group=cache&zone=cache_one +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'cache_one:OK'], + ['two/file.txt' => 'cache_two:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=reset&group=cache&zone=cache_one' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '"processingCounts":[1-9]' +] diff --git a/modules/ngx_http_vts/t/012.control_delete_fully.t b/modules/ngx_http_vts/t/012.control_delete_fully.t new file mode 100644 index 0000000..2a844ff --- /dev/null +++ b/modules/ngx_http_vts/t/012.control_delete_fully.t @@ -0,0 +1,38 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 4; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=delete&group=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=delete&group=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + diff --git a/modules/ngx_http_vts/t/013.control_delete_group.t b/modules/ngx_http_vts/t/013.control_delete_group.t new file mode 100644 index 0000000..775678a --- /dev/null +++ b/modules/ngx_http_vts/t/013.control_delete_group.t @@ -0,0 +1,185 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 4 + 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=delete&group=server&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + "GET /status/control?cmd=delete&group=server&zone=*", +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 2: /status/control?cmd=delete&group=filter&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'filter:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=delete&group=filter&zone=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 3: /status/control?cmd=delete&group=upstream@group&zone=* +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['backend/file.txt' => 'upstream@group:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=delete&group=upstream@group&zone=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 4: /status/control?cmd=delete&group=upstream@alone&zone=* +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://localhost:1981; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK" +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=delete&group=upstream@alone&zone=*', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 5: /status/control?cmd=delete&group=cache&zone=* +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'cache_one:OK'], + ['two/file.txt' => 'cache_two:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=delete&group=cache&zone=*' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '"processingCounts":[1-9]' +] diff --git a/modules/ngx_http_vts/t/014.control_delete_zone.t b/modules/ngx_http_vts/t/014.control_delete_zone.t new file mode 100644 index 0000000..16a46ef --- /dev/null +++ b/modules/ngx_http_vts/t/014.control_delete_zone.t @@ -0,0 +1,185 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + +plan tests => repeat_each() * blocks() * 4 + 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: /status/control?cmd=delete&group=server&zone=localhost +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } +--- user_files eval +[ + ['storage/control/file.txt' => 'server:OK'] +] +--- request eval +[ + 'GET /storage/control/file.txt', + 'GET /status/control?cmd=delete&group=server&zone=localhost', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 2: /status/control?cmd=delete&group=filter&zone=storage::localhost@vol0 +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'filter:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /status/control?cmd=delete&group=filter&zone=storage::localhost@vol0', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 3: /status/control?cmd=delete&group=upstream@group&zone=backend@127.0.0.1:80 +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['backend/file.txt' => 'upstream@group:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=delete&group=upstream@group&zone=backend@127.0.0.1:80', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 4: /status/control?cmd=delete&group=upstream@alone&zone=127.0.0.1:1981 +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /backend { + proxy_set_header Host backend; + proxy_pass http://localhost:1981; + } +--- tcp_listen: 1981 +--- tcp_reply eval +"HTTP/1.1 200 OK\r\n\r\nupstream\@alone:OK" +--- request eval +[ + 'GET /backend/file.txt', + 'GET /status/control?cmd=delete&group=upstream@alone&zone=127.0.0.1:1981', +] +--- response_body_like eval +[ + 'OK', + '"processingCounts":[1-9]' +] + + + +=== TEST 5: /status/control?cmd=delete&group=cache&zone=cache_one +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + proxy_cache_path cache_two levels=1:2 keys_zone=cache_two:2m inactive=1m max_size=4m; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /one { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } + location /two { + proxy_cache cache_two; + proxy_cache_valid 200 10s; + proxy_set_header Host backend; + proxy_pass http://backend; + } +--- user_files eval +[ + ['one/file.txt' => 'cache_one:OK'], + ['two/file.txt' => 'cache_two:OK'] +] +--- request eval +[ + 'GET /one/file.txt', + 'GET /two/file.txt', + 'GET /status/control?cmd=delete&group=cache&zone=cache_one' +] +--- response_body_like eval +[ + 'OK', + 'OK', + '"processingCounts":[1-9]' +] diff --git a/modules/ngx_http_vts/t/015.vts_variables_by_lua.t b/modules/ngx_http_vts/t/015.vts_variables_by_lua.t new file mode 100644 index 0000000..c35664a --- /dev/null +++ b/modules/ngx_http_vts/t/015.vts_variables_by_lua.t @@ -0,0 +1,67 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 6; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST1: access embeded variables starting with a $vts_* by lua +--- http_config + vhost_traffic_status_zone; +--- config + location /variables { + access_by_lua_block { + local i + local variables = { + ngx.var.vts_request_counter, + ngx.var.vts_in_bytes, + ngx.var.vts_out_bytes, + ngx.var.vts_1xx_counter, + ngx.var.vts_2xx_counter, + ngx.var.vts_3xx_counter, + ngx.var.vts_4xx_counter, + ngx.var.vts_5xx_counter, + ngx.var.vts_request_time_counter, + ngx.var.vts_request_time, + ngx.var.vts_cache_miss_counter, + ngx.var.vts_cache_bypass_counter, + ngx.var.vts_cache_expired_counter, + ngx.var.vts_cache_stale_counter, + ngx.var.vts_cache_updating_counter, + ngx.var.vts_cache_revalidated_counter, + ngx.var.vts_cache_hit_counter, + ngx.var.vts_cache_scarce_counter + } + ngx.print("embeded_variables: 18, find_variables: ", table.getn(variables), ", variables: "); + for i=1, table.getn(variables) do + if variables[i] then + ngx.print(i, ":[", variables[i], "] ") + else + ngx.print(i, ":[nil] ") + end + end + } + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/access/file.txt' => 'access:OK'] +] +--- request eval +[ + 'GET /storage/access/file.txt', + 'GET /variables', + 'GET /variables' +] +--- response_body_like eval +[ + 'OK', + 'find_variables: 18', + 'find_variables: 18' +] diff --git a/modules/ngx_http_vts/t/016.limit_traffic_by_lua.t b/modules/ngx_http_vts/t/016.limit_traffic_by_lua.t new file mode 100644 index 0000000..642708d --- /dev/null +++ b/modules/ngx_http_vts/t/016.limit_traffic_by_lua.t @@ -0,0 +1,83 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 8; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST1: limit traffic using $vts_* by lua +--- http_config + vhost_traffic_status_zone; +--- config + set $limit_in 200; + set $limit_out 256; + access_by_lua_block { + local limits = { + ["request"] = tonumber(ngx.var.limit_request), + ["in"] = tonumber(ngx.var.limit_in), + ["out"] = tonumber(ngx.var.limit_out), + ["1xx"] = tonumber(ngx.var.limit_1xx), + ["2xx"] = tonumber(ngx.var.limit_2xx), + ["3xx"] = tonumber(ngx.var.limit_3xx), + ["4xx"] = tonumber(ngx.var.limit_4xx), + ["5xx"] = tonumber(ngx.var.limit_5xx), + ["miss"] = tonumber(ngx.var.limit_miss), + ["bypass"] = tonumber(ngx.var.limit_bypass), + ["expired"] = tonumber(ngx.var.limit_expired), + ["stale"] = tonumber(ngx.var.limit_stale), + ["updating"] = tonumber(ngx.var.limit_updating), + ["revalidated"] = tonumber(ngx.var.limit_revalidated), + ["hit"] = tonumber(ngx.var.limit_hit), + ["scarce"] = tonumber(ngx.var.limit_scarce) + } + + local stats = { + ["request"] = limits["request"] and tonumber(ngx.var.vts_request_counter), + ["in"] = limits["in"] and tonumber(ngx.var.vts_in_bytes), + ["out"] = limits["out"] and tonumber(ngx.var.vts_out_bytes), + ["1xx"] = limits["1xx"] and tonumber(ngx.var.vts_1xx_counter), + ["2xx"] = limits["2xx"] and tonumber(ngx.var.vts_2xx_counter), + ["3xx"] = limits["3xx"] and tonumber(ngx.var.vts_3xx_counter), + ["4xx"] = limits["4xx"] and tonumber(ngx.var.vts_4xx_counter), + ["5xx"] = limits["5xx"] and tonumber(ngx.var.vts_5xx_counter), + ["miss"] = limits["miss"] and tonumber(ngx.var.vts_cache_miss_counter), + ["bypass"] = limits["bypass"] and tonumber(ngx.var.vts_cache_bypass_counter), + ["expired"] = limits["expired"] and tonumber(ngx.var.vts_cache_expired_counter), + ["stale"] = limits["stale"] and tonumber(ngx.var.vts_cache_stale_counter), + ["updating"] = limits["updating"] and tonumber(ngx.var.vts_cache_updating_counter), + ["revalidated"] = limits["revalidated"] and tonumber(ngx.var.vts_cache_revalidated_counter), + ["hit"] = limits["hit"] and tonumber(ngx.var.vts_cache_hit_counter), + ["scarce"] = limits["scarce"] and tonumber(ngx.var.vts_cache_scarce_counter) + } + + for k,v in pairs(limits) do + if stats[k] and stats[k] > v then + ngx.say("exceeded ", k, " traffic limit[", v, "] < current[", stats[k], "]"); + end + end + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + } +--- user_files eval +[ + ['storage/limit/file.txt' => 'limit:OK'] +] +--- request eval +[ + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'exceeded', + 'exceeded' +] diff --git a/modules/ngx_http_vts/t/017.limit_traffic.t b/modules/ngx_http_vts/t/017.limit_traffic.t new file mode 100644 index 0000000..d13c4e8 --- /dev/null +++ b/modules/ngx_http_vts/t/017.limit_traffic.t @@ -0,0 +1,194 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 12; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: vhost_traffic_status_limit_traffic request:n 402 +--- http_config + vhost_traffic_status_zone; +--- config + location ~ / { + set $member request; + vhost_traffic_status_limit_traffic $member:4 402; + } + error_page 402 /storage/limit/402.txt; + location = /storage/limit/402.txt { + internal; + } +--- user_files eval +[ + ['storage/limit/file.txt' => 'server:OK'], + ['storage/limit/402.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt' +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 402 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 2: vhost_traffic_status_limit_traffic in:n +--- http_config + vhost_traffic_status_zone; +--- config + location ~ / { + vhost_traffic_status_limit_traffic in:320; + } + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } +--- user_files eval +[ + ['storage/limit/file.txt' => 'server:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt' +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 503 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 3: vhost_traffic_status_limit_traffic out:n +--- http_config + vhost_traffic_status_zone; +--- config + location ~ / { + vhost_traffic_status_limit_traffic out:1024; + } + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } +--- user_files eval +[ + ['storage/limit/file.txt' => 'server:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt' +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 503 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 4: vhost_traffic_status_limit off +--- http_config + vhost_traffic_status_zone; + vhost_traffic_status_limit off; +--- config + location ~ / { + set $member request; + vhost_traffic_status_limit_traffic $member:4; + } + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } +--- user_files eval +[ + ['storage/limit/file.txt' => 'server:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt', + 'GET /storage/limit/file.txt' +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 200 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] diff --git a/modules/ngx_http_vts/t/018.limit_traffic_by_set_key.t b/modules/ngx_http_vts/t/018.limit_traffic_by_set_key.t new file mode 100644 index 0000000..6162624 --- /dev/null +++ b/modules/ngx_http_vts/t/018.limit_traffic_by_set_key.t @@ -0,0 +1,206 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 12; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: vhost_traffic_status_limit_traffic_by_set_key FG@group@name request:n 402 +--- http_config + vhost_traffic_status_zone; +--- config + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + set $member request; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume $member:4 402; + } + error_page 402 /storage/limit/402.txt; + location = /storage/limit/402.txt { + internal; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/limit/402.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 402 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 2: vhost_traffic_status_limit_traffic_by_set_key FG@group@name in:n +--- http_config + vhost_traffic_status_zone; +--- config + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume in:300; + } + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 503 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 3: vhost_traffic_status_limit_traffic_by_set_key FG@group@name out:n +--- http_config + vhost_traffic_status_zone; +--- config + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume out:1024; + } + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 503 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 4: vhost_traffic_status_limit_traffic_by_set_key UG@group@name request:n +--- http_config + vhost_traffic_status_zone; + upstream backend { + server localhost; + } + server { + server_name backend; + } +--- config + location /backend { + vhost_traffic_status_limit_traffic_by_set_key UG@backend@127.0.0.1:80 request:3; + proxy_set_header Host backend; + proxy_pass http://backend; + } + error_page 503 /backend/limit/503.txt; + location = /backend/limit/503.txt { + internal; + } +--- user_files eval +[ + ['backend/file.txt' => 'backend:OK'], + ['backend/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /backend/file.txt', + 'GET /backend/file.txt', + 'GET /backend/file.txt', + 'GET /backend/file.txt', + 'GET /backend/file.txt', + 'GET /backend/file.txt', +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 503, +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', +] diff --git a/modules/ngx_http_vts/t/019.limit_traffic_check_duplicate.t b/modules/ngx_http_vts/t/019.limit_traffic_check_duplicate.t new file mode 100644 index 0000000..727f750 --- /dev/null +++ b/modules/ngx_http_vts/t/019.limit_traffic_check_duplicate.t @@ -0,0 +1,107 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 12; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: limit_check_duplicate on +--- http_config + vhost_traffic_status_zone; +--- config + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_limit_check_duplicate on; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:8; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:4; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt' +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 200 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 2: limit_check_duplicate off +--- http_config + vhost_traffic_status_zone; +--- config + error_page 503 /storage/limit/503.txt; + location = /storage/limit/503.txt { + internal; + } + location ~ ^/storage/(.+)/.*$ { + set $volume $1; + vhost_traffic_status_limit_check_duplicate off; + vhost_traffic_status_filter_by_set_key $volume storage::$server_name; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:8; + vhost_traffic_status_limit_traffic_by_set_key FG@storage::$server_name@$volume request:4; + } +--- user_files eval +[ + ['storage/vol0/file.txt' => 'vol0:OK'], + ['storage/limit/503.txt' => 'limited:OK'] +] +--- request eval +[ + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt', + 'GET /storage/vol0/file.txt' +] +--- error_code eval +[ + 200, + 200, + 200, + 200, + 200, + 503 +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK', + 'OK', + 'OK', + 'OK' +] diff --git a/modules/ngx_http_vts/t/020.display_sum_key.t b/modules/ngx_http_vts/t/020.display_sum_key.t new file mode 100644 index 0000000..90db557 --- /dev/null +++ b/modules/ngx_http_vts/t/020.display_sum_key.t @@ -0,0 +1,28 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; + +plan tests => repeat_each() * blocks() * 2; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: display_sum_key total +--- http_config + vhost_traffic_status_zone; +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_sum_key total; + vhost_traffic_status_display_format json; + access_log off; + } +--- request eval +[ + 'GET /status/format/json', +] +--- response_body_like eval +[ + 'total', +] diff --git a/modules/ngx_http_vts/t/021.set_by_filter.t b/modules/ngx_http_vts/t/021.set_by_filter.t new file mode 100644 index 0000000..07d17ee --- /dev/null +++ b/modules/ngx_http_vts/t/021.set_by_filter.t @@ -0,0 +1,250 @@ +# vi:set ft=perl ts=4 sw=4 et fdm=marker: + +use Test::Nginx::Socket; +use Fcntl; + +add_response_body_check( + sub { + my ($block, $body, $req_idx, $repeated_req_idx, $dry_run) = @_; + + my $path = 't/servroot/logs/access.log'; + my @lines = FH->getlines() if (sysopen(FH, $path, O_RDONLY)); + close(FH); + my $ll = $lines[-1]; + + ($ll =~ /(requestCounter|inBytes|outBytes|2xx):[-0-9]/) or + bail_out "variables by set_by_filter error($ll)"; + + ($req_idx > 1 && $ll !~ /(requestCounter|2xx):[1-9]/) and + bail_out "variables by set_by_filter error($ll)"; + + if ($block->name =~ /TEST 5/) { + ($req_idx > 1 && $ll !~ /(cacheMaxSize|cacheUsedSize|cacheHit):[0-9]/) and + bail_out "variables by set_by_filter error($ll)"; + } + } +); + +add_cleanup_handler( + sub { + my $CacheDir = "t/servroot/cache_*"; + system("rm -rf $CacheDir > /dev/null") == 0 or + bail_out "Can't remove $CacheDir"; + } +); + + +plan tests => repeat_each() * blocks() * 6; +no_shuffle(); +run_tests(); + +__DATA__ + +=== TEST 1: access variables by vhost_traffic_status_set_by_filter $* server/*/* +--- http_config + vhost_traffic_status_zone; + log_format basic '[$time_local] requestCounter:$requestCounter ' + 'inBytes:$inBytes outBytes:$outBytes ' + '2xx:$2xx'; + access_log logs/access.log basic; +--- config + location /v { + set $group server; + set $zone localhost; + + vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter; + vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes; + vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes; + vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx; + } +--- user_files eval +[ + ['v/file.txt' => '{"return":"OK"}'] +] +--- request eval +[ + 'GET /v/file.txt', + 'GET /v/file.txt', + 'GET /v/file.txt' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 2: access variables by vhost_traffic_status_set_by_filter $* upstream@alone/*/* +--- http_config + vhost_traffic_status_zone; + log_format basic '[$time_local] requestCounter:$requestCounter ' + 'inBytes:$inBytes outBytes:$outBytes ' + '2xx:$2xx'; + access_log logs/access.log basic; + upstream backend { + server localhost:1984; + } +--- config + location /status { + vhost_traffic_status_display; + vhost_traffic_status_display_format json; + access_log off; + } + location /v { + set $group upstream@alone; + set $zone 127.0.0.1:1984; + + vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter; + vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes; + vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes; + vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx; + + proxy_pass http://localhost:1984/return; + } +--- user_files eval +[ + ['return/file.txt' => '{"return":"OK"}'] +] +--- request eval +[ + 'GET /v/file.txt', + 'GET /v/file.txt', + 'GET /v/file.txt' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 3: access variables by vhost_traffic_status_set_by_filter $* upstream@group/*/* +--- http_config + vhost_traffic_status_zone; + log_format basic '[$time_local] requestCounter:$requestCounter ' + 'inBytes:$inBytes outBytes:$outBytes ' + '2xx:$2xx'; + access_log logs/access.log basic; + upstream backend { + server localhost:1984; + } +--- config + location /v { + set $group upstream@group; + set $zone backend@127.0.0.1:1984; + + vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter; + vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes; + vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes; + vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx; + + proxy_pass http://backend/return; + } +--- user_files eval +[ + ['return/file.txt' => '{"return":"OK"}'] +] +--- request eval +[ + 'GET /v/file.txt', + 'GET /v/file.txt', + 'GET /v/file.txt' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 4: access variables by vhost_traffic_status_set_by_filter $* filter/*/* +--- http_config + vhost_traffic_status_zone; + log_format basic '[$time_local] requestCounter:$requestCounter ' + 'inBytes:$inBytes outBytes:$outBytes ' + '2xx:$2xx'; + access_log logs/access.log basic; +--- config + location /v { + vhost_traffic_status_filter_by_set_key v group; + + set $group filter; + set $zone group@v; + + vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter; + vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes; + vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes; + vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx; + } +--- user_files eval +[ + ['v/file.txt' => '{"return":"OK"}'] +] +--- request eval +[ + 'GET /v/file.txt', + 'GET /v/file.txt', + 'GET /v/file.txt' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK' +] + + + +=== TEST 5: access variables by vhost_traffic_status_set_by_filter $* cache/*/* +--- http_config + vhost_traffic_status_zone; + proxy_cache_path cache_one levels=1:2 keys_zone=cache_one:2m inactive=1m max_size=4m; + log_format basic '[$time_local] requestCounter:$requestCounter ' + 'inBytes:$inBytes outBytes:$outBytes ' + '2xx:$2xx cacheMaxSize:$cacheMaxSize ' + 'cacheUsedSize:$cacheUsedSize cacheHit:$cacheHit'; + access_log logs/access.log basic; + upstream backend { + server localhost:1984; + } +--- config + location /v { + proxy_cache cache_one; + proxy_cache_valid 200 10s; + + set $group cache; + set $zone cache_one; + + vhost_traffic_status_set_by_filter $requestCounter $group/$zone/requestCounter; + vhost_traffic_status_set_by_filter $inBytes $group/$zone/inBytes; + vhost_traffic_status_set_by_filter $outBytes $group/$zone/outBytes; + vhost_traffic_status_set_by_filter $2xx $group/$zone/2xx; + + vhost_traffic_status_set_by_filter $cacheMaxSize $group/$zone/cacheMaxSize; + vhost_traffic_status_set_by_filter $cacheUsedSize $group/$zone/cacheUsedSize; + vhost_traffic_status_set_by_filter $cacheHit $group/$zone/cacheHit; + + proxy_pass http://backend/return; + } +--- user_files eval +[ + ['return/file.txt' => '{"return":"OK"}'] +] +--- request eval +[ + 'GET /v/file.txt', + 'GET /v/file.txt', + 'GET /v/file.txt' +] +--- response_body_like eval +[ + 'OK', + 'OK', + 'OK' +] diff --git a/modules/ngx_http_vts/util/fileToHex.pl b/modules/ngx_http_vts/util/fileToHex.pl new file mode 100644 index 0000000..b1151d8 --- /dev/null +++ b/modules/ngx_http_vts/util/fileToHex.pl @@ -0,0 +1,121 @@ +#! /usr/bin/env perl +# +# @file: fileToHex.pl +# @brief: +# @author: YoungJoo.Kim +# @version: +# @date: + +package FileToHex; + +use strict; +use Carp; + +sub new{ + my($class, %cnf) = @_; + + my $path = delete $cnf{path}; + my $handle = delete $cnf{handle}; + + my $self = + bless { + path => $path, + handle => $handle + }, $class; + + return bless $self; +} + +sub __exit { + my $self = shift if ref ($_[0]); + my $res = shift; + Carp::carp __PACKAGE__ . ": $res->{string}"; + exit($res->{return} || 1); +} + +sub fileOpen { + my $self = shift if ref ($_[0]); + my $path = shift || $self->{path}; + $path = $self->{path} unless defined $path; + (defined $path && -e $path) || $self->__exit({string => "error: [$path] is not defined or exists!"}); + open(my $handle, "<", $path) || $self->__exit({string => "error: open(): $!"}); + $self->{handle} = $handle; + return $self->{handle}; +} + +sub fileClose { + my $self = shift if ref ($_[0]); + my $handle = shift || $self->{handle}; + $handle && close($handle); +} + +sub fileReadByte { + my $self = shift if ref ($_[0]); + my $buf = \shift; + my $byte = shift || 1; + my $handle = shift || $self->{handle}; + return read($handle, $$buf, $byte); +} + +sub DESTROY { + my $self = shift if ref ($_[0]); + $self->fileClose(); +} + +1; + +package main; + +if ($#ARGV < 0) { + print "Usage: $0 {path} {max} {type}\n"; + exit(2); +} + +my $path = $ARGV[0]; +my $max = $ARGV[1] || 16; +my $type = $ARGV[2] || "buffer"; +my $plus = ""; +my $buf = ""; +my $i = 0; +my $fth = FileToHex->new(path => $path); + +$fth->fileOpen(); +if ($type eq "define") { + # type: define + while($fth->fileReadByte(my $c)) { + $i++; + $buf .= '\x' . unpack("H2", $c); + if (!($i % $max)) { + $plus .= "\"$buf\" \\\n"; + $buf = ""; + } + } + + if (!($i % $max)) { + print substr($plus, 0, -3) . "\n"; + + } else { + print $plus . "\"$buf\"\n"; + } + +} else { + # type: buffer + while($fth->fileReadByte(my $c)) { + $i++; + $buf .= '0x' . unpack("H2", $c) . ', '; + if (!($i % $max)) { + $plus .= "$buf\n"; + $buf = ""; + } + } + + if (!($i % $max)) { + print $plus . "0x00\n"; + + } else { + print $plus . $buf . "0x00\n"; + } +} +$fth->fileClose(); + +# vi:set ft=perl ts=4 sw=4 et fdm=marker: diff --git a/modules/ngx_http_vts/util/tplToBuffer.sh b/modules/ngx_http_vts/util/tplToBuffer.sh new file mode 100644 index 0000000..be6eb76 --- /dev/null +++ b/modules/ngx_http_vts/util/tplToBuffer.sh @@ -0,0 +1,36 @@ +#! /usr/bin/env bash +# +# @file: tplToDefine.sh +# @brief: +# @author: YoungJoo.Kim +# @version: +# @date: + +# Set up a default search path. +PATH="/sbin:/usr/sbin:/bin:/usr/bin" +export PATH + +template=$1 +if [ -z "$template" ]; then + echo "Usage: $0 {template.html}" + exit 2 +fi + +tmp=$template.$(date '+%s') + +\cp -af $template $tmp + +if [ -f "$tmp" ]; then + perl -p -i -e 's/%/%%/g' $tmp + perl -p -i -e 's/{{uri}}/%V/g' $tmp +fi + +echo "static char NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA[] = {" + +\perl fileToHex.pl $tmp 16 buffer + +echo "};" + +\rm -f $tmp + +# vi:set ft=sh ts=4 sw=4 et fdm=marker: diff --git a/modules/ngx_http_vts/util/tplToDefine.sh b/modules/ngx_http_vts/util/tplToDefine.sh new file mode 100644 index 0000000..020d92c --- /dev/null +++ b/modules/ngx_http_vts/util/tplToDefine.sh @@ -0,0 +1,34 @@ +#! /usr/bin/env bash +# +# @file: tplToDefine.sh +# @brief: +# @author: YoungJoo.Kim +# @version: +# @date: + +# Set up a default search path. +PATH="/sbin:/usr/sbin:/bin:/usr/bin" +export PATH + +template=$1 +if [ -z "$template" ]; then + echo "Usage: $0 {template.html}" + exit 2 +fi + +tmp=$template.$(date '+%s') + +\cp -af $template $tmp + +if [ -f "$tmp" ]; then + perl -p -i -e 's/%/%%/g' $tmp + perl -p -i -e 's/{{uri}}/%V/g' $tmp +fi + +echo "#define NGX_HTTP_VHOST_TRAFFIC_STATUS_HTML_DATA \\" + +\perl fileToHex.pl $tmp 16 define + +\rm -f $tmp + +# vi:set ft=sh ts=4 sw=4 et fdm=marker: diff --git a/modules/ngx_input_validation_module/config b/modules/ngx_input_validation_module/config new file mode 100644 index 0000000..df5aa81 --- /dev/null +++ b/modules/ngx_input_validation_module/config @@ -0,0 +1,12 @@ +ngx_addon_name=ngx_http_input_validation_module + +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP + ngx_module_name=ngx_http_input_validation_module + ngx_module_srcs="$ngx_addon_dir/ngx_input_validation_module.c" + . auto/module +else + + HTTP_MODULES="$HTTP_MODULES ngx_input_validation_module.c" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_addon_dir/ngx_input_validation_module.c" +fi diff --git a/modules/ngx_input_validation_module/ngx_input_validation_module.c b/modules/ngx_input_validation_module/ngx_input_validation_module.c new file mode 100644 index 0000000..58b141f --- /dev/null +++ b/modules/ngx_input_validation_module/ngx_input_validation_module.c @@ -0,0 +1,493 @@ + +/* + IronFox Input Validation Module + By: Khalgh Salehi , khaleghsalehi@gmail.com + Copyright (c) 2016 IronFox, info@ironfox.org * http://ironfox.org + Thanks Xiaomi Corp for https://github.com/54chen/nginx-http-hashdos-module + + */ +#include +#include +#include + +#ifndef NGX_HTTP_MAX_CAPTURES +#define NGX_HTTP_MAX_CAPTURES 9 +#endif + +static void *ngx_http_Input_Validation_create_loc_conf(ngx_conf_t *cf); + +static char *ngx_http_Input_Validation_merge_loc_conf(ngx_conf_t *cf, + void *parent, + void *child); + +static ngx_int_t ngx_http_Input_Validation_init(ngx_conf_t *cf); + +static ngx_int_t ngx_http_Input_Validation_handler(ngx_http_request_t *r); + +static void ngx_Input_Validation_request_body_handler(ngx_http_request_t *r); + +static char *ngx_http_Check_Input_Validation(ngx_conf_t *cf, + ngx_command_t *cmd, + void *conf); + +int string_ln(char *p); + + +int string_ln(char *p) { + int count = 0; + while (*p != '\0') { + count++; + p++; + } + return count; +} + +typedef struct { + /* Nginx config format: Value Type Length Action; + * e.g username "^[A-Za-z0-9]" 15 block; + * Discription: + * if the username do not match with [A-Za-z0-9] and the len > 15 then drop request + */ + ngx_str_t body_args_name; // Name of Variable + ngx_str_t body_args_type; // Type of Variable + ngx_str_t body_args_len; // Length of Variable + ngx_str_t action; // Action [Block/Learn] + int *captures; + ngx_int_t ncaptures; + ngx_regex_t *match_regex; +} Input_Validation_Args; + +/* + * Module configuration struct + */ +typedef struct { + ngx_flag_t enable; + ngx_int_t body_max_count; + ngx_array_t *Input_Validation_Items; // array of Input_Validation_Args +} ngx_http_Input_Validation_loc_conf_t; + +typedef struct { + ngx_flag_t done:1; + ngx_flag_t waiting_more_body:1; +} ngx_http_post_read_ctx_t; + +/* +Module directive +struct ngx_command_t { + ngx_str_t name; + ngx_uint_t type; + char *(*set)(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + ngx_uint_t conf; + ngx_uint_t offset; + void *post; +}; + */ + +static ngx_command_t ngx_http_Input_Validation_commands[] = { + {ngx_string("input_validation"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_Input_Validation_loc_conf_t, enable), + NULL}, + + {ngx_string("input_validation_arg"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE4, + ngx_http_Check_Input_Validation, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL}, + + {ngx_string("input_validation_max_arg"), + NGX_HTTP_MAIN_CONF | NGX_HTTP_SRV_CONF | NGX_HTTP_LOC_CONF | NGX_CONF_TAKE1, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_Input_Validation_loc_conf_t, body_max_count), + NULL}, + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_Input_Validation_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_Input_Validation_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_Input_Validation_create_loc_conf, /* create location configuration */ + ngx_http_Input_Validation_merge_loc_conf /* merge location configuration */ +}; + +static void *ngx_http_Input_Validation_create_loc_conf(ngx_conf_t *cf) { + ngx_http_Input_Validation_loc_conf_t *conf; + conf = ngx_pcalloc(cf->pool, + sizeof(ngx_http_Input_Validation_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + conf->enable = NGX_CONF_UNSET; + conf->body_max_count = NGX_CONF_UNSET; + return conf; +} + +static char *ngx_http_Input_Validation_merge_loc_conf(ngx_conf_t *cf, + void *parent, + void *child) { + ngx_http_Input_Validation_loc_conf_t *prev = parent; + ngx_http_Input_Validation_loc_conf_t *conf = child; + ngx_conf_merge_value(conf->enable, + prev->enable, + 1); + ngx_conf_merge_value(conf->body_max_count, + prev->body_max_count, + 1000); + return NGX_CONF_OK; +} + +/* + * Module definition + */ +ngx_module_t ngx_http_Input_Validation_module = { + NGX_MODULE_V1, + &ngx_http_Input_Validation_module_ctx, /* module context */ + ngx_http_Input_Validation_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t ngx_http_Input_Validation_init(ngx_conf_t *cf) { + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_core_module); + h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + *h = ngx_http_Input_Validation_handler; + return NGX_OK; +} + +static ngx_int_t ngx_http_Input_Validation_handler(ngx_http_request_t *r) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Start Input Validator."); + ngx_int_t rc; + ngx_http_Input_Validation_loc_conf_t *alcf; + ngx_http_post_read_ctx_t *ctx; + + alcf = ngx_http_get_module_loc_conf(r, + ngx_http_Input_Validation_module); + if (!alcf->enable) { + return NGX_OK; + } + ctx = ngx_http_get_module_ctx(r, + ngx_http_Input_Validation_module); + if (ctx != NULL) { + if (ctx->done) { + return NGX_DECLINED; + } + return NGX_DONE; + } + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_post_read_ctx_t)); + + if (ctx == NULL) { + ngx_http_finalize_request(r, NGX_ERROR); + return NGX_ERROR; + } + ngx_http_set_ctx(r, ctx, ngx_http_Input_Validation_module); + + rc = ngx_http_read_client_request_body(r, + ngx_Input_Validation_request_body_handler); + + if (rc == NGX_ERROR || rc >= NGX_HTTP_SPECIAL_RESPONSE) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Body Request is -> [%O] ", rc); + return rc; + } + + if (rc == NGX_AGAIN) { + ctx->waiting_more_body = 1; + return NGX_DONE; + } + + return NGX_DECLINED; +} + + +static char *ngx_http_Check_Input_Validation(ngx_conf_t *cf, + ngx_command_t *cmd, + void *conf) { + ngx_http_Input_Validation_loc_conf_t *rlcf = conf; + ngx_str_t *value; + Input_Validation_Args *pair; + // dont forget for any error handeling here, e.g NULL, etc... + value = cf->args->elts; + + if (rlcf->Input_Validation_Items == NULL) { + rlcf->Input_Validation_Items = ngx_array_create(cf->pool, + 4, + sizeof(Input_Validation_Args)); + if (rlcf->Input_Validation_Items == NULL) { + return NGX_CONF_ERROR; + } + } + pair = ngx_array_push(rlcf->Input_Validation_Items); + if (pair == NULL) { + return NGX_CONF_ERROR; + } + ngx_memzero(pair, sizeof(Input_Validation_Args)); + pair->body_args_name = value[1]; + pair->body_args_type = value[2]; + pair->body_args_len = value[3]; + pair->action = value[4]; + return NGX_CONF_OK; +} + + +static void ngx_Input_Validation_request_body_handler(ngx_http_request_t *r) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Body Transferring is over."); + ngx_http_Input_Validation_loc_conf_t *alcf; + ngx_int_t count, limit; + u_char ch, *p; + ngx_chain_t *cl; + ngx_buf_t *buf, *next; + ngx_http_post_read_ctx_t *ctx; + ngx_uint_t i; + ngx_int_t check_len = 0; + Input_Validation_Args *pairp, *pair; + + //Regex + ngx_int_t matchstatus = 0; + ngx_regex_compile_t rc; + ngx_str_t err; + ngx_int_t options; + options = 0; + + r->read_event_handler = ngx_http_request_empty_handler; + ctx = ngx_http_get_module_ctx(r, + ngx_http_Input_Validation_module); + ctx->done = 1; + r->main->count--; + + if (r->request_body == NULL || r->request_body->bufs == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Body Buffer is empty {NULL}"); + return; + } + + alcf = ngx_http_get_module_loc_conf(r, + ngx_http_Input_Validation_module); + if (alcf->body_max_count <= 0) { + limit = 800; //Change with your own risk, more value maybe cause DoS attack + } else { + limit = alcf->body_max_count; + } + + count = 0; + + cl = r->request_body->bufs; + buf = cl->buf; + next = '\0'; + + if (cl->next == NULL) { + + +/* + * + * Input Validation + */ + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[InputValidation] **** Start Input Validation ****"); + pairp = (Input_Validation_Args *) alcf->Input_Validation_Items->elts; + for (i = 0; i < alcf->Input_Validation_Items->nelts; i++) { + pair = &pairp[i]; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] ========================================"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Arg[Name]: %s", + pair->body_args_name.data); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Arg[Type]: %s", + pair->body_args_type.data); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Arg[Len]: %s", + pair->body_args_len.data); + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] ========================================"); + char BUFF[1024]; + int ic = 0; + for (p = buf->pos; p < buf->last; p++) { + //ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"[InputValidation] value %c",*p); + // Store characters in BUFF + BUFF[ic] = *p; + ic++; + } + BUFF[1024] = '\0'; // Null char for end of buffer + char *pch; + pch = strtok(BUFF, "&"); + while (pch != NULL) { + if (ngx_strstr(pch, pair->body_args_name.data)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "[Input_Validation] Item found.%s", pch); + /*First store the pch in another buffer and then delimit the sub-string*/ + char *pch2; + char BUFF2[1024]; + BUFF2[1024] = '\0'; + strncpy(BUFF2, pch, 1023); + int count = 1; + pch2 = strtok(BUFF2, "="); + while (pch2 != NULL) { + if (count > 1) { + // Variable=Value , we going to inspect the Value's Type & Length + // #Step 1, check the length + check_len = ngx_atoi(pair->body_args_len.data, + ngx_strlen(pair->body_args_len.data)); + if (check_len >= string_ln(pch2)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Item Value %s", pch2); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Item Size %d", check_len); + } + if (check_len < string_ln(pch2)) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Buffer Overflow Attack , Value %d", check_len); + // depend on the pair->action status ( block mode or profilng) + //return NGX_ERROR; + } + // #Step 2, check the type, using ngx_regex + rc.pattern = pair->body_args_type; + rc.pool = r->pool; + rc.err = err; + rc.options = options; + if (ngx_regex_compile(&rc) == NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Regex Ok"); + } + if (ngx_regex_compile(&rc) != NGX_OK) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Regex Error"); + } + + + if (pair->captures == NULL || pair->ncaptures == 0) { + pair->ncaptures = (NGX_HTTP_MAX_CAPTURES + 1) * 3; + pair->captures = ngx_palloc(r->pool, + pair->ncaptures * sizeof(int)); + if (pair->captures == NULL) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] cpatures allocation error"); + } + } + + + char ASL[1024]; + memset(ASL, '\0', 1024); + strncpy(ASL, pch2, 1024); + ngx_str_t dd_str = ngx_string(ASL); + pair->match_regex = rc.regex; + matchstatus = ngx_regex_exec(pair->match_regex, + &dd_str, + (int *) pair->captures, + pair->ncaptures); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] ASL -> , Value [%s]", dd_str.data); + + if (matchstatus == NGX_REGEX_NO_MATCHED) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] ==[ Type Attack ]=="); + if (ngx_strstr(pair->action.data, "block")) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Blocking Mod"); + // if Block Mod then send error and reject request + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + } + if (ngx_strstr(pair->action.data, "learn")) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] Profiling Mod"); + } + } + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] matchstatus , Value %d", matchstatus); + + if (matchstatus != NGX_REGEX_NO_MATCHED) { + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] ==[ Type Match, Safe.]=="); + + } + } + pch2 = strtok(NULL, "="); + count++; + }// End of While + }// End of if + pch = strtok(NULL, "&"); + }// End of While... + } + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] **** End of Input Validation ****"); + +/* + * + * Input Validation + */ + + for (p = buf->pos; p < buf->last; p++) { + ch = *p; + + if (ch == '&') { + count++; + } + } + } + if (cl->next != NULL) { + for (; cl; cl = cl->next) { + next = cl->buf; + + if (next->in_file) { + ngx_log_error(NGX_LOG_ERR, + r->connection->log, + 0, "[Input_Validation] in-file buffer found. aborted." + " consider increasing your client_body_buffer_size setting."); + ctx->waiting_more_body = 0; + ctx->done = 1; + r->main->count--; + return; + } + + for (p = next->pos; p < next->last; p++) { + ch = *p; + if (ch == '&') { + count++; + } + } + } + } + ++count; + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "[Input_Validation] parse request body parameters count is [%O], limit is [%O]", count, limit); + if (count >= limit) { + (void) ngx_http_discard_request_body(r); + ngx_http_finalize_request(r, NGX_HTTP_NOT_ALLOWED); + ngx_log_error(NGX_LOG_ERR, + r->connection->log, + 0, + "[Input_Validation] in rb->bfs -> client intended to send too large body: %O bytes, body size: %O, limit is: %O", + r->headers_in.content_length_n, + count, + limit); + ctx->waiting_more_body = 0; + ctx->done = 1; + r->main->count--; + } + + if (ctx->waiting_more_body) { + ctx->waiting_more_body = 0; + ngx_http_core_run_phases(r); + } +} + + diff --git a/modules/ngx_input_validation_module/readme.txt b/modules/ngx_input_validation_module/readme.txt new file mode 100644 index 0000000..6862b16 --- /dev/null +++ b/modules/ngx_input_validation_module/readme.txt @@ -0,0 +1,80 @@ +Nginx Input Validation Module + *Note: this module is not distributed with the Nginx source. + Installation instructions can be found below.* + + Description + Input Validation is a request inspection module which can do both regular + expression and fixed string on request bodies. + It inspect the request parameters and block the abnormal requests bases on rules. + + +Usage Example: + location /post.php { + input_validation on; + input_validation_arg "username" "^[a-zA-Z0-9_]" "10" block; + input_validation_arg "password" "^[A-Za-z0-9!@#$%^&*()_+]" "15" block; + input_validation_arg "phone" "^[+0-9]" "15" block ; + input_validation_arg "address" "^[A-Za-z0-9]" "40" block; + input_validation_max_arg 30; + error_log logs/error.log debug; + root html; + index index.html index.htm; + proxy_pass http://127.0.0.1:8080/post.php; + } + + Directives + * input_validation + context: *http, server, location* + Value: on|off ( Enable/Disable Module) + + + * input_validation_arg + context: *http, server, location* + Arguments Format: "Variable Name" "^[Regex]" "Variable Maximum Length" "Action" + where: + "Variable Name" to argument name in request body + "^[Regex]" to Regular Expression + "Variable Maximum Length" Variable Maximum Length , Integer + "Action" Action if the attack detection , "block" immediately block the request , "learn" for IronFox profiler + + * input_validation_max_arg + context: *http, server, location* + Define the maximum arguments count to blocking the hashdos attack. default is a 800. + + + Installation + To install, get the source with subversion: + + git clone + https://github.com/irontoolki/IronFox/tree/master/ironfox/ngx_Input_Validation_module + + and then compile Nginx with the following option: + + ./configure --add-module=/path/to/module + + Known issue + * + + + Reporting a bug + Questions/patches may be directed to khalegh Salehi, khaleghsalehi@gmail.com + +======================================================================== +Copyright & License + The code base is borrowed directly from the hashdos at https://github.com/54chen/nginx-http-hashdos-module . + This part of code is copyrighted by Xiaomi Corp. + + Copyright (c) 2016 , Khalegh Salehi , khaleghsalehi@gmail.com , IronFox.org. + + +This module is licensed under the terms of the BSD license. +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. +Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. +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/modules/replace-filter-nginx-module/.travis.yml b/modules/replace-filter-nginx-module/.travis.yml new file mode 100644 index 0000000..737f051 --- /dev/null +++ b/modules/replace-filter-nginx-module/.travis.yml @@ -0,0 +1,51 @@ +sudo: required +dist: xenial + +os: linux + +language: c + +compiler: + - gcc + - clang + +addons: + apt: + packages: + - axel + - cpanminus + - libluajit-5.1-dev + - libgd-dev + - libpcre3-dev + +cache: + apt: true + +env: + global: + - LUAJIT_LIB=/usr/lib64/libluajit-5.1.so + - LUAJIT_INC=/usr/include/luajit-2.0 + - LUA_INCLUDE_DIR=/usr/include/luajit-2.0 + - LUA_CMODULE_DIR=/lib + matrix: + - NGINX_VERSION=1.11.2 + - NGINX_VERSION=1.17.8 + +before_install: + - sudo cpanm --notest Test::Nginx > build.log 2>&1 || (cat build.log && exit 1) + +install: + - git clone https://github.com/openresty/openresty.git ../openresty + - git clone https://github.com/openresty/no-pool-nginx.git ../no-pool-nginx + - git clone https://github.com/openresty/nginx-devel-utils.git + - git clone https://github.com/openresty/lua-nginx-module.git ../lua-nginx-module + - git clone https://github.com/openresty/echo-nginx-module.git ../echo-nginx-module + - git clone https://github.com/simpl/ngx_devel_kit.git ../ndk-nginx-module + - git clone https://github.com/openresty/sregex.git + +script: + - cd sregex && sudo make PREFIX=/usr install && cd .. + - export PATH=$PWD/work/nginx/sbin:$PWD/nginx-devel-utils:$PATH + - sh util/build.sh $NGINX_VERSION > build.log 2>&1 || (cat build.log && exit 1) + - nginx -V + - prove -r t diff --git a/modules/replace-filter-nginx-module/config b/modules/replace-filter-nginx-module/config new file mode 100644 index 0000000..58127af --- /dev/null +++ b/modules/replace-filter-nginx-module/config @@ -0,0 +1,93 @@ +ngx_feature="agentzh's sregex library" +ngx_feature_libs="-lsregex" +ngx_feature_name= +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_test="sre_regex_t *re; + sre_program_t *prog; + sre_pool_t *pool; + u_char s[] = {'a', 'b', 'c'}; + sre_int_t rc, err_offset, ovector; + sre_int_t *pending_matched; + sre_uint_t ncaps; + sre_vm_pike_ctx_t *pctx; + pool = sre_create_pool(1024); + re = sre_regex_parse(pool, s, &ncaps, 0, &err_offset); + prog = sre_regex_compile(pool, re); + pctx = sre_vm_pike_create_ctx(pool, prog, &ovector, 0); + rc = sre_vm_pike_exec(pctx, s, 32, 1, &pending_matched); + sre_destroy_pool(pool)" + +if [ -n "$SREGEX_INC" -o -n "$SREGEX_LIB" ]; then + # explicitly set sregex lib path + ngx_feature="agentzh's sregex library in $SREGEX_LIB and $SREGEX_INC (specified by the SREGEX_LIB and SREGEX_INC env)" + ngx_feature_path="$SREGEX_INC" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R$SREGEX_LIB -L$SREGEX_LIB -lsregex" + else + ngx_feature_libs="-L$SREGEX_LIB -lsregex" + fi + + . auto/feature + + if [ $ngx_found = no ]; then + cat << END + $0: error: ngx_http_replace_filter_module requires agentzh's sregex library and SREGEX_LIB is defined as $SREGEX_LIB and SREGEX_INC (path for sregex/sregex.h) $SREGEX_INC, but we cannot find sregex there. +END + exit 1 + fi + +else + # auto-discovery + ngx_feature="agentzh's sregex library" + ngx_feature_libs="-lsregex" + . auto/feature + + if [ $ngx_found = no ]; then + # default installation prefix in sregex + ngx_feature="agentzh's sregex library in /usr/local/" + ngx_feature_path="/usr/local/include" + if [ $NGX_RPATH = YES ]; then + ngx_feature_libs="-R/usr/local/lib -L/usr/local/lib -lsregex" + else + ngx_feature_libs="-L/usr/local/lib -lsregex" + fi + . auto/feature + fi +fi + +if [ $ngx_found = no ]; then + cat << END + $0: error: ngx_http_replace_filter_module requires agentzh's sregex library. +END + exit 1 +fi + +REPLACE_FILTER_SRCS="$ngx_addon_dir/src/ngx_http_replace_filter_module.c \ + $ngx_addon_dir/src/ngx_http_replace_script.c \ + $ngx_addon_dir/src/ngx_http_replace_parse.c \ + $ngx_addon_dir/src/ngx_http_replace_util.c" +REPLACE_FILTER_DEPS="$ngx_addon_dir/src/ngx_http_replace_filter_module.h \ + $ngx_addon_dir/src/ngx_http_replace_script.h \ + $ngx_addon_dir/src/ngx_http_replace_parse.h \ + $ngx_addon_dir/src/ngx_http_replace_util.h" + +ngx_addon_name=ngx_http_replace_filter_module +if test -n "$ngx_module_link"; then + ngx_module_type=HTTP_AUX_FILTER + ngx_module_name=$ngx_addon_name + ngx_module_srcs="$REPLACE_FILTER_SRCS" + ngx_module_deps="$REPLACE_FILTER_DEPS" + ngx_module_incs=$ngx_feature_path + ngx_module_libs=$ngx_feature_libs + + . auto/module + +else + HTTP_AUX_FILTER_MODULES="$HTTP_AUX_FILTER_MODULES $ngx_addon_name" + NGX_ADDON_SRCS="$NGX_ADDON_SRCS $REPLACE_FILTER_SRCS" + NGX_ADDON_DEPS="$NGX_ADDON_DEPS $REPLACE_FILTER_DEPS" + CORE_INCS="$CORE_INCS $ngx_feature_path" + CORE_LIBS="$CORE_LIBS $ngx_feature_libs" +fi diff --git a/modules/replace-filter-nginx-module/src/ddebug.h b/modules/replace-filter-nginx-module/src/ddebug.h new file mode 100644 index 0000000..3e5d4f5 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ddebug.h @@ -0,0 +1,112 @@ +#ifndef DDEBUG_H +#define DDEBUG_H + + +#include +#include +#include + + +#if defined(DDEBUG) && (DDEBUG) + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) fprintf(stderr, "replace_filter *** %s: ", __func__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " at %s line %d.\n", __FILE__, __LINE__) + +# else + +#include +#include + +#include + +static void dd(const char * fmt, ...) { +} + +# endif + +# if DDEBUG > 1 + +# define dd_enter() dd_enter_helper(r, __func__) + +static void dd_enter_helper(ngx_http_request_t *r, const char *func) { + ngx_http_posted_request_t *pr; + + fprintf(stderr, ">enter %s %.*s %.*s?%.*s c:%d m:%p r:%p ar:%p pr:%p", + func, + (int) r->method_name.len, r->method_name.data, + (int) r->uri.len, r->uri.data, + (int) r->args.len, r->args.data, + 0/*(int) r->main->count*/, r->main, + r, r->connection->data, r->parent); + + if (r->posted_requests) { + fprintf(stderr, " posted:"); + + for (pr = r->posted_requests; pr; pr = pr->next) { + fprintf(stderr, "%p,", pr); + } + } + + fprintf(stderr, "\n"); +} + +# else + +# define dd_enter() + +# endif + +#else + +# if (NGX_HAVE_VARIADIC_MACROS) + +# define dd(...) + +# define dd_enter() + +# else + +#include + +static void dd(const char * fmt, ...) { +} + +static void dd_enter() { +} + +# endif + +#endif + +#if defined(DDEBUG) && (DDEBUG) + +#define dd_check_read_event_handler(r) \ + dd("r->read_event_handler = %s", \ + r->read_event_handler == ngx_http_block_reading ? \ + "ngx_http_block_reading" : \ + r->read_event_handler == ngx_http_test_reading ? \ + "ngx_http_test_reading" : \ + r->read_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#define dd_check_write_event_handler(r) \ + dd("r->write_event_handler = %s", \ + r->write_event_handler == ngx_http_handler ? \ + "ngx_http_handler" : \ + r->write_event_handler == ngx_http_core_run_phases ? \ + "ngx_http_core_run_phases" : \ + r->write_event_handler == ngx_http_request_empty_handler ? \ + "ngx_http_request_empty_handler" : "UNKNOWN") + +#else + +#define dd_check_read_event_handler(r) +#define dd_check_write_event_handler(r) + +#endif + +#endif /* DDEBUG_H */ + diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.c b/modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.c new file mode 100644 index 0000000..815bd21 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.c @@ -0,0 +1,1021 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_replace_filter_module.h" +#include "ngx_http_replace_parse.h" +#include "ngx_http_replace_script.h" +#include "ngx_http_replace_util.h" + + +enum { + SREGEX_COMPILER_POOL_SIZE = 4096 +}; + + +static ngx_int_t ngx_http_replace_output(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx); +static char *ngx_http_replace_filter(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static void *ngx_http_replace_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_replace_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); +static ngx_int_t ngx_http_replace_filter_init(ngx_conf_t *cf); +static void ngx_http_replace_cleanup_pool(void *data); +static void *ngx_http_replace_create_main_conf(ngx_conf_t *cf); + + +#define ngx_http_replace_regex_is_disabled(ctx) \ + ((ctx)->disabled[(ctx)->regex_id / 8] & (1 << ((ctx)->regex_id % 8))) + + +#define ngx_http_replace_regex_set_disabled(ctx) \ + (ctx)->disabled[(ctx)->regex_id / 8] |= (1 << ((ctx)->regex_id % 8)) + + +static volatile ngx_cycle_t *ngx_http_replace_prev_cycle = NULL; + + +#define NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED 0 +#define NGX_HTTP_REPLACE_KEEP_LAST_MODIFIED 1 + + +static ngx_conf_enum_t ngx_http_replace_filter_last_modified[] = { + { ngx_string("clear"), NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED }, + { ngx_string("keep"), NGX_HTTP_REPLACE_KEEP_LAST_MODIFIED }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_replace_filter_commands[] = { + + { ngx_string("replace_filter"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE23, + ngx_http_replace_filter, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("replace_filter_types"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE, + ngx_http_types_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_replace_loc_conf_t, types_keys), + &ngx_http_html_default_types[0] }, + + { ngx_string("replace_filter_max_buffered_size"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_replace_loc_conf_t, max_buffered_size), + NULL }, + + { ngx_string("replace_filter_last_modified"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_1MORE, + ngx_conf_set_enum_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_replace_loc_conf_t, last_modified), + &ngx_http_replace_filter_last_modified }, + + { ngx_string("replace_filter_skip"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF + |NGX_CONF_TAKE1, + ngx_http_set_complex_value_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_replace_loc_conf_t, skip), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_replace_filter_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_replace_filter_init, /* postconfiguration */ + + ngx_http_replace_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_replace_create_loc_conf, /* create location configuration */ + ngx_http_replace_merge_loc_conf /* merge location configuration */ +}; + + +ngx_module_t ngx_http_replace_filter_module = { + NGX_MODULE_V1, + &ngx_http_replace_filter_module_ctx, /* module context */ + ngx_http_replace_filter_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_http_output_header_filter_pt ngx_http_next_header_filter; +static ngx_http_output_body_filter_pt ngx_http_next_body_filter; + + +static ngx_int_t +ngx_http_replace_header_filter(ngx_http_request_t *r) +{ + size_t size; + ngx_str_t skip; + ngx_pool_cleanup_t *cln; + ngx_http_replace_ctx_t *ctx; + ngx_http_replace_loc_conf_t *rlcf; + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_replace_filter_module); + + dd("replace header filter"); + + if (rlcf->regexes.nelts == 0 + || r->headers_out.content_length_n == 0 + || (r->headers_out.content_encoding + && r->headers_out.content_encoding->value.len) + || ngx_http_test_content_type(r, &rlcf->types) == NULL) + { + return ngx_http_next_header_filter(r); + } + + dd("skip: %p", rlcf->skip); + + if (rlcf->skip != NULL) { + if (ngx_http_complex_value(r, rlcf->skip, &skip) != NGX_OK) { + return NGX_ERROR; + } + + if (skip.len && (skip.len != 1 || skip.data[0] != '0')) { + return ngx_http_next_header_filter(r); + } + } + + ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_replace_ctx_t)); + if (ctx == NULL) { + return NGX_ERROR; + } + + ctx->last_special = &ctx->special; + ctx->last_pending = &ctx->pending; + ctx->last_pending2 = &ctx->pending2; + ctx->last_captured = &ctx->captured; + + ctx->sub = ngx_pcalloc(r->pool, + rlcf->multi_replace.nelts * sizeof(ngx_str_t)); + if (ctx->sub == NULL) { + return NGX_ERROR; + } + + ctx->ovector = ngx_palloc(r->pool, rlcf->ovecsize); + if (ctx->ovector == NULL) { + return NGX_ERROR; + } + + size = ngx_align(rlcf->regexes.nelts, 8) / 8; + ctx->disabled = ngx_pcalloc(r->pool, size); + if (ctx->disabled == NULL) { + return NGX_ERROR; + } + + ctx->vm_pool = sre_create_pool(1024); + if (ctx->vm_pool == NULL) { + return NGX_ERROR; + } + + dd("created vm pool %p", ctx->vm_pool); + + cln = ngx_pool_cleanup_add(r->pool, 0); + if (cln == NULL) { + sre_destroy_pool(ctx->vm_pool); + return NGX_ERROR; + } + + cln->data = ctx->vm_pool; + cln->handler = ngx_http_replace_cleanup_pool; + + ctx->vm_ctx = sre_vm_pike_create_ctx(ctx->vm_pool, rlcf->program, + ctx->ovector, rlcf->ovecsize); + if (ctx->vm_ctx == NULL) { + return NGX_ERROR; + } + + ngx_http_set_ctx(r, ctx, ngx_http_replace_filter_module); + + ctx->last_out = &ctx->out; + + r->filter_need_in_memory = 1; + + if (r == r->main) { + ngx_http_clear_content_length(r); + + if (rlcf->last_modified == NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED) { + ngx_http_clear_last_modified(r); + } + } + + return ngx_http_next_header_filter(r); +} + + +static void +ngx_http_replace_cleanup_pool(void *data) +{ + sre_pool_t *pool = data; + + if (pool) { + dd("destroy sre pool %p", pool); + sre_destroy_pool(pool); + } +} + + +static ngx_int_t +ngx_http_replace_body_filter(ngx_http_request_t *r, ngx_chain_t *in) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_str_t *sub; + ngx_chain_t *cl, *cur = NULL, *rematch = NULL; + + ngx_http_replace_ctx_t *ctx; + ngx_http_replace_loc_conf_t *rlcf; + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_replace_filter_module); + + ctx = ngx_http_get_module_ctx(r, ngx_http_replace_filter_module); + + if (ctx == NULL) { + return ngx_http_next_body_filter(r, in); + } + + if ((in == NULL + && ctx->buf == NULL + && ctx->in == NULL + && ctx->busy == NULL)) + { + return ngx_http_next_body_filter(r, in); + } + + if ((ctx->once || ctx->vm_done) && (ctx->buf == NULL || ctx->in == NULL)) { + + if (ctx->busy) { + if (ngx_http_replace_output(r, ctx) == NGX_ERROR) { + return NGX_ERROR; + } + } + + return ngx_http_next_body_filter(r, in); + } + + /* add the incoming chain to the chain ctx->in */ + + if (in) { + if (ngx_chain_add_copy(r->pool, &ctx->in, in) != NGX_OK) { + return NGX_ERROR; + } + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http sub filter \"%V\"", &r->uri); + + while (ctx->in || ctx->buf) { + + if (ctx->buf == NULL) { + cur = ctx->in; + ctx->buf = cur->buf; + ctx->in = cur->next; + + ctx->pos = ctx->buf->pos; + ctx->special_buf = ngx_buf_special(ctx->buf); + ctx->last_buf = (ctx->buf->last_buf || ctx->buf->last_in_chain); + + dd("=== new incoming buf: size=%d, special=%u, last=%u", + (int) ngx_buf_size(ctx->buf), ctx->special_buf, + ctx->last_buf); + } + + b = NULL; + + while (ctx->pos < ctx->buf->last + || (ctx->special_buf && ctx->last_buf)) + { + rc = rlcf->parse_buf(r, ctx, rematch); + + ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "replace filter parse: %d, %p-%p", + rc, ctx->copy_start, ctx->copy_end); + + if (rc == NGX_ERROR) { + return rc; + } + + if (rc == NGX_DECLINED) { + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (!ctx->special_buf) { + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + + } else { + ctx->copy_start = NULL; + ctx->copy_end = NULL; + } + + sre_reset_pool(ctx->vm_pool); + ctx->vm_done = 1; + } + + dd("copy_end - copy_start: %d, special: %u", + (int) (ctx->copy_end - ctx->copy_start), ctx->special_buf); + + if (ctx->copy_start != ctx->copy_end && !ctx->special_buf) { + dd("copy: %.*s", (int) (ctx->copy_end - ctx->copy_start), + ctx->copy_start); + + cl = ngx_http_replace_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + b = cl->buf; + + b->memory = 1; + b->pos = ctx->copy_start; + b->last = ctx->copy_end; + + *ctx->last_out = cl; + ctx->last_out = &cl->next; + } + + if (rc == NGX_AGAIN) { + if (ctx->special_buf && ctx->last_buf) { + break; + } + + continue; + } + + if (rc == NGX_DECLINED) { + break; + } + + /* rc == NGX_OK || rc == NGX_BUSY */ + + cl = ngx_http_replace_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + b = cl->buf; + + dd("free data buf: %p", b); + + sub = &ctx->sub[ctx->regex_id]; + + if (sub->data == NULL + || rlcf->parse_buf == ngx_http_replace_capturing_parse) + { + ngx_http_replace_complex_value_t *cv; + + if (ngx_http_replace_regex_is_disabled(ctx)) { + cv = &rlcf->verbatim; + + } else { + cv = rlcf->multi_replace.elts; + cv = &cv[ctx->regex_id]; + } + + if (ngx_http_replace_complex_value(r, ctx->captured, + rlcf->ncaps, + ctx->ovector, + cv, sub) + != NGX_OK) + { + return NGX_ERROR; + } + + /* release ctx->captured */ + if (ctx->captured) { + dd("release ctx captured: %p", ctx->captured); + *ctx->last_captured = ctx->free; + ctx->free = ctx->captured; + + ctx->captured = NULL; + ctx->last_captured = &ctx->captured; + } + } + + dd("emit replaced value: \"%.*s\"", (int) sub->len, sub->data); + + if (sub->len) { + b->memory = 1; + b->pos = sub->data; + b->last = sub->data + sub->len; + + } else { + b->sync = 1; + } + + cl->buf = b; + cl->next = NULL; + + *ctx->last_out = cl; + ctx->last_out = &cl->next; + + if (!ctx->once && !ngx_http_replace_regex_is_disabled(ctx)) { + uint8_t *once; + + once = rlcf->multi_once.elts; + + if (rlcf->regexes.nelts == 1) { + ctx->once = once[0]; + + } else { + if (once[ctx->regex_id]) { + ngx_http_replace_regex_set_disabled(ctx); + if (!rlcf->seen_global + && ++ctx->disabled_count == rlcf->regexes.nelts) + { + ctx->once = 1; + } + } + } + } + + if (rc == NGX_BUSY) { + dd("goto rematch"); + goto rematch; + } + + if (ctx->special_buf) { + break; + } + + continue; + } + + if ((ctx->buf->flush || ctx->last_buf || ngx_buf_in_memory(ctx->buf)) + && cur) + { + if (b == NULL) { + cl = ngx_http_replace_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + b = cl->buf; + b->sync = 1; + + *ctx->last_out = cl; + ctx->last_out = &cl->next; + } + + dd("setting shadow and last buf: %d", (int) ctx->buf->last_buf); + b->last_buf = ctx->buf->last_buf; + b->last_in_chain = ctx->buf->last_in_chain; + b->flush = ctx->buf->flush; + b->shadow = ctx->buf; + b->recycled = ctx->buf->recycled; + } + + if (!ctx->special_buf) { + ctx->stream_pos += ctx->buf->last - ctx->buf->pos; + } + + if (rematch) { + rematch->next = ctx->free; + ctx->free = rematch; + rematch = NULL; + } + +rematch: + + dd("ctx->rematch: %p", ctx->rematch); + + if (ctx->rematch == NULL) { + ctx->buf = NULL; + cur = NULL; + + } else { + + if (cur) { + ctx->in = cur; + cur = NULL; + } + + ctx->buf = ctx->rematch->buf; + + dd("ctx->buf set to rematch buf %p, len=%d, next=%p", + ctx->buf, (int) ngx_buf_size(ctx->buf), ctx->rematch->next); + + rematch = ctx->rematch; + ctx->rematch = rematch->next; + + ctx->pos = ctx->buf->pos; + ctx->special_buf = ngx_buf_special(ctx->buf); + ctx->last_buf = (ctx->buf->last_buf || ctx->buf->last_in_chain); + ctx->stream_pos = ctx->buf->file_pos; + } + +#if (DDEBUG) + /* + ngx_http_replace_dump_chain("ctx->pending", &ctx->pending, + ctx->last_pending); + ngx_http_replace_dump_chain("ctx->pending2", &ctx->pending2, + ctx->last_pending2); + */ +#endif + } /* while */ + + if (ctx->out == NULL && ctx->busy == NULL) { + return NGX_OK; + } + + return ngx_http_replace_output(r, ctx); +} + + +static ngx_int_t +ngx_http_replace_output(ngx_http_request_t *r, ngx_http_replace_ctx_t *ctx) +{ + ngx_int_t rc; + ngx_buf_t *b; + ngx_chain_t *cl; + +#if (DDEBUG) + b = NULL; + for (cl = ctx->out; cl; cl = cl->next) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "replace out: %p %p", cl->buf, cl->buf->pos); + if (cl->buf == b) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "the same buf was used in sub"); + ngx_debug_point(); + return NGX_ERROR; + } + b = cl->buf; + } + + /* ngx_http_replace_dump_chain("ctx->out", &ctx->out, ctx->last_out); */ +#endif + + rc = ngx_http_next_body_filter(r, ctx->out); + + /* we are essentially duplicating the logic of + * ngx_chain_update_chains below, + * with our own optimizations */ + + if (ctx->busy == NULL) { + ctx->busy = ctx->out; + + } else { + for (cl = ctx->busy; cl->next; cl = cl->next) { /* void */ } + cl->next = ctx->out; + } + + ctx->out = NULL; + ctx->last_out = &ctx->out; + + while (ctx->busy) { + + cl = ctx->busy; + b = cl->buf; + + if (ngx_buf_size(b) != 0) { + break; + } + + if (cl->buf->tag != (ngx_buf_tag_t) &ngx_http_replace_filter_module) { + ctx->busy = cl->next; + ngx_free_chain(r->pool, cl); + continue; + } + + if (b->shadow) { + b->shadow->pos = b->shadow->last; + b->shadow->file_pos = b->shadow->file_last; + } + + ctx->busy = cl->next; + + if (ngx_buf_special(b)) { + + /* collect special bufs to ctx->special, which may still be busy */ + + cl->next = NULL; + *ctx->last_special = cl; + ctx->last_special = &cl->next; + + } else { + + /* add ctx->special to ctx->free because they cannot be busy at + * this point */ + + *ctx->last_special = ctx->free; + ctx->free = ctx->special; + ctx->special = NULL; + ctx->last_special = &ctx->special; + +#if 0 + /* free the temporary buf's data block if it is big enough */ + if (b->temporary + && b->start != NULL + && b->end - b->start > (ssize_t) r->pool->max) + { + ngx_pfree(r->pool, b->start); + } +#endif + + /* add the data buf itself to the free buf chain */ + + cl->next = ctx->free; + ctx->free = cl; + } + } + + if (ctx->in || ctx->buf) { + r->buffered |= NGX_HTTP_SUB_BUFFERED; + + } else { + r->buffered &= ~NGX_HTTP_SUB_BUFFERED; + } + + return rc; +} + + +static char * +ngx_http_replace_filter(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_replace_loc_conf_t *rlcf = conf; + ngx_http_replace_main_conf_t *rmcf; + + int *flags; + u_char *p, **re; + ngx_str_t *value; + ngx_uint_t i; + uint8_t *once; + + ngx_pool_cleanup_t *cln; + ngx_http_replace_complex_value_t *cv; + ngx_http_replace_compile_complex_value_t ccv; + + value = cf->args->elts; + + re = ngx_array_push(&rlcf->regexes); + if (re == NULL) { + return NGX_CONF_ERROR; + } + + *re = value[1].data; + + cv = ngx_array_push(&rlcf->multi_replace); + if (cv == NULL) { + return NGX_CONF_ERROR; + } + + ngx_memzero(cv, sizeof(ngx_http_replace_complex_value_t)); + ngx_memzero(&ccv, sizeof(ngx_http_replace_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &value[2]; + ccv.complex_value = cv; + + if (ngx_http_replace_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + + /* check variable usage in the "replace" argument */ + + if (cv->capture_variables) { + rlcf->parse_buf = ngx_http_replace_capturing_parse; + + } else if (rlcf->parse_buf == NULL) { + rlcf->parse_buf = ngx_http_replace_non_capturing_parse; + } + +#if 0 + rlcf->parse_buf = ngx_http_replace_capturing_parse; +#endif + + flags = ngx_array_push(&rlcf->multi_flags); + if (flags == NULL) { + return NGX_CONF_ERROR; + } + *flags = 0; + + once = ngx_array_push(&rlcf->multi_once); + if (once == NULL) { + return NGX_CONF_ERROR; + } + *once = 1; /* default to once */ + + if (cf->args->nelts == 4) { + /* 3 user args */ + + p = value[3].data; + + for (i = 0; i < value[3].len; i++) { + switch (p[i]) { + case 'i': + *flags |= SRE_REGEX_CASELESS; + break; + + case 'g': + *once = 0; + break; + + default: + return "specifies an unrecognized regex flag"; + } + } + } + + if (*once) { + rlcf->seen_once = 1; + + } else { + rlcf->seen_global = 1; + } + + if (rlcf->seen_once && rlcf->regexes.nelts > 1) { + rlcf->parse_buf = ngx_http_replace_capturing_parse; + + if (rlcf->verbatim.value.data == NULL) { + ngx_str_t v = ngx_string("$&"); + + ngx_memzero(&ccv, sizeof(ngx_http_replace_compile_complex_value_t)); + + ccv.cf = cf; + ccv.value = &v; + ccv.complex_value = &rlcf->verbatim; + + if (ngx_http_replace_compile_complex_value(&ccv) != NGX_OK) { + return NGX_CONF_ERROR; + } + } + } + + rmcf = + ngx_http_conf_get_module_main_conf(cf, ngx_http_replace_filter_module); + + if (rmcf->compiler_pool == NULL) { + rmcf->compiler_pool = sre_create_pool(SREGEX_COMPILER_POOL_SIZE); + if (rmcf->compiler_pool == NULL) { + return NGX_CONF_ERROR; + } + + cln = ngx_pool_cleanup_add(cf->pool, 0); + if (cln == NULL) { + sre_destroy_pool(rmcf->compiler_pool); + rmcf->compiler_pool = NULL; + return NGX_CONF_ERROR; + } + + cln->data = rmcf->compiler_pool; + cln->handler = ngx_http_replace_cleanup_pool; + } + + return NGX_CONF_OK; +} + + +static void * +ngx_http_replace_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_replace_loc_conf_t *conf; + + conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_replace_loc_conf_t)); + if (conf == NULL) { + return NULL; + } + + /* + * set by ngx_pcalloc(): + * + * conf->types = { NULL }; + * conf->types_keys = NULL; + * conf->program = NULL; + * conf->ncaps = 0; + * conf->ovecsize = 0; + * conf->parse_buf = NULL; + * conf->verbatim = { {0, NULL}, NULL, NULL, 0 }; + * conf->seen_once = 0; + * conf->seen_global = 0; + * conf->skip = NULL; + */ + + conf->max_buffered_size = NGX_CONF_UNSET_SIZE; + conf->last_modified = NGX_CONF_UNSET_UINT; + + ngx_array_init(&conf->multi_replace, cf->pool, 4, + sizeof(ngx_http_replace_complex_value_t)); + + ngx_array_init(&conf->multi_flags, cf->pool, 4, sizeof(int)); + + ngx_array_init(&conf->regexes, cf->pool, 4, sizeof(u_char *)); + + ngx_array_init(&conf->multi_once, cf->pool, 4, sizeof(uint8_t)); + + return conf; +} + + +static char * +ngx_http_replace_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + u_char **value; + sre_int_t err_offset, err_regex_id; + ngx_str_t prefix, suffix; + sre_pool_t *ppool; /* parser pool */ + sre_regex_t *re; + sre_program_t *prog; + + ngx_http_replace_main_conf_t *rmcf; + + ngx_http_replace_loc_conf_t *prev = parent; + ngx_http_replace_loc_conf_t *conf = child; + + ngx_conf_merge_size_value(conf->max_buffered_size, + prev->max_buffered_size, + 8192); + + ngx_conf_merge_uint_value(conf->last_modified, + prev->last_modified, + NGX_HTTP_REPLACE_CLEAR_LAST_MODIFIED); + + if (ngx_http_merge_types(cf, &conf->types_keys, &conf->types, + &prev->types_keys, &prev->types, + ngx_http_html_default_types) + != NGX_OK) + { + return NGX_CONF_ERROR; + } + + if (conf->skip == NULL) { + conf->skip = prev->skip; + } + + if (conf->regexes.nelts > 0 && conf->program == NULL) { + + dd("parsing and compiling %d regexes", (int) conf->regexes.nelts); + + ppool = sre_create_pool(1024); + if (ppool == NULL) { + return NGX_CONF_ERROR; + } + + value = conf->regexes.elts; + + re = sre_regex_parse_multi(ppool, value, conf->regexes.nelts, + &conf->ncaps, conf->multi_flags.elts, + &err_offset, &err_regex_id); + + if (re == NULL) { + + if (err_offset >= 0) { + prefix.data = value[err_regex_id]; + prefix.len = err_offset; + + suffix.data = value[err_regex_id] + err_offset; + suffix.len = ngx_strlen(value[err_regex_id]) - err_offset; + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "failed to parse regex at offset %i: " + "syntax error; marked by <-- HERE in " + "\"%V <-- HERE %V\"", + (ngx_int_t) err_offset, &prefix, &suffix); + + } else { + + if (err_regex_id >= 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "failed to parse regex \"%s\"", + value[err_regex_id]); + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "failed to parse regex \"%s\" " + "and its siblings", + value[0]); + } + } + + sre_destroy_pool(ppool); + return NGX_CONF_ERROR; + } + + rmcf = ngx_http_conf_get_module_main_conf(cf, + ngx_http_replace_filter_module); + + prog = sre_regex_compile(rmcf->compiler_pool, re); + + sre_destroy_pool(ppool); + + if (prog == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "failed to compile regex \"%s\" and its " + "siblings", value[0]); + + return NGX_CONF_ERROR; + } + + conf->program = prog; + conf->ovecsize = 2 * (conf->ncaps + 1) * sizeof(sre_int_t); + + } else { + + conf->regexes = prev->regexes; + conf->multi_once = prev->multi_once; + conf->multi_flags = prev->multi_flags; + conf->multi_replace = prev->multi_replace; + conf->parse_buf = prev->parse_buf; + conf->verbatim = prev->verbatim; + conf->program = prev->program; + conf->ncaps = prev->ncaps; + conf->ovecsize = prev->ovecsize; + conf->seen_once = prev->seen_once; + conf->seen_global = prev->seen_global; + } + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_replace_filter_init(ngx_conf_t *cf) +{ + int multi_http_blocks; + ngx_http_replace_main_conf_t *rmcf; + + rmcf = + ngx_http_conf_get_module_main_conf(cf, ngx_http_replace_filter_module); + + if (ngx_http_replace_prev_cycle != ngx_cycle) { + ngx_http_replace_prev_cycle = ngx_cycle; + multi_http_blocks = 0; + + } else { + multi_http_blocks = 1; + } + + if (multi_http_blocks || rmcf->compiler_pool != NULL) { + ngx_http_next_header_filter = ngx_http_top_header_filter; + ngx_http_top_header_filter = ngx_http_replace_header_filter; + + ngx_http_next_body_filter = ngx_http_top_body_filter; + ngx_http_top_body_filter = ngx_http_replace_body_filter; + + return NGX_OK; + } + + return NGX_OK; +} + + +static void * +ngx_http_replace_create_main_conf(ngx_conf_t *cf) +{ + ngx_http_replace_main_conf_t *rmcf; + + rmcf = ngx_pcalloc(cf->pool, sizeof(ngx_http_replace_main_conf_t)); + if (rmcf == NULL) { + return NULL; + } + + /* set by ngx_pcalloc: + * rmcf->compiler_pool = NULL; + */ + + return rmcf; +} diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.h b/modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.h new file mode 100644 index 0000000..4380905 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_filter_module.h @@ -0,0 +1,99 @@ +#ifndef _NGX_HTTP_REPLACE_FILTER_MODULE_H_INCLUDED_ +#define _NGX_HTTP_REPLACE_FILTER_MODULE_H_INCLUDED_ + + +#include "ngx_http_replace_script.h" +#include +#include +#include +#include + + +extern ngx_module_t ngx_http_replace_filter_module; + + +typedef struct { + sre_int_t regex_id; + sre_int_t stream_pos; + sre_int_t *ovector; + sre_pool_t *vm_pool; + sre_vm_pike_ctx_t *vm_ctx; + + ngx_chain_t *pending; /* pending data before the + pending matched capture */ + ngx_chain_t **last_pending; + + ngx_chain_t *pending2; /* pending data after the pending + matched capture */ + ngx_chain_t **last_pending2; + + ngx_buf_t *buf; + + ngx_str_t *sub; + + u_char *pos; + u_char *copy_start; + u_char *copy_end; + + ngx_chain_t *in; + ngx_chain_t *out; + ngx_chain_t **last_out; + ngx_chain_t *busy; + ngx_chain_t *free; + ngx_chain_t *special; + ngx_chain_t **last_special; + ngx_chain_t *rematch; + ngx_chain_t *captured; + ngx_chain_t **last_captured; + uint8_t *disabled; + sre_uint_t disabled_count; + + size_t total_buffered; + + unsigned once:1; + unsigned vm_done:1; + unsigned special_buf:1; + unsigned last_buf:1; +} ngx_http_replace_ctx_t; + + +typedef ngx_int_t (*ngx_http_replace_parse_buf_pt)(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, ngx_chain_t *rematch); + + +typedef struct { + sre_pool_t *compiler_pool; +} ngx_http_replace_main_conf_t; + + +typedef struct { + sre_uint_t ncaps; + size_t ovecsize; + + ngx_array_t multi_once; /* of uint8_t */ + ngx_array_t regexes; /* of u_char* */ + ngx_array_t multi_flags; /* of int */ + ngx_array_t multi_replace; + /* of ngx_http_replace_complex_value_t */ + + sre_program_t *program; + + ngx_hash_t types; + ngx_array_t *types_keys; + + size_t max_buffered_size; + + ngx_uint_t last_modified; + /* replace_filter_last_modified */ + + ngx_http_replace_parse_buf_pt parse_buf; + ngx_http_replace_complex_value_t verbatim; + + ngx_http_complex_value_t *skip; + + unsigned seen_once; /* :1 */ + unsigned seen_global; /* :1 */ +} ngx_http_replace_loc_conf_t; + + +#endif /* _NGX_HTTP_REPLACE_FILTER_MODULE_H_INCLUDED_ */ diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_parse.c b/modules/replace-filter-nginx-module/src/ngx_http_replace_parse.c new file mode 100644 index 0000000..cd65ef1 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_parse.c @@ -0,0 +1,937 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + * Copyright (C) Igor Sysoev + * Copyright (C) Nginx, Inc. + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_replace_parse.h" +#include "ngx_http_replace_util.h" + + +static void ngx_http_replace_check_total_buffered(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, sre_int_t len, sre_int_t mlen); + + +ngx_int_t +ngx_http_replace_capturing_parse(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, ngx_chain_t *rematch) +{ + sre_int_t ret, from, to; + ngx_int_t rc; + ngx_chain_t *new_rematch = NULL; + ngx_chain_t *cl; + ngx_chain_t **last_rematch, **last; + size_t len; + + dd("replace capturing parse"); + + if (ctx->once || ctx->vm_done) { + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once"); + + return NGX_AGAIN; + } + + len = ctx->buf->last - ctx->pos; + + dd("=== process data chunk %p len=%d, pos=%u, special=%u, " + "last=%u, \"%.*s\"", ctx->buf, (int) (ctx->buf->last - ctx->pos), + (int) (ctx->pos - ctx->buf->pos + ctx->stream_pos), + ctx->special_buf, ctx->last_buf, + (int) (ctx->buf->last - ctx->pos), ctx->pos); + + ret = sre_vm_pike_exec(ctx->vm_ctx, ctx->pos, len, ctx->last_buf, NULL); + + dd("vm pike exec: %d", (int) ret); + + if (ret >= 0) { + ctx->regex_id = ret; + ctx->total_buffered = 0; + + from = ctx->ovector[0]; + to = ctx->ovector[1]; + + dd("pike vm ok: (%d, %d)", (int) from, (int) to); + + if (from >= ctx->stream_pos) { + /* the match is completely on the current buf */ + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + /* prepare ctx->captured */ + + cl = ngx_http_replace_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf->pos = ctx->buf->pos; + cl->buf->last = ctx->buf->last; + cl->buf->memory = 1; + cl->buf->file_pos = ctx->stream_pos; + cl->buf->file_last = ctx->stream_pos + + (cl->buf->last - cl->buf->pos); + + *ctx->last_captured = cl; + ctx->last_captured = &cl->next; + + dd("ctx captured: %p", ctx->captured); + + /* prepare copy-out data */ + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->pos + (from - ctx->stream_pos); + + dd("copy len: %d", (int) (ctx->copy_end - ctx->copy_start)); + + ctx->pos = ctx->buf->pos + (to - ctx->stream_pos); + return NGX_OK; + } + + /* from < ctx->stream_pos */ + + if (ctx->pending) { + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending, + &ctx->last_pending, from, + &cl, &last, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (cl) { + if (to >= ctx->stream_pos) { + /* no pending data to be rematched */ + + if (to == ctx->stream_pos) { + *ctx->last_captured = cl; + ctx->last_captured = &cl->next; + + } else { + *ctx->last_captured = cl; + ctx->last_captured = last; + + cl = ngx_http_replace_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + cl->buf->pos = ctx->buf->pos; + cl->buf->last = ctx->buf->last; + cl->buf->memory = 1; + cl->buf->file_pos = ctx->stream_pos; + cl->buf->file_last = ctx->stream_pos + + (cl->buf->last - cl->buf->pos); + + *ctx->last_captured = cl; + ctx->last_captured = &cl->next; + } + + } else { + /* there's pending data to be rematched */ + + if (ngx_http_replace_split_chain(r, ctx, &cl, + &last, + to, &new_rematch, + &last_rematch, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + if (cl) { + *ctx->last_captured = cl; + ctx->last_captured = last; + } + + if (new_rematch) { + if (rematch) { + ctx->rematch = rematch; + } + + /* prepend cl to ctx->rematch */ + *last_rematch = ctx->rematch; + ctx->rematch = new_rematch; + } + } + } + } + +#if (DDEBUG) + ngx_http_replace_dump_chain("ctx->rematch", &ctx->rematch, NULL); +#endif + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + + ctx->pos = ctx->buf->pos + (to - ctx->stream_pos); + + return new_rematch ? NGX_BUSY : NGX_OK; + } + + switch (ret) { + case SRE_AGAIN: + from = ctx->ovector[0]; + to = ctx->ovector[1]; + + dd("pike vm again: (%d, %d)", (int) from, (int) to); + + if (from == -1) { + from = ctx->stream_pos + (ctx->buf->last - ctx->buf->pos); + } + + if (to == -1) { + to = ctx->stream_pos + (ctx->buf->last - ctx->buf->pos); + } + + dd("pike vm again (adjusted): stream pos:%d, (%d, %d)", + (int) ctx->stream_pos, (int) from, (int) to); + + if (from > to) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "invalid capture range: %i > %i", (ngx_int_t) from, + (ngx_int_t) to); + return NGX_ERROR; + } + + if (from == to) { + if (ctx->pending) { + ctx->total_buffered = 0; + + dd("output pending"); + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->pos + (from - ctx->stream_pos); + ctx->pos = ctx->copy_end; + + return NGX_AGAIN; + } + + /* + * append the existing ctx->pending data right before + * the $& capture to ctx->out. + */ + + if (from >= ctx->stream_pos) { + /* the match is completely on the current buf */ + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->pos + (from - ctx->stream_pos); + + if (ctx->pending) { + ctx->total_buffered = 0; + + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + dd("create ctx->pending as (%ld, %ld)", (long) from, (long) to); + rc = ngx_http_replace_new_pending_buf(r, ctx, from, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + +#if 1 + if (rc == NGX_BUSY) { + dd("stop processing because of buffer size limit reached"); + ctx->once = 1; + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + return NGX_AGAIN; + } +#endif + + *ctx->last_pending = cl; + ctx->last_pending = &cl->next; + + ctx->pos = ctx->buf->last; + + return NGX_AGAIN; + } + + dd("from < ctx->stream_pos"); + + if (ctx->pending) { + /* split ctx->pending into ctx->out and ctx->pending */ + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending, + &ctx->last_pending, from, &cl, + &last, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->pending) { + dd("adjust pending: pos=%d, from=%d", + (int) ctx->pending->buf->file_pos, (int) from); + + ctx->total_buffered -= (size_t) + (from - ctx->pending->buf->file_pos); + + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (cl) { + dd("splitted ctx->pending into ctx->out and ctx->pending: %d", + (int) ctx->total_buffered); + + ctx->pending = cl; + ctx->last_pending = last; + } + } + + /* new pending data to buffer to ctx->pending */ + + rc = ngx_http_replace_new_pending_buf(r, ctx, ctx->pos + - ctx->buf->pos + + ctx->stream_pos, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + +#if 1 + if (rc == NGX_BUSY) { + ctx->once = 1; + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + + return NGX_AGAIN; + } +#endif + + *ctx->last_pending = cl; + ctx->last_pending = &cl->next; + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + + ctx->pos = ctx->buf->last; + + return NGX_AGAIN; + + case SRE_DECLINED: + ctx->total_buffered = 0; + + return NGX_DECLINED; + + default: + /* SRE_ERROR */ + return NGX_ERROR; + } + + /* cannot reach here */ +} + + +ngx_int_t +ngx_http_replace_non_capturing_parse(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, ngx_chain_t *rematch) +{ + sre_int_t ret, from, to, mfrom = -1, mto = -1; + ngx_int_t rc; + ngx_chain_t *new_rematch = NULL; + ngx_chain_t *cl; + ngx_chain_t **last_rematch, **last; + size_t len; + sre_int_t *pending_matched; + + dd("replace non capturing parse"); + + if (ctx->once || ctx->vm_done) { + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "once"); + + return NGX_AGAIN; + } + + len = ctx->buf->last - ctx->pos; + + dd("=== process data chunk %p len=%d, pos=%u, special=%u, " + "last=%u, \"%.*s\"", ctx->buf, (int) (ctx->buf->last - ctx->pos), + (int) (ctx->pos - ctx->buf->pos + ctx->stream_pos), + ctx->special_buf, ctx->last_buf, + (int) (ctx->buf->last - ctx->pos), ctx->pos); + + ret = sre_vm_pike_exec(ctx->vm_ctx, ctx->pos, len, ctx->last_buf, + &pending_matched); + + dd("vm pike exec: %d", (int) ret); + + if (ret >= 0) { + ctx->regex_id = ret; + ctx->total_buffered = 0; + + from = ctx->ovector[0]; + to = ctx->ovector[1]; + + dd("pike vm ok: (%d, %d)", (int) from, (int) to); + + if (from >= ctx->stream_pos) { + /* the match is completely on the current buf */ + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (ctx->pending2) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "assertion failed: ctx->pending2 is not NULL " + "when the match is completely on the current " + "buf"); + return NGX_ERROR; + } + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->pos + (from - ctx->stream_pos); + + dd("copy len: %d", (int) (ctx->copy_end - ctx->copy_start)); + + ctx->pos = ctx->buf->pos + (to - ctx->stream_pos); + return NGX_OK; + } + + /* from < ctx->stream_pos */ + + if (ctx->pending) { + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending, + &ctx->last_pending, from, + &cl, &last, 0) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (cl) { + *last = ctx->free; + ctx->free = cl; + } + } + + if (ctx->pending2) { + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending2, + &ctx->last_pending2, + to, &new_rematch, &last_rematch, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->pending2) { + *ctx->last_pending2 = ctx->free; + ctx->free = ctx->pending2; + + ctx->pending2 = NULL; + ctx->last_pending2 = &ctx->pending2; + } + + if (new_rematch) { + if (rematch) { + ctx->rematch = rematch; + } + + /* prepend cl to ctx->rematch */ + *last_rematch = ctx->rematch; + ctx->rematch = new_rematch; + } + } + +#if (DDEBUG) + ngx_http_replace_dump_chain("ctx->rematch", &ctx->rematch, NULL); +#endif + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + + ctx->pos = ctx->buf->pos + (to - ctx->stream_pos); + + return new_rematch ? NGX_BUSY : NGX_OK; + } + + switch (ret) { + case SRE_AGAIN: + from = ctx->ovector[0]; + to = ctx->ovector[1]; + + dd("pike vm again: (%d, %d)", (int) from, (int) to); + + if (from == -1) { + from = ctx->stream_pos + (ctx->buf->last - ctx->buf->pos); + } + + if (to == -1) { + to = ctx->stream_pos + (ctx->buf->last - ctx->buf->pos); + } + + dd("pike vm again (adjusted): stream pos:%d, (%d, %d)", + (int) ctx->stream_pos, (int) from, (int) to); + + if (from > to) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "invalid capture range: %i > %i", (ngx_int_t) from, + (ngx_int_t) to); + return NGX_ERROR; + } + + if (pending_matched) { + mfrom = pending_matched[0]; + mto = pending_matched[1]; + + dd("pending matched: (%ld, %ld)", (long) mfrom, (long) mto); + } + + if (from == to) { + if (ctx->pending) { + ctx->total_buffered = 0; + + dd("output pending"); + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->pos + (from - ctx->stream_pos); + ctx->pos = ctx->copy_end; + + ngx_http_replace_check_total_buffered(r, ctx, to - from, + mto - mfrom); + return NGX_AGAIN; + } + + /* + * append the existing ctx->pending data right before + * the $& capture to ctx->out. + */ + + if (from >= ctx->stream_pos) { + /* the match is completely on the current buf */ + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->pos + (from - ctx->stream_pos); + + if (ctx->pending) { + ctx->total_buffered = 0; + + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (ctx->pending2) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "assertion failed: ctx->pending2 is not NULL " + "when the match is completely on the current " + "buf"); + return NGX_ERROR; + } + + if (pending_matched) { + + if (from < mfrom) { + /* create ctx->pending as (from, mfrom) */ + + rc = ngx_http_replace_new_pending_buf(r, ctx, from, mfrom, + &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_BUSY) { + dd("stop processing because of buffer size limit " + "reached"); + ctx->once = 1; + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + return NGX_AGAIN; + } + + *ctx->last_pending = cl; + ctx->last_pending = &cl->next; + } + + if (mto < to) { + /* create ctx->pending2 as (mto, to) */ + rc = ngx_http_replace_new_pending_buf(r, ctx, mto, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + +#if 1 + if (rc == NGX_BUSY) { + dd("stop processing because of buffer size limit " + "reached"); + ctx->once = 1; + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + return NGX_AGAIN; + } +#endif + + *ctx->last_pending2 = cl; + ctx->last_pending2 = &cl->next; + } + + } else { + dd("create ctx->pending as (%ld, %ld)", (long) from, (long) to); + rc = ngx_http_replace_new_pending_buf(r, ctx, from, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + +#if 1 + if (rc == NGX_BUSY) { + dd("stop processing because of buffer size limit reached"); + ctx->once = 1; + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + return NGX_AGAIN; + } +#endif + + *ctx->last_pending = cl; + ctx->last_pending = &cl->next; + } + + ctx->pos = ctx->buf->last; + + ngx_http_replace_check_total_buffered(r, ctx, to - from, + mto - mfrom); + + return NGX_AGAIN; + } + + dd("from < ctx->stream_pos"); + + if (ctx->pending) { + /* split ctx->pending into ctx->out and ctx->pending */ + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending, + &ctx->last_pending, from, &cl, + &last, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->pending) { + dd("adjust pending: pos=%d, from=%d", + (int) ctx->pending->buf->file_pos, (int) from); + + ctx->total_buffered -= (size_t) + (from - ctx->pending->buf->file_pos); + + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + if (cl) { + dd("splitted ctx->pending into ctx->out and ctx->pending: %d", + (int) ctx->total_buffered); + ctx->pending = cl; + ctx->last_pending = last; + } + + if (pending_matched && !ctx->pending2 && mto >= ctx->stream_pos) { + dd("splitting ctx->pending into ctx->pending and ctx->free"); + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending, + &ctx->last_pending, mfrom, &cl, + &last, 0) + != NGX_OK) + { + return NGX_ERROR; + } + + if (cl) { + ctx->total_buffered -= (size_t) (ctx->stream_pos - mfrom); + + dd("splitted ctx->pending into ctx->pending and ctx->free"); + *last = ctx->free; + ctx->free = cl; + } + } + } + + if (ctx->pending2) { + + if (pending_matched) { + dd("splitting ctx->pending2 into ctx->free and ctx->pending2"); + + if (ngx_http_replace_split_chain(r, ctx, &ctx->pending2, + &ctx->last_pending2, + mto, &cl, &last, 1) + != NGX_OK) + { + return NGX_ERROR; + } + + if (ctx->pending2) { + + dd("total buffered reduced by %d (was %d)", + (int) (mto - ctx->pending2->buf->file_pos), + (int) ctx->total_buffered); + + ctx->total_buffered -= (size_t) + (mto - ctx->pending2->buf->file_pos); + + *ctx->last_pending2 = ctx->free; + ctx->free = ctx->pending2; + + ctx->pending2 = NULL; + ctx->last_pending2 = &ctx->pending2; + } + + if (cl) { + ctx->pending2 = cl; + ctx->last_pending2 = last; + } + } + + if (mto < to) { + dd("new pending data to buffer to ctx->pending2: (%ld, %ld)", + (long) mto, (long) to); + + rc = ngx_http_replace_new_pending_buf(r, ctx, mto, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + +#if 1 + if (rc == NGX_BUSY) { + ctx->once = 1; + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + + if (ctx->pending2) { + new_rematch = ctx->pending2; + last_rematch = ctx->last_pending2; + + if (rematch) { + ctx->rematch = rematch; + } + + /* prepend cl to ctx->rematch */ + *last_rematch = ctx->rematch; + ctx->rematch = new_rematch; + + ctx->pending2 = NULL; + ctx->last_pending2 = &ctx->pending2; + } + + ctx->pos = ctx->buf->pos + (mto - ctx->stream_pos); + return new_rematch ? NGX_BUSY : NGX_OK; + } +#endif + + *ctx->last_pending2 = cl; + ctx->last_pending2 = &cl->next; + } + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + + ctx->pos = ctx->buf->last; + + ngx_http_replace_check_total_buffered(r, ctx, to - from, + mto - mfrom); + + return NGX_AGAIN; + } + + /* ctx->pending2 == NULL */ + + if (pending_matched) { + + if (mto < to) { + /* new pending data to buffer to ctx->pending2 */ + rc = ngx_http_replace_new_pending_buf(r, ctx, mto, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + + if (rc == NGX_BUSY) { + ctx->once = 1; + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + ctx->pos = ctx->buf->pos + mto - ctx->stream_pos; + + return NGX_OK; + } + + *ctx->last_pending2 = cl; + ctx->last_pending2 = &cl->next; + } + + /* otherwise no new data to buffer */ + + } else { + + /* new pending data to buffer to ctx->pending */ + rc = ngx_http_replace_new_pending_buf(r, ctx, ctx->pos + - ctx->buf->pos + + ctx->stream_pos, to, &cl); + if (rc == NGX_ERROR) { + return NGX_ERROR; + } + +#if 1 + if (rc == NGX_BUSY) { + ctx->once = 1; + + if (ctx->pending) { + *ctx->last_out = ctx->pending; + ctx->last_out = ctx->last_pending; + + ctx->pending = NULL; + ctx->last_pending = &ctx->pending; + } + + ctx->copy_start = ctx->pos; + ctx->copy_end = ctx->buf->last; + ctx->pos = ctx->buf->last; + + return NGX_AGAIN; + } +#endif + + *ctx->last_pending = cl; + ctx->last_pending = &cl->next; + } + + ctx->copy_start = NULL; + ctx->copy_end = NULL; + + ctx->pos = ctx->buf->last; + + ngx_http_replace_check_total_buffered(r, ctx, to - from, + mto - mfrom); + + return NGX_AGAIN; + + case SRE_DECLINED: + ctx->total_buffered = 0; + + return NGX_DECLINED; + + default: + /* SRE_ERROR */ + return NGX_ERROR; + } + + /* cannot reach here */ +} + + +static void +ngx_http_replace_check_total_buffered(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, sre_int_t len, sre_int_t mlen) +{ + dd("total buffered: %d", (int) ctx->total_buffered); + + if ((ssize_t) ctx->total_buffered != len - mlen) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "replace filter: ctx->total_buffered out of " + "sync: it is %i but should be %uz", + ctx->total_buffered, (ngx_int_t) (len - mlen)); + +#if (DDEBUG) + assert(0); +#endif + } +} diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_parse.h b/modules/replace-filter-nginx-module/src/ngx_http_replace_parse.h new file mode 100644 index 0000000..8a92f10 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_parse.h @@ -0,0 +1,14 @@ +#ifndef _NGX_HTTP_REPLACE_PARSE_H_INCLUDED_ +#define _NGX_HTTP_REPLACE_PARSE_H_INCLUDED_ + + +#include "ngx_http_replace_filter_module.h" + + +ngx_int_t ngx_http_replace_non_capturing_parse(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, ngx_chain_t *rematch); +ngx_int_t ngx_http_replace_capturing_parse(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, ngx_chain_t *rematch); + + +#endif /* _NGX_HTTP_REPLACE_PARSE_H_INCLUDED_ */ diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_script.c b/modules/replace-filter-nginx-module/src/ngx_http_replace_script.c new file mode 100644 index 0000000..fe3c0ce --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_script.c @@ -0,0 +1,721 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_replace_script.h" + + +static void *ngx_http_replace_script_add_code(ngx_array_t *codes, size_t size); +static size_t ngx_http_replace_script_copy_len_code( + ngx_http_replace_script_engine_t *e); +static size_t + ngx_http_replace_script_copy_code(ngx_http_replace_script_engine_t *e); +static ngx_int_t ngx_http_replace_script_add_copy_code( + ngx_http_replace_script_compile_t *sc, ngx_str_t *value, ngx_uint_t last); +static ngx_int_t + ngx_http_replace_script_compile(ngx_http_replace_script_compile_t *sc); +static ngx_int_t ngx_http_replace_script_add_capture_code( + ngx_http_replace_script_compile_t *sc, ngx_uint_t n); +static size_t ngx_http_replace_script_copy_capture_len_code( + ngx_http_replace_script_engine_t *e); +static size_t ngx_http_replace_script_copy_capture_code( + ngx_http_replace_script_engine_t *e); +static ngx_int_t + ngx_http_replace_script_done(ngx_http_replace_script_compile_t *sc); +static ngx_int_t ngx_http_replace_script_init_arrays( + ngx_http_replace_script_compile_t *sc); +static ngx_int_t + ngx_http_replace_script_add_var_code(ngx_http_replace_script_compile_t *sc, + ngx_str_t *name); +static size_t + ngx_http_replace_script_copy_var_len_code( + ngx_http_replace_script_engine_t *e); +static size_t + ngx_http_replace_script_copy_var_code(ngx_http_replace_script_engine_t *e); +static void ngx_http_replace_count_variables(u_char *src, size_t len, + ngx_uint_t *ngxvars, ngx_uint_t *capvars); + + +ngx_int_t +ngx_http_replace_compile_complex_value( + ngx_http_replace_compile_complex_value_t *ccv) +{ + ngx_str_t *v; + ngx_uint_t n, ngxvars, capvars; + ngx_array_t lengths, values, *pl, *pv; + + ngx_http_replace_script_compile_t sc; + + v = ccv->value; + + ngx_http_replace_count_variables(v->data, v->len, &ngxvars, &capvars); + + ccv->complex_value->value = *v; + ccv->complex_value->lengths = NULL; + ccv->complex_value->values = NULL; + + if (capvars == 0 && ngxvars == 0) { + return NGX_OK; + } + + n = capvars * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_capture_code_t)) + + ngxvars * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_var_code_t)) + + sizeof(uintptr_t); + + if (ngx_array_init(&lengths, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + n = capvars * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_capture_code_t)) + + ngxvars * (2 * sizeof(ngx_http_replace_script_var_code_t) + + sizeof(ngx_http_replace_script_var_code_t)) + + sizeof(uintptr_t); + + if (ngx_array_init(&values, ccv->cf->pool, n, 1) != NGX_OK) { + return NGX_ERROR; + } + + pl = &lengths; + pv = &values; + + ngx_memzero(&sc, sizeof(ngx_http_replace_script_compile_t)); + + sc.cf = ccv->cf; + sc.source = v; + sc.lengths = &pl; + sc.values = &pv; + + if (ngx_http_replace_script_compile(&sc) != NGX_OK) { + ngx_array_destroy(&lengths); + ngx_array_destroy(&values); + return NGX_ERROR; + } + + ccv->complex_value->lengths = lengths.elts; + ccv->complex_value->values = values.elts; + ccv->complex_value->capture_variables = sc.capture_variables; + + return NGX_OK; +} + + +ngx_int_t +ngx_http_replace_complex_value(ngx_http_request_t *r, + ngx_chain_t *captured, sre_uint_t ncaps, sre_int_t *cap, + ngx_http_replace_complex_value_t *val, ngx_str_t *value) +{ + size_t len; + ngx_http_replace_script_code_pt code; + ngx_http_replace_script_len_code_pt lcode; + ngx_http_replace_script_engine_t e; + + if (val->lengths == NULL) { + *value = val->value; + return NGX_OK; + } + + ngx_memzero(&e, sizeof(ngx_http_replace_script_engine_t)); + + e.request = r; + e.ncaptures = (ncaps + 1) * 2; + e.captures_data = captured; + e.captures = cap; + e.ip = val->lengths; + + len = 0; + + while (*(uintptr_t *) e.ip) { + lcode = *(ngx_http_replace_script_len_code_pt *) e.ip; + len += lcode(&e); + } + + value->len = len; + value->data = ngx_pnalloc(r->pool, len); + if (value->data == NULL) { + return NGX_ERROR; + } + + e.ip = val->values; + e.pos = value->data; + + while (*(uintptr_t *) e.ip) { + code = *(ngx_http_replace_script_code_pt *) e.ip; + code((ngx_http_replace_script_engine_t *) &e); + } + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_replace_script_compile(ngx_http_replace_script_compile_t *sc) +{ + u_char ch; + ngx_str_t name; + ngx_uint_t i, bracket; + unsigned num_var; + ngx_uint_t n = 0; + + if (ngx_http_replace_script_init_arrays(sc) != NGX_OK) { + return NGX_ERROR; + } + + for (i = 0; i < sc->source->len; /* void */ ) { + + name.len = 0; + + if (sc->source->data[i] == '$') { + + if (++i == sc->source->len) { + goto invalid_variable; + } + + if (sc->source->data[i] == '$') { + name.data = &sc->source->data[i]; + i++; + name.len++; + sc->size += name.len; + + if (ngx_http_replace_script_add_copy_code(sc, &name, + (i == sc->source->len)) + != NGX_OK) + { + return NGX_ERROR; + } + + continue; + } + + if ((sc->source->data[i] >= '1' && sc->source->data[i] <= '9') + || sc->source->data[i] == '&') + { + num_var = 1; + n = 0; + + } else { + num_var = 0; + } + + if (sc->source->data[i] == '{') { + bracket = 1; + + if (++i == sc->source->len) { + goto invalid_variable; + } + + if ((sc->source->data[i] >= '1' && sc->source->data[i] <= '9') + || sc->source->data[i] == '&') + { + num_var = 1; + n = 0; + } + + name.data = &sc->source->data[i]; + + } else { + bracket = 0; + name.data = &sc->source->data[i]; + } + + for ( /* void */ ; i < sc->source->len; i++, name.len++) { + ch = sc->source->data[i]; + + if (ch == '}' && bracket) { + i++; + bracket = 0; + break; + } + + if (num_var) { + if (ch >= '0' && ch <= '9') { + n = n * 10 + (ch - '0'); + continue; + } + + if (ch == '&') { + i++; + name.len++; + } + + break; + } + + /* not a number variable like $1, $2, etc */ + + if ((ch >= 'A' && ch <= 'Z') + || (ch >= 'a' && ch <= 'z') + || (ch >= '0' && ch <= '9') + || ch == '_') + { + continue; + } + + break; + } + + if (bracket) { + ngx_log_error(NGX_LOG_ERR, sc->cf->log, 0, + "the closing bracket in \"%V\" " + "variable is missing", &name); + return NGX_ERROR; + } + + if (name.len == 0) { + goto invalid_variable; + } + + if (num_var) { + dd("found numbered capturing variable \"%.*s\"", + (int) name.len, name.data); + + sc->capture_variables++; + + if (ngx_http_replace_script_add_capture_code(sc, n) != NGX_OK) { + return NGX_ERROR; + } + + } else { + sc->nginx_variables++; + + if (ngx_http_replace_script_add_var_code(sc, &name) != NGX_OK) { + return NGX_ERROR; + } + } + + continue; + } + + name.data = &sc->source->data[i]; + + while (i < sc->source->len) { + + if (sc->source->data[i] == '$') { + break; + } + + i++; + name.len++; + } + + sc->size += name.len; + + if (ngx_http_replace_script_add_copy_code(sc, &name, + (i == sc->source->len)) + != NGX_OK) + { + return NGX_ERROR; + } + } + + return ngx_http_replace_script_done(sc); + +invalid_variable: + + ngx_log_error(NGX_LOG_ERR, sc->cf->log, 0, + "replace script: invalid capturing variable name found " + "in \"%V\"", sc->source); + + return NGX_ERROR; +} + + +static ngx_int_t +ngx_http_replace_script_add_copy_code(ngx_http_replace_script_compile_t *sc, + ngx_str_t *value, ngx_uint_t last) +{ + size_t size, len; + ngx_http_replace_script_copy_code_t *code; + + len = value->len; + + code = ngx_http_replace_script_add_code(*sc->lengths, + sizeof(ngx_http_replace_script_copy_code_t)); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_replace_script_code_pt) + ngx_http_replace_script_copy_len_code; + code->len = len; + + size = (sizeof(ngx_http_replace_script_copy_code_t) + len + + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1); + + code = ngx_http_replace_script_add_code(*sc->values, size); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_replace_script_code_pt) + ngx_http_replace_script_copy_code; + code->len = len; + + ngx_memcpy((u_char *) code + sizeof(ngx_http_replace_script_copy_code_t), + value->data, value->len); + + return NGX_OK; +} + + +static size_t +ngx_http_replace_script_copy_len_code(ngx_http_replace_script_engine_t *e) +{ + ngx_http_replace_script_copy_code_t *code; + + code = (ngx_http_replace_script_copy_code_t *) e->ip; + + e->ip += sizeof(ngx_http_replace_script_copy_code_t); + + return code->len; +} + + +static size_t +ngx_http_replace_script_copy_code(ngx_http_replace_script_engine_t *e) +{ + u_char *p; + + ngx_http_replace_script_copy_code_t *code; + + code = (ngx_http_replace_script_copy_code_t *) e->ip; + + p = e->pos; + + if (!e->skip) { + e->pos = ngx_copy(p, e->ip + + sizeof(ngx_http_replace_script_copy_code_t), + code->len); + } + + e->ip += sizeof(ngx_http_replace_script_copy_code_t) + + ((code->len + sizeof(uintptr_t) - 1) & ~(sizeof(uintptr_t) - 1)); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "replace script copy: \"%*s\"", e->pos - p, p); + + return 0; +} + + +static ngx_int_t +ngx_http_replace_script_add_capture_code(ngx_http_replace_script_compile_t *sc, + ngx_uint_t n) +{ + ngx_http_replace_script_capture_code_t *code; + + code = ngx_http_replace_script_add_code(*sc->lengths, + sizeof(ngx_http_replace_script_capture_code_t)); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_replace_script_code_pt) + ngx_http_replace_script_copy_capture_len_code; + code->n = 2 * n; + + code = ngx_http_replace_script_add_code(*sc->values, + sizeof(ngx_http_replace_script_capture_code_t)); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_replace_script_code_pt) + ngx_http_replace_script_copy_capture_code; + code->n = 2 * n; + + return NGX_OK; +} + + +static size_t +ngx_http_replace_script_copy_capture_len_code( + ngx_http_replace_script_engine_t *e) +{ + sre_int_t *cap; + ngx_uint_t n; + + ngx_http_replace_script_capture_code_t *code; + + code = (ngx_http_replace_script_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_replace_script_capture_code_t); + + n = code->n; + + dd("group index: %d, ncaptures: %d", (int) n, (int) e->ncaptures); + + if (n + 1 < e->ncaptures) { + cap = e->captures; + return cap[n + 1] - cap[n]; + } + + return 0; +} + + +static size_t +ngx_http_replace_script_copy_capture_code(ngx_http_replace_script_engine_t *e) +{ + sre_int_t *cap, from, to, len; + u_char *p; +#if (NGX_DEBUG) + u_char *pos; +#endif + ngx_uint_t n; + ngx_chain_t *cl; + + ngx_http_replace_script_capture_code_t *code; + + code = (ngx_http_replace_script_capture_code_t *) e->ip; + + e->ip += sizeof(ngx_http_replace_script_capture_code_t); + + n = code->n; + +#if (NGX_DEBUG) + pos = e->pos; +#endif + + if (n < e->ncaptures) { + + cap = e->captures; + from = cap[n]; + to = cap[n + 1]; + + dd("captures data: %p", e->captures_data); + + for (cl = e->captures_data; cl; cl = cl->next) { + + if (from >= cl->buf->file_last) { + continue; + } + + /* from < cl->buf->file_last */ + + if (to <= cl->buf->file_pos) { + break; + } + + p = cl->buf->pos + (from - cl->buf->file_pos); + len = ngx_min(cl->buf->file_last, to) - from; + e->pos = ngx_copy(e->pos, p, len); + from += len; + } + } + +#if (NGX_DEBUG) + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, + "replace script capture: \"%*s\"", e->pos - pos, pos); +#endif + + return 0; +} + + +static ngx_int_t +ngx_http_replace_script_init_arrays(ngx_http_replace_script_compile_t *sc) +{ + ngx_uint_t n; + + if (*sc->lengths == NULL) { + n = sc->capture_variables + * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_capture_code_t)) + + sc->nginx_variables + * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_var_code_t)) + + sizeof(uintptr_t); + + *sc->lengths = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->lengths == NULL) { + return NGX_ERROR; + } + } + + if (*sc->values == NULL) { + n = sc->capture_variables + * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_capture_code_t)) + + sc->nginx_variables + * (2 * sizeof(ngx_http_replace_script_copy_code_t) + + sizeof(ngx_http_replace_script_var_code_t)) + + sizeof(uintptr_t); + + *sc->values = ngx_array_create(sc->cf->pool, n, 1); + if (*sc->values == NULL) { + return NGX_ERROR; + } + } + + sc->nginx_variables = 0; + sc->capture_variables = 0; + + return NGX_OK; +} + + +static ngx_int_t +ngx_http_replace_script_done(ngx_http_replace_script_compile_t *sc) +{ + uintptr_t *code; + + code = ngx_http_replace_script_add_code(*sc->lengths, + sizeof(uintptr_t)); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + + code = ngx_http_replace_script_add_code(*sc->values, sizeof(uintptr_t)); + if (code == NULL) { + return NGX_ERROR; + } + + *code = (uintptr_t) NULL; + + return NGX_OK; +} + + +static void * +ngx_http_replace_script_add_code(ngx_array_t *codes, size_t size) +{ + return ngx_array_push_n(codes, size); +} + + +static ngx_int_t +ngx_http_replace_script_add_var_code(ngx_http_replace_script_compile_t *sc, + ngx_str_t *name) +{ + ngx_int_t index; + ngx_http_replace_script_var_code_t *code; + + index = ngx_http_get_variable_index(sc->cf, name); + + if (index == NGX_ERROR) { + return NGX_ERROR; + } + + code = ngx_http_replace_script_add_code(*sc->lengths, + sizeof(ngx_http_replace_script_var_code_t)); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_replace_script_code_pt) + ngx_http_replace_script_copy_var_len_code; + + code->index = (uintptr_t) index; + + code = ngx_http_replace_script_add_code(*sc->values, + sizeof(ngx_http_replace_script_var_code_t)); + if (code == NULL) { + return NGX_ERROR; + } + + code->code = (ngx_http_replace_script_code_pt) + ngx_http_replace_script_copy_var_code; + code->index = (uintptr_t) index; + + return NGX_OK; +} + + +static size_t +ngx_http_replace_script_copy_var_len_code(ngx_http_replace_script_engine_t *e) +{ + ngx_http_variable_value_t *value; + ngx_http_replace_script_var_code_t *code; + + code = (ngx_http_replace_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_replace_script_var_code_t); + + value = ngx_http_get_indexed_variable(e->request, code->index); + + if (value && !value->not_found) { + return value->len; + } + + return 0; +} + + +static size_t +ngx_http_replace_script_copy_var_code(ngx_http_replace_script_engine_t *e) +{ + u_char *p; + ngx_http_variable_value_t *value; + ngx_http_replace_script_var_code_t *code; + + code = (ngx_http_replace_script_var_code_t *) e->ip; + + e->ip += sizeof(ngx_http_replace_script_var_code_t); + + if (!e->skip) { + + value = ngx_http_get_indexed_variable(e->request, code->index); + + if (value && !value->not_found) { + p = e->pos; + e->pos = ngx_copy(p, value->data, value->len); + + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, + e->request->connection->log, 0, + "http replace script var: \"%*s\"", e->pos - p, p); + } + } + + return 0; +} + + +static void +ngx_http_replace_count_variables(u_char *src, size_t len, + ngx_uint_t *ngxvars, ngx_uint_t *capvars) +{ + ngx_uint_t i; + unsigned var = 0; + u_char c; + + *ngxvars = 0; + *capvars = 0; + + for (i = 0; i < len; i++) { + c = src[i]; + + if (c == '$') { + if (var) { + var = 0; + + } else { + var = 1; + } + + } else if (var) { + if ((c >= '1' && c <= '9') || c == '&') { + (*capvars)++; + + } else { + (*ngxvars)++; + } + + var = 0; + } + } +} + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_script.h b/modules/replace-filter-nginx-module/src/ngx_http_replace_script.h new file mode 100644 index 0000000..52acfb7 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_script.h @@ -0,0 +1,97 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef _NGX_HTTP_REPLACE_SCRIPT_H_INCLUDED_ +#define _NGX_HTTP_REPLACE_SCRIPT_H_INCLUDED_ + + +#include +#include +#include +#include +#include + + +typedef struct { + ngx_conf_t *cf; + ngx_str_t *source; + + ngx_array_t **lengths; + ngx_array_t **values; + + ngx_uint_t capture_variables; /* captures $1, $2, etc */ + ngx_uint_t nginx_variables; /* nginx variables */ + ngx_uint_t size; +} ngx_http_replace_script_compile_t; + + +typedef struct { + ngx_str_t value; + void *lengths; + void *values; + ngx_uint_t capture_variables; +} ngx_http_replace_complex_value_t; + + +typedef struct { + ngx_conf_t *cf; + ngx_str_t *value; + + ngx_http_replace_complex_value_t *complex_value; +} ngx_http_replace_compile_complex_value_t; + + +typedef struct { + u_char *ip; + u_char *pos; + + ngx_str_t buf; + + sre_int_t *captures; + ngx_uint_t ncaptures; + ngx_chain_t *captures_data; + + unsigned skip:1; + + ngx_http_request_t *request; +} ngx_http_replace_script_engine_t; + + +typedef size_t (*ngx_http_replace_script_code_pt) + (ngx_http_replace_script_engine_t *e); + +typedef size_t (*ngx_http_replace_script_len_code_pt) + (ngx_http_replace_script_engine_t *e); + + +typedef struct { + ngx_http_replace_script_code_pt code; + uintptr_t len; +} ngx_http_replace_script_copy_code_t; + + +typedef struct { + ngx_http_replace_script_code_pt code; + uintptr_t n; +} ngx_http_replace_script_capture_code_t; + + +typedef struct { + ngx_http_replace_script_code_pt code; + uintptr_t index; +} ngx_http_replace_script_var_code_t; + + +ngx_int_t ngx_http_replace_compile_complex_value( + ngx_http_replace_compile_complex_value_t *ccv); +ngx_int_t ngx_http_replace_complex_value(ngx_http_request_t *r, + ngx_chain_t *captured, sre_uint_t ncaps, sre_int_t *cap, + ngx_http_replace_complex_value_t *val, ngx_str_t *value); + + +#endif /* _NGX_HTTP_REPLACE_SCRIPT_H_INCLUDED_ */ + +/* vi:set ft=c ts=4 sw=4 et fdm=marker: */ diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_util.c b/modules/replace-filter-nginx-module/src/ngx_http_replace_util.c new file mode 100644 index 0000000..216dbbd --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_util.c @@ -0,0 +1,220 @@ + +/* + * Copyright (C) Yichun Zhang (agentzh) + */ + + +#ifndef DDEBUG +#define DDEBUG 0 +#endif +#include "ddebug.h" + + +#include "ngx_http_replace_util.h" + + +ngx_chain_t * +ngx_http_replace_get_free_buf(ngx_pool_t *p, ngx_chain_t **free) +{ + ngx_chain_t *cl; + + cl = ngx_chain_get_free_buf(p, free); + if (cl == NULL) { + return cl; + } + + ngx_memzero(cl->buf, sizeof(ngx_buf_t)); + + cl->buf->tag = (ngx_buf_tag_t) &ngx_http_replace_filter_module; + + return cl; +} + + +ngx_int_t +ngx_http_replace_split_chain(ngx_http_request_t *r, ngx_http_replace_ctx_t *ctx, + ngx_chain_t **pa, ngx_chain_t ***plast_a, sre_int_t split, ngx_chain_t **pb, + ngx_chain_t ***plast_b, unsigned b_sane) +{ + sre_int_t file_last; + ngx_chain_t *cl, *newcl, **ll; + +#if 0 + b_sane = 0; +#endif + + ll = pa; + for (cl = *pa; cl; ll = &cl->next, cl = cl->next) { + if (cl->buf->file_last > split) { + /* found an overlap */ + + if (cl->buf->file_pos < split) { + + dd("adjust cl buf (b_sane=%d): \"%.*s\"", b_sane, + (int) ngx_buf_size(cl->buf), cl->buf->pos); + + file_last = cl->buf->file_last; + cl->buf->last -= file_last - split; + cl->buf->file_last = split; + + dd("adjusted cl buf (next=%p): %.*s", + cl->next, + (int) ngx_buf_size(cl->buf), cl->buf->pos); + + /* build the b chain */ + if (b_sane) { + newcl = ngx_http_replace_get_free_buf(r->pool, + &ctx->free); + if (newcl == NULL) { + return NGX_ERROR; + } + + newcl->buf->memory = 1; + newcl->buf->pos = cl->buf->last; + newcl->buf->last = cl->buf->last + file_last - split; + newcl->buf->file_pos = split; + newcl->buf->file_last = file_last; + + newcl->next = cl->next; + + *pb = newcl; + if (plast_b) { + if (cl->next) { + *plast_b = *plast_a; + + } else { + *plast_b = &newcl->next; + } + } + + } else { + *pb = cl->next; + if (plast_b) { + *plast_b = *plast_a; + } + } + + /* truncate the a chain */ + *plast_a = &cl->next; + cl->next = NULL; + + return NGX_OK; + } + + /* build the b chain */ + *pb = cl; + if (plast_b) { + *plast_b = *plast_a; + } + + /* truncate the a chain */ + *plast_a = ll; + *ll = NULL; + + return NGX_OK; + } + } + + /* missed */ + + *pb = NULL; + if (plast_b) { + *plast_b = pb; + } + + return NGX_OK; +} + + +ngx_int_t +ngx_http_replace_new_pending_buf(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, sre_int_t from, sre_int_t to, + ngx_chain_t **out) +{ + size_t len; + ngx_buf_t *b; + ngx_chain_t *cl; + + ngx_http_replace_loc_conf_t *rlcf; + + if (from < ctx->stream_pos) { + from = ctx->stream_pos; + } + + len = (size_t) (to - from); + if (len == 0) { + return NGX_ERROR; + } + + ctx->total_buffered += len; + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_replace_filter_module); + + if (ctx->total_buffered > rlcf->max_buffered_size) { +#if 1 + ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, + "replace filter: exceeding " + "replace_filter_max_buffered_size (%uz): %uz", + rlcf->max_buffered_size, ctx->total_buffered); + return NGX_BUSY; +#endif + } + + cl = ngx_http_replace_get_free_buf(r->pool, &ctx->free); + if (cl == NULL) { + return NGX_ERROR; + } + + b = cl->buf; + b->temporary = 1; + + /* abuse the file_pos and file_last fields here */ + b->file_pos = from; + b->file_last = to; + + b->start = ngx_palloc(r->pool, len); + if (b->start == NULL) { + return NGX_ERROR; + } + b->end = b->start + len; + + b->pos = b->start; + b->last = ngx_copy(b->pos, ctx->buf->pos + from - ctx->stream_pos, len); + + dd("buffered pending data: stream_pos=%ld (%ld, %ld): %.*s", + (long) ctx->stream_pos, (long) from, (long) to, + (int) len, ctx->buf->pos + from - ctx->stream_pos); + + *out = cl; + return NGX_OK; +} + + +#if (DDEBUG) +void +ngx_http_replace_dump_chain(const char *prefix, ngx_chain_t **pcl, + ngx_chain_t **last) +{ + ngx_chain_t *cl; + + if (*pcl == NULL) { + dd("%s buf empty", prefix); + if (last && last != pcl) { + dd("BAD last %s", prefix); + assert(0); + } + } + + for (cl = *pcl; cl; cl = cl->next) { + dd("%s buf: \"%.*s\"", prefix, (int) ngx_buf_size(cl->buf), + cl->buf->pos); + + if (cl->next == NULL) { + if (last && last != &cl->next) { + dd("BAD last %s", prefix); + assert(0); + } + } + } +} +#endif /* DDEBUG */ diff --git a/modules/replace-filter-nginx-module/src/ngx_http_replace_util.h b/modules/replace-filter-nginx-module/src/ngx_http_replace_util.h new file mode 100644 index 0000000..24675e3 --- /dev/null +++ b/modules/replace-filter-nginx-module/src/ngx_http_replace_util.h @@ -0,0 +1,22 @@ +#ifndef _NGX_HTTP_REPLACE_UTIL_H_INCLUDED_ +#define _NGX_HTTP_REPLACE_UTIL_H_INCLUDED_ + + +#include "ngx_http_replace_filter_module.h" + + +ngx_chain_t *ngx_http_replace_get_free_buf(ngx_pool_t *p, + ngx_chain_t **free); +ngx_int_t ngx_http_replace_split_chain(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, ngx_chain_t **pa, ngx_chain_t ***plast_a, + sre_int_t split, ngx_chain_t **pb, ngx_chain_t ***plast_b, unsigned b_sane); +ngx_int_t ngx_http_replace_new_pending_buf(ngx_http_request_t *r, + ngx_http_replace_ctx_t *ctx, sre_int_t from, sre_int_t to, + ngx_chain_t **out); +#if (DDEBUG) +void ngx_http_replace_dump_chain(const char *prefix, ngx_chain_t **pcl, + ngx_chain_t **last); +#endif + + +#endif /* _NGX_HTTP_REPLACE_UTIL_H_INCLUDED_ */ diff --git a/modules/replace-filter-nginx-module/t/01-sanity.t b/modules/replace-filter-nginx-module/t/01-sanity.t new file mode 100644 index 0000000..6ea5aee --- /dev/null +++ b/modules/replace-filter-nginx-module/t/01-sanity.t @@ -0,0 +1,1821 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4 + 1); + +our $StapOutputChains = <<'_EOC_'; +global active + +F(ngx_http_handler) { + active = 1 +} + +/* +F(ngx_http_write_filter) { + if (active && pid() == target()) { + printf("http writer filter: %s\n", ngx_chain_dump($in)) + } +} +*/ + +F(ngx_http_chunked_body_filter) { + if (active && pid() == target()) { + printf("http chunked filter: %s\n", ngx_chain_dump($in)) + } +} + +F(ngx_http_replace_output) { + if (active && pid() == target()) { + printf("http replace output: %s\n", ngx_chain_dump($ctx->out)) + } +} + +probe syscall.writev { + if (active && pid() == target()) { + printf("writev(%s)", ngx_iovec_dump($vec, $vlen)) + /* + for (i = 0; i < $vlen; i++) { + printf(" %p [%s]", $vec[i]->iov_base, text_str(user_string_n($vec[i]->iov_base, $vec[i]->iov_len))) + } + */ + } +} + +probe syscall.writev.return { + if (active && pid() == target()) { + printf(" = %s\n", retstr) + } +} + +_EOC_ + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ambiguous pattern +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter abcabd X; + } +--- request +GET /t + +--- stap +F(ngx_http_replace_non_capturing_parse) { + println("non capturing parse") +} + +F(ngx_http_replace_capturing_parse) { + println("capturing parse") +} + +F(ngx_http_replace_complex_value) { + println("complex value") +} + +--- stap_out_like chop +^(non capturing parse\n)+$ + +--- response_body +abcXe +--- no_error_log +[alert] +[error] + + + +=== TEST 2: ambiguous pattern +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n ababac; + replace_filter abac X; + } +--- request +GET /t +--- response_body chop +abX +--- no_error_log +[alert] +[error] + + + +=== TEST 3: alt +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abc; + replace_filter 'ab|abc' X; + } +--- request +GET /t +--- response_body +Xc +--- no_error_log +[alert] +[error] + + + +=== TEST 4: caseless +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcaBde; + replace_filter abCabd X i; + } +--- request +GET /t +--- response_body +abcXe +--- no_error_log +[alert] +[error] + + + +=== TEST 5: case sensitive (no match) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcaBde; + replace_filter abCabd X; + } +--- request +GET /t +--- response_body +abcabcaBde +--- no_error_log +[alert] +[error] + + + +=== TEST 6: 1-byte chain bufs +--- config + default_type text/html; + replace_filter_max_buffered_size 3; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1413") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() +} + +--- response_body +abXd +--- no_error_log +[alert] +[error] + + + +=== TEST 7: 2-byte chain bufs +--- config + default_type text/html; + replace_filter_max_buffered_size 2; + + location = /t { + echo -n ab; + echo -n ab; + echo -n ac; + echo d; + replace_filter abac X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +abXd +--- no_error_log +[alert] +[error] + + + +=== TEST 8: 3-byte chain bufs +--- config + default_type text/html; + replace_filter_max_buffered_size 3; + + location = /t { + echo -n aba; + echo -n bac; + echo d; + replace_filter abac X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +abXd +--- no_error_log +[alert] +[error] + + + +=== TEST 9: 3-byte chain bufs (more) +--- config + default_type text/html; + replace_filter_max_buffered_size 4; + + location = /t { + echo -n aba; + echo -n bac; + echo d; + replace_filter abacd X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +abX +--- no_error_log +[alert] +[error] + + + +=== TEST 10: once by default (1st char matched) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /t { + echo abcabcabde; + replace_filter a X; + } +--- request +GET /t +--- response_body +Xbcabcabde +--- no_error_log +[alert] +[error] + + + +=== TEST 11: once by default (2nd char matched) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter b X; + } +--- request +GET /t +--- response_body +aXcabcabde +--- no_error_log +[alert] +[error] + + + +=== TEST 12: global substitution +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo bbc; + replace_filter b X g; + } +--- request +GET /t +--- response_body +XXc +--- no_error_log +[alert] +[error] + + + +=== TEST 13: global substitution +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter b X g; + } +--- request +GET /t +--- response_body +aXcaXcaXde +--- no_error_log +[alert] +[error] + + + +=== TEST 14: global substitution (empty captures) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n abcabcabde; + replace_filter [0-9]* X g; + } +--- request +GET /t +--- response_body chop +XaXbXcXaXbXcXaXbXdXeX +--- no_error_log +[alert] +[error] + + + +=== TEST 15: global substitution (empty captures, splitted) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n ab; + echo -n cab; + echo -n c; + echo -n abde; + replace_filter [0-9]* X g; + } +--- request +GET /t +--- response_body chop +XaXbXcXaXbXcXaXbXdXeX +--- no_error_log +[alert] +[error] + + + +=== TEST 16: global substitution (\d+) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo "hello1234, 56 world"; + replace_filter \d+ X g; + } +--- request +GET /t +--- response_body +helloX, X world +--- no_error_log +[alert] +[error] + + + +=== TEST 17: replace_filter_types default to text/html +--- config + default_type text/plain; + location /t { + echo abc; + replace_filter b X; + } +--- request +GET /t +--- response_body +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 18: custom replace_filter_types +--- config + default_type text/plain; + location /t { + echo abc; + replace_filter b X; + replace_filter_types text/plain; + } +--- request +GET /t +--- response_body +aXc +--- no_error_log +[alert] +[error] + + + +=== TEST 19: multiple replace_filter_types settings +--- config + default_type text/plain; + location /t { + echo abc; + replace_filter b X; + replace_filter_types text/css text/plain; + } +--- request +GET /t +--- response_body +aXc +--- no_error_log +[alert] +[error] + + + +=== TEST 20: trim leading spaces +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /a.html { + replace_filter '^\s+' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /a.html +--- response_body +hello, world +blah yeah +hello +baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 21: trim trailing spaces +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /a.html { + replace_filter '\s+$' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /a.html +--- response_body chop + hello, world +blah yeah +hello + baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 22: trim both leading and trailing spaces +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /a.html { + replace_filter '^\s+|\s+$' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /a.html +--- response_body chop +hello, world +blah yeah +hello +baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 23: pure flush buf in the stream (no data) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location = /t { + echo_flush; + replace_filter 'a' 'X' g; + } +--- request +GET /t +--- response_body chop +--- no_error_log +[alert] +[error] + + + +=== TEST 24: pure flush buf in the stream (with data) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location = /t { + echo a; + echo_flush; + replace_filter 'a' 'X' g; + } +--- request +GET /t +--- stap3 eval: $::StapOutputChains +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:539") { + printf("chain: %s", ngx_chain_dump($ctx->busy)) + //print_ubacktrace() +} +--- response_body +X +--- no_error_log +[alert] +[error] + + + +=== TEST 25: trim both leading and trailing spaces (1 byte at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + location = /t { + echo -n 'a'; + echo ' '; + echo "b"; + replace_filter '^\s+|\s+$' '' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body chop +a +b + +--- no_error_log +[alert] +[error] + + + +=== TEST 26: trim both leading and trailing spaces (1 byte at a time), no \s for $ +--- config + replace_filter_max_buffered_size 1; + default_type text/html; + location = /t { + echo -n 'a'; + echo ' '; + echo "b"; + replace_filter '^\s+| +$' '' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a +b + +--- no_error_log +[alert] +[error] + + + +=== TEST 27: trim both leading and trailing spaces (1 byte at a time) +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1438") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- request +GET /t +--- response_body chop +hello, world +blah yeah +hello +baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 28: \b at the border +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n a; + echo b; + replace_filter '\bb|a' X g; + } +--- request +GET /t +--- response_body +Xb +--- no_error_log +[alert] +[error] + + + +=== TEST 29: \B at the border +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /t { + echo -n a; + echo ','; + replace_filter '\B,|a' X g; + } +--- request +GET /t +--- response_body +X, +--- no_error_log +[alert] +[error] + + + +=== TEST 30: \A at the border +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n a; + echo 'b'; + replace_filter '\Ab|a' X g; + } +--- request +GET /t +--- response_body +Xb +--- no_error_log +[alert] +[error] + + + +=== TEST 31: memory bufs with last_buf=1 +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + return 200 "abc"; + replace_filter \w+ X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body chop +X +--- no_error_log +[alert] +[error] + + + +=== TEST 32: trim both leading and trailing spaces (2 bytes at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 4; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + local len = string.len(txt) + i = 1 + while i <= len do + if i == len then + ngx.print(string.sub(txt, i, i)) + i = i + 1 + else + ngx.print(string.sub(txt, i, i + 1)) + i = i + 2 + end + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 eval: $::StapOutputChains +--- request +GET /t +--- response_body chop +hello, world +blah yeah +hello +baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 33: trim both leading and trailing spaces (3 bytes at a time) +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + local len = string.len(txt) + i = 1 + while i <= len do + if i == len then + ngx.print(string.sub(txt, i, i)) + i = i + 1 + elseif i == len - 1 then + ngx.print(string.sub(txt, i, i + 1)) + i = i + 2 + else + ngx.print(string.sub(txt, i, i + 2)) + i = i + 3 + end + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 eval: $::StapOutputChains +--- request +GET /t +--- response_body chop +hello, world +blah yeah +hello +baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 34: github issue #2: error "general look-ahead not supported" +--- config + replace_filter_max_buffered_size 3; + location /t { + charset utf-8; + default_type text/html; + echo "ABCabcABCabc"; + #replace_filter_types text/plain; + replace_filter "a.+a" "X" "ig"; + } +--- request +GET /t + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1492") { + print_ubacktrace() +} + +--- response_body +Xbc +--- no_error_log +[alert] +[error] + + + +=== TEST 35: backtrack to the middle of a pending capture (pending: output|capture + rematch) +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n ab; + echo -n c; + echo d; + replace_filter 'abce|b' 'X' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1501") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 36: backtrack to the middle of a pending capture (pending: output + capture|rematch +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n a; + echo -n bc; + echo d; + replace_filter 'abce|b' 'X' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1501") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 37: backtrack to the middle of a pending capture (pending: output + capture + rematch +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n a; + echo -n b; + echo -n c; + echo d; + replace_filter 'abce|b' 'X' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1522") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 38: backtrack to the middle of a pending capture (pending: output|capture|rematch +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n abc; + echo d; + replace_filter 'abce|b' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 39: backtrack to the middle of a pending capture (pending: output|capture|rematch(2) +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n abcc; + echo d; + replace_filter 'abcce|b' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXccd + +--- no_error_log +[alert] +[error] + + + +=== TEST 40: backtrack to the middle of a pending capture (pending: output|capture(2)|rematch +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n abbc; + echo d; + replace_filter 'abbce|bb' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 41: backtrack to the middle of a pending capture (pending: output(2)|capture|rematch +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n aabc; + echo d; + replace_filter 'aabce|b' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aaXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 42: backtrack to the beginning of a pending capture (pending: output + capture|rematch(2) +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n a; + echo -n bcc; + echo d; + replace_filter 'abcce|b' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXccd + +--- no_error_log +[alert] +[error] + + + +=== TEST 43: backtrack to the beginning of a pending capture (pending: output + capture(2)|rematch +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n a; + echo -n bbc; + echo d; + replace_filter 'abbce|bb' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 44: backtrack to the middle of a pending capture (pending: output(2) + capture|rematch +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n aa; + echo -n bc; + echo d; + replace_filter 'aabce|b' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aaXcd + +--- no_error_log +[alert] +[error] + + + +=== TEST 45: assertions across AGAIN +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n a; + echo -n "\n"; + echo b; + replace_filter 'a\n^b' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +X + +--- no_error_log +[alert] +[error] + + + +=== TEST 46: assertions when capture backtracking happens +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n a; + echo -n b; + echo -n c; + echo -n d; + echo f; + #echo abcdf; + replace_filter 'abcde|b|\bc' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcdf + +--- no_error_log +[alert] +[error] + + + +=== TEST 47: assertions when capture backtracking happens (2 pending matches) +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n a; + echo -n b; + echo -n ' '; + echo -n d; + echo f; + #echo ab df; + replace_filter 'ab de|b|b |\b ' 'X' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXXdf + +--- no_error_log +[alert] +[error] + + + +=== TEST 48: github issue #2: error "general look-ahead not supported", no "g" +--- config + replace_filter_max_buffered_size 3; + location /t { + charset utf-8; + default_type text/html; + echo "ABCabcABCabc"; + #replace_filter_types text/plain; + replace_filter "a.+a" "X" "i"; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +Xbc +--- no_error_log +[alert] +[error] + + + +=== TEST 49: nested rematch bufs +--- config + replace_filter_max_buffered_size 4; + location /t { + default_type text/html; + echo -n a; + echo -n b; + echo -n c; + echo -n d; + echo -n e; + echo g; + #echo abcdeg; + replace_filter 'abcdef|b|cdf|c' X g; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +aXXdeg +--- no_error_log +[alert] +[error] + + + +=== TEST 50: nested rematch bufs (splitting pending buf) +--- config + replace_filter_max_buffered_size 6; + location /t { + default_type text/html; + echo -n a; + echo -n b; + echo -n cd; + echo -n e; + echo -n f; + echo -n g; + echo i; + #echo abcdefh; + replace_filter 'abcdefgh|b|cdeg|d' X g; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +aXcXefgi +--- no_error_log +[alert] +[error] + + + +=== TEST 51: remove C/C++ comments (1 byte at a time) +--- config + replace_filter_max_buffered_size 42; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '/\*.*?\*/|//[^\n]*' '' g; + } +--- user_files +>>> a.html + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /t +--- response_body eval +" i don't know +hello world +blah */ b + + +" +--- no_error_log +[alert] +[error] + + + +=== TEST 52: remove C/C++ comments (all at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + + location /a.html { + replace_filter '/\*.*?\*/|//[^\n]*' '' g; + } + +--- user_files +>>> a.html + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /a.html +--- response_body eval +" i don't know +hello world +blah */ b + + +" +--- no_error_log +[alert] +[error] + + + +=== TEST 53: remove C/C++ comments (all at a time) - server-level config +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + + replace_filter '/\*.*?\*/|//[^\n]*' '' g; + +--- user_files +>>> a.html + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /a.html +--- response_body eval +" i don't know +hello world +blah */ b + + +" +--- no_error_log +[alert] +[error] + + + +=== TEST 54: multiple replace_filter_types settings (server level) +--- config + replace_filter_max_buffered_size 0; + default_type text/plain; + replace_filter_types text/css text/plain; + location /t { + echo abc; + replace_filter b X; + } +--- request +GET /t +--- response_body +aXc +--- no_error_log +[alert] +[error] + + + +=== TEST 55: multiple replace_filter_types settings (server level, but overridding in location) +--- config + replace_filter_max_buffered_size 0; + default_type text/plain; + replace_filter_types text/css text/plain; + location /t { + echo abc; + replace_filter_types text/javascript; + replace_filter b X; + } +--- request +GET /t +--- response_body +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 56: do not use replace_filter at all +--- config + replace_filter_max_buffered_size 0; + default_type text/plain; + replace_filter_types text/css text/plain; + location /t { + echo abc; + replace_filter_types text/css; + } +--- request +GET /t +--- response_body +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 57: bad regex +--- config + default_type text/html; + location /t { + echo abc; + replace_filter '(a+b' ''; + } +--- request +GET /t +--- response_body +abc +--- no_error_log +[alert] +[error] +--- SKIP + + + +=== TEST 58: github issue #3: data lost in particular situation +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location /t { + default_type text/html; + echo "ABCabcABC"; + echo "ABCabcABC"; + #echo "ABCabcABC\nABCabcABC"; + replace_filter "(a.+?c){2}" "X" "ig"; + } +--- request +GET /t +--- response_body +XXABC +--- no_error_log +[alert] +[error] + + + +=== TEST 59: variation +--- config + replace_filter_max_buffered_size 5; + default_type text/html; + location /t { + default_type text/html; + #echo "ABCabcABC"; + #echo "ABCabcABC"; + echo "ACacAC ACacAC"; + replace_filter "(a.+?c){2}" "X" "ig"; + } +--- request +GET /t +--- response_body +XacAC +--- no_error_log +[alert] +[error] + + + +=== TEST 60: nested pending matched +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location /t { + default_type text/html; + echo -n a; + echo -n b; + echo -n c; + echo -n def; + echo -n gh; + echo -n i; + echo k; + #echo abcdefig; + replace_filter "abcdefghij|bcdefg|cd" "X" "ig"; + } +--- request +GET /t +--- response_body +aXhik +--- no_error_log +[alert] +[error] + + + +=== TEST 61: test split chain with b_sane=1, next=NULL +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + + location = /t { + echo -n aba; + echo -n ba; + echo -n bac; + echo d; + #echo abababacd; + replace_filter abacd X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1217") { + print_ubacktrace() +} +--- response_body +ababX +--- no_error_log +[alert] +[error] + + + +=== TEST 62: test split chain with b_sane=1, next not NULL +--- config + replace_filter_max_buffered_size 6; + default_type text/html; + + location = /t { + echo -n aba; + echo -n ba; + echo -n ba; + echo -n bac; + echo d; + #echo abababacd; + replace_filter ababacd X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1217") { + print_ubacktrace() +} +--- response_body +ababX +--- no_error_log +[alert] +[error] + + + +=== TEST 63: trim leading spaces (1 byte at a time) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /a.html { + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '^\s+' '' g; + } + +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /t +--- response_body +hello, world +blah yeah +hello +baby! +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 64: split ctx->pending into ctx->pending and ctx->free +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + + location = /t { + #echo "abc\nd"; + echo -n a; + echo -n b; + echo -n c; + echo -n "\n"; + echo d; + replace_filter "abcd|bc\ne|c$" X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1482") { + print_ubacktrace() +} +--- response_body +abX +d +--- no_error_log +[alert] +[error] + + + +=== TEST 65: trim both leading and trailing spaces (1 byte at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 2; + location /t { + echo -n 'a'; + echo_sleep 0.001; + echo ' '; + echo_sleep 0.001; + echo ''; + echo_sleep 0.001; + echo ' '; + echo_sleep 0.001; + echo "b"; + echo_sleep 0.001; + echo " "; + replace_filter '^\s+|\s+$' '' g; + } + + location = /main { + echo_location_async /t1; + echo_location_async /t2; + echo_location_async /t3; + echo_location_async /t4; + echo_location_async /t5; + echo_location_async /t6; + } + +--- stap3 eval: $::StapOutputChains +--- request +GET /main +--- response_body +a +b +a +b +a +b +a +b +a +b +a +b + +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/02-max-buffered.t b/modules/replace-filter-nginx-module/t/02-max-buffered.t new file mode 100644 index 0000000..4287bc1 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/02-max-buffered.t @@ -0,0 +1,277 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4); + +our $StapOutputChains = <<'_EOC_'; +global active + +F(ngx_http_handler) { + active = 1 +} + +/* +F(ngx_http_write_filter) { + if (active && pid() == target()) { + printf("http writer filter: %s\n", ngx_chain_dump($in)) + } +} +*/ + +F(ngx_http_chunked_body_filter) { + if (active && pid() == target()) { + printf("http chunked filter: %s\n", ngx_chain_dump($in)) + } +} + +F(ngx_http_replace_output) { + if (active && pid() == target()) { + printf("http replace output: %s\n", ngx_chain_dump($ctx->out)) + } +} + +probe syscall.writev { + if (active && pid() == target()) { + printf("writev(%s)", ngx_iovec_dump($vec, $vlen)) + /* + for (i = 0; i < $vlen; i++) { + printf(" %p [%s]", $vec[i]->iov_base, text_str(user_string_n($vec[i]->iov_base, $vec[i]->iov_len))) + } + */ + } +} + +probe syscall.writev.return { + if (active && pid() == target()) { + printf(" = %s\n", retstr) + } +} + +_EOC_ + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: 1-byte chain bufs (0) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1413") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() +} + +--- response_body +ababacd +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (0): 1 +--- no_error_log +[error] + + + +=== TEST 2: 1-byte chain bufs (1) +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac X; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1439") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- response_body +ababacd +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (1): 2 +--- no_error_log +[error] + + + +=== TEST 3: trim both leading and trailing spaces (1 byte at a time) (2) +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1438") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- request +GET /t +--- response_body +hello, world +blah yeah +hello + baby! + +abc + +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (2): 3 +--- no_error_log +[error] + + + +=== TEST 4: github issue #2: error "general look-ahead not supported" +--- config + replace_filter_max_buffered_size 0; + location /t { + charset utf-8; + default_type text/html; + echo "ABCabcABCabc"; + #replace_filter_types text/plain; + replace_filter "a.+a" "X" "ig"; + } +--- request +GET /t + +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1481") { + print_ubacktrace() +} + +--- response_body +ABCabcABCabc +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (0): 2 +--- no_error_log +[error] + + + +=== TEST 5: backtrack to the middle of a pending capture (pending: output|capture + rematch) (0) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location = /t { + echo -n ab; + echo -n c; + echo d; + replace_filter 'abce|b' 'X' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1492") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +abcd + +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (0): 1 +--- no_error_log +[error] + + + +=== TEST 6: backtrack to the middle of a pending capture (pending: output|capture + rematch) (1) +--- config + replace_filter_max_buffered_size 1; + default_type text/html; + location = /t { + echo -n ab; + echo -n c; + echo d; + replace_filter 'abce|b' 'X' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1501") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aXcd + +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (1): 2 +--- no_error_log +[error] + diff --git a/modules/replace-filter-nginx-module/t/03-var.t b/modules/replace-filter-nginx-module/t/03-var.t new file mode 100644 index 0000000..0cc0293 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/03-var.t @@ -0,0 +1,295 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4 + 3); + +our $StapOutputChains = <<'_EOC_'; +global active + +F(ngx_http_handler) { + active = 1 +} + +/* +F(ngx_http_write_filter) { + if (active && pid() == target()) { + printf("http writer filter: %s\n", ngx_chain_dump($in)) + } +} +*/ + +F(ngx_http_chunked_body_filter) { + if (active && pid() == target()) { + printf("http chunked filter: %s\n", ngx_chain_dump($in)) + } +} + +F(ngx_http_replace_output) { + if (active && pid() == target()) { + printf("http replace output: %s\n", ngx_chain_dump($ctx->out)) + } +} + +probe syscall.writev { + if (active && pid() == target()) { + printf("writev(%s)", ngx_iovec_dump($vec, $vlen)) + /* + for (i = 0; i < $vlen; i++) { + printf(" %p [%s]", $vec[i]->iov_base, text_str(user_string_n($vec[i]->iov_base, $vec[i]->iov_len))) + } + */ + } +} + +probe syscall.writev.return { + if (active && pid() == target()) { + printf(" = %s\n", retstr) + } +} + +_EOC_ + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: nginx vars (global) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo abc; + replace_filter . $foo g; + } +--- request +GET /t + +--- stap +F(ngx_http_replace_non_capturing_parse) { + println("non capturing parse") +} + +F(ngx_http_replace_capturing_parse) { + println("capturing parse") +} + +--- stap_out_like chop +^(non capturing parse\n)+$ + +--- response_body chop +XXXX +--- no_error_log +[alert] +[error] + + + +=== TEST 2: nginx vars (non-global) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo abc; + replace_filter . $foo; + } +--- request +GET /t + +--- stap +F(ngx_http_replace_non_capturing_parse) { + println("non capturing parse") +} + +F(ngx_http_replace_capturing_parse) { + println("capturing parse") +} + +--- stap_out_like chop +^(non capturing parse\n)+$ + +--- response_body +Xbc +--- no_error_log +[alert] +[error] + + + +=== TEST 3: undefined nginx vars +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abc; + replace_filter . $foo; + } +--- request +GET /t +--- response_body +Xbc +--- no_error_log +[alert] +[error] +--- SKIP + + + +=== TEST 4: use of capturing variables +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abc; + replace_filter . $1; + } +--- request +GET /t +--- response_body +Xbc +--- no_error_log +[alert] +[error] +--- SKIP + + + +=== TEST 5: more contexts +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo abc; + replace_filter . "[$foo]"; + } +--- request +GET /t +--- response_body +[X]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 6: more nginx vars +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + set $bar Y; + echo abc; + replace_filter . "[$foo,$bar]"; + } +--- request +GET /t +--- response_body +[X,Y]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 7: various lengths of nginx var values +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo XYZ; + set $bar ""; + echo abc; + replace_filter . "[$foo,$bar]"; + } +--- request +GET /t +--- response_body +[XYZ,]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 8: escaping the dollar sign +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + set $bar Y; + echo abc; + replace_filter . "[$foo,$$bar]"; + } +--- request +GET /t +--- response_body +[X,$bar]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 9: \ is not an escaping sequence +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + set $bar Y; + echo abc; + replace_filter . "[\$foo,\$bar]"; + } +--- request +GET /t +--- response_body +[\X,\Y]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 10: cached subs values +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo abc; + replace_filter . "$foo" g; + } +--- request +GET /t +--- response_body chop +XXXX + +--- stap +F(ngx_http_replace_complex_value) { + println("complex value") +} + +--- stap_out +complex value + +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/04-capturing.t b/modules/replace-filter-nginx-module/t/04-capturing.t new file mode 100644 index 0000000..c94c7d7 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/04-capturing.t @@ -0,0 +1,1893 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4 + 1); + +our $StapOutputChains = <<'_EOC_'; +global active + +F(ngx_http_handler) { + active = 1 +} + +/* +F(ngx_http_write_filter) { + if (active && pid() == target()) { + printf("http writer filter: %s\n", ngx_chain_dump($in)) + } +} +*/ + +F(ngx_http_chunked_body_filter) { + if (active && pid() == target()) { + printf("http chunked filter: %s\n", ngx_chain_dump($in)) + } +} + +F(ngx_http_replace_output) { + if (active && pid() == target()) { + printf("http replace output: %s\n", ngx_chain_dump($ctx->out)) + } +} + +probe syscall.writev { + if (active && pid() == target()) { + printf("writev(%s)", ngx_iovec_dump($vec, $vlen)) + /* + for (i = 0; i < $vlen; i++) { + printf(" %p [%s]", $vec[i]->iov_base, text_str(user_string_n($vec[i]->iov_base, $vec[i]->iov_len))) + } + */ + } +} + +probe syscall.writev.return { + if (active && pid() == target()) { + printf(" = %s\n", retstr) + } +} + +_EOC_ + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: ambiguous pattern +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter abcabd "[$&]"; + } +--- request +GET /t +--- response_body +abc[abcabd]e + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 2: ambiguous pattern +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n ababac; + replace_filter abac "[$&]"; + } +--- request +GET /t +--- response_body chop +ab[abac] +--- no_error_log +[alert] +[error] + + + +=== TEST 3: alt +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abc; + replace_filter 'ab|abc' [$&]; + } +--- request +GET /t +--- response_body +[ab]c +--- no_error_log +[alert] +[error] + + + +=== TEST 4: caseless +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcaBde; + replace_filter abCabd [$&] i; + } +--- request +GET /t +--- response_body +abc[abcaBd]e +--- no_error_log +[alert] +[error] + + + +=== TEST 5: case sensitive (no match) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcaBde; + replace_filter abCabd [$&]; + } +--- request +GET /t +--- response_body +abcabcaBde +--- no_error_log +[alert] +[error] + + + +=== TEST 6: 1-byte chain bufs +--- config + default_type text/html; + replace_filter_max_buffered_size 3; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1413") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() +} + +--- response_body +ab[abac]d +--- no_error_log +[alert] +[error] + + + +=== TEST 7: 2-byte chain bufs +--- config + default_type text/html; + replace_filter_max_buffered_size 2; + + location = /t { + echo -n ab; + echo -n ab; + echo -n ac; + echo d; + replace_filter abac [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +ab[abac]d +--- no_error_log +[alert] +[error] + + + +=== TEST 8: 3-byte chain bufs +--- config + default_type text/html; + replace_filter_max_buffered_size 3; + + location = /t { + echo -n aba; + echo -n bac; + echo d; + replace_filter abac [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +ab[abac]d +--- no_error_log +[alert] +[error] + + + +=== TEST 9: 3-byte chain bufs (more) +--- config + default_type text/html; + replace_filter_max_buffered_size 4; + + location = /t { + echo -n aba; + echo -n bac; + echo d; + replace_filter abacd [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +ab[abacd] +--- no_error_log +[alert] +[error] + + + +=== TEST 10: once by default (1st char matched) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /t { + echo abcabcabde; + replace_filter a [$&]; + } +--- request +GET /t +--- response_body +[a]bcabcabde +--- no_error_log +[alert] +[error] + + + +=== TEST 11: once by default (2nd char matched) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter b [$&]; + } +--- request +GET /t +--- response_body +a[b]cabcabde +--- no_error_log +[alert] +[error] + + + +=== TEST 12: global substitution +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo bbc; + replace_filter b [$&] g; + } +--- request +GET /t +--- response_body +[b][b]c +--- no_error_log +[alert] +[error] + + + +=== TEST 13: global substitution +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter b [$&] g; + } +--- request +GET /t +--- response_body +a[b]ca[b]ca[b]de +--- no_error_log +[alert] +[error] + + + +=== TEST 14: global substitution (empty captures) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n abcabcabde; + replace_filter [0-9]* [$&] g; + } +--- request +GET /t +--- response_body chop +[]a[]b[]c[]a[]b[]c[]a[]b[]d[]e[] +--- no_error_log +[alert] +[error] + + + +=== TEST 15: global substitution (empty captures, splitted) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n ab; + echo -n cab; + echo -n c; + echo -n abde; + replace_filter [0-9]* [$&] g; + } +--- request +GET /t +--- response_body chop +[]a[]b[]c[]a[]b[]c[]a[]b[]d[]e[] +--- no_error_log +[alert] +[error] + + + +=== TEST 16: global substitution (\d+) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo "hello1234, 56 world"; + replace_filter \d+ [$&] g; + } +--- request +GET /t +--- response_body +hello[1234], [56] world +--- no_error_log +[alert] +[error] + + + +=== TEST 17: replace_filter_types default to text/html +--- config + default_type text/plain; + location /t { + echo abc; + replace_filter b [$&]; + } +--- request +GET /t +--- response_body +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 18: custom replace_filter_types +--- config + default_type text/plain; + location /t { + echo abc; + replace_filter b [$&]; + replace_filter_types text/plain; + } +--- request +GET /t +--- response_body +a[b]c +--- no_error_log +[alert] +[error] + + + +=== TEST 19: multiple replace_filter_types settings +--- config + default_type text/plain; + location /t { + echo abc; + replace_filter b [$&]; + replace_filter_types text/css text/plain; + } +--- request +GET /t +--- response_body +a[b]c +--- no_error_log +[alert] +[error] + + + +=== TEST 20: trim leading spaces +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /a.html { + replace_filter '^\s+' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /a.html +--- response_body +[ ]hello, world +blah yeah +hello +[ ]baby! +[ +]abc +--- no_error_log +[alert] +[error] + + + +=== TEST 21: trim trailing spaces +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /a.html { + replace_filter '\s+$' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /a.html +--- response_body chop + hello, world[ ] +blah yeah +hello[ ] + baby![ + ] +abc[ +] +--- no_error_log +[alert] +[error] + + + +=== TEST 22: trim both leading and trailing spaces +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /a.html { + replace_filter '^\s+|\s+$' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /a.html +--- response_body chop +[ ]hello, world[ ] +blah yeah +hello[ ] +[ ]baby! +[ +]abc[ +] +--- no_error_log +[alert] +[error] + + + +=== TEST 23: pure flush buf in the stream (no data) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location = /t { + echo_flush; + replace_filter 'a' '[$&]' g; + } +--- request +GET /t +--- response_body chop +--- no_error_log +[alert] +[error] + + + +=== TEST 24: pure flush buf in the stream (with data) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location = /t { + echo a; + echo_flush; + replace_filter 'a' '[$&]' g; + } +--- request +GET /t +--- stap3 eval: $::StapOutputChains +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:539") { + printf("chain: %s", ngx_chain_dump($ctx->busy)) + //print_ubacktrace() +} +--- response_body +[a] +--- no_error_log +[alert] +[error] + + + +=== TEST 25: trim both leading and trailing spaces (1 byte at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 2; + location = /t { + echo -n 'a'; + echo ' '; + echo "b"; + replace_filter '^\s+|\s+$' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body chop +a[ ] +b[ +] + +--- no_error_log +[alert] +[error] + + + +=== TEST 26: trim both leading and trailing spaces (1 byte at a time), no \s for $ +--- config + replace_filter_max_buffered_size 1; + default_type text/html; + location = /t { + echo -n 'a'; + echo ' '; + echo "b"; + replace_filter '^\s+| +$' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[ ] +b + +--- no_error_log +[alert] +[error] + + + +=== TEST 27: trim both leading and trailing spaces (1 byte at a time) +--- config + replace_filter_max_buffered_size 7; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1438") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- request +GET /t +--- response_body chop +[ ]hello, world[ ] +blah yeah +hello[ ] +[ ]baby! +[ +]abc[ +] + +--- no_error_log +[alert] +[error] + + + +=== TEST 28: \b at the border +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n a; + echo b; + replace_filter '\bb|a' [$&] g; + } +--- request +GET /t +--- response_body +[a]b +--- no_error_log +[alert] +[error] + + + +=== TEST 29: \B at the border +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location /t { + echo -n a; + echo ','; + replace_filter '\B,|a' [$&] g; + } +--- request +GET /t +--- response_body +[a], +--- no_error_log +[alert] +[error] + + + +=== TEST 30: \A at the border +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n a; + echo 'b'; + replace_filter '\Ab|a' [$&] g; + } +--- request +GET /t +--- response_body +[a]b +--- no_error_log +[alert] +[error] + + + +=== TEST 31: memory bufs with last_buf=1 +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + return 200 "abc"; + replace_filter \w+ [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body chop +[abc] +--- no_error_log +[alert] +[error] + + + +=== TEST 32: trim both leading and trailing spaces (2 bytes at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 7; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + local len = string.len(txt) + i = 1 + while i <= len do + if i == len then + ngx.print(string.sub(txt, i, i)) + i = i + 1 + else + ngx.print(string.sub(txt, i, i + 1)) + i = i + 2 + end + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 eval: $::StapOutputChains +--- request +GET /t +--- response_body chop +[ ]hello, world[ ] +blah yeah +hello[ ] +[ ]baby! +[ +]abc[ +] + +--- no_error_log +[alert] +[error] + + + +=== TEST 33: trim both leading and trailing spaces (3 bytes at a time) +--- config + replace_filter_max_buffered_size 5; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + local len = string.len(txt) + i = 1 + while i <= len do + if i == len then + ngx.print(string.sub(txt, i, i)) + i = i + 1 + elseif i == len - 1 then + ngx.print(string.sub(txt, i, i + 1)) + i = i + 2 + else + ngx.print(string.sub(txt, i, i + 2)) + i = i + 3 + end + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 eval: $::StapOutputChains +--- request +GET /t +--- response_body chop +[ ]hello, world[ ] +blah yeah +hello[ ] +[ ]baby! +[ +]abc[ +] + +--- no_error_log +[alert] +[error] + + + +=== TEST 34: github issue #2: error "general look-ahead not supported" +--- config + replace_filter_max_buffered_size 13; + location /t { + charset utf-8; + default_type text/html; + echo "ABCabcABCabc"; + #replace_filter_types text/plain; + replace_filter "a.+a" "[$&]" "ig"; + } +--- request +GET /t + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1492") { + print_ubacktrace() +} + +--- response_body +[ABCabcABCa]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 35: backtrack to the middle of a pending capture (pending: output|capture + rematch) +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n ab; + echo -n c; + echo d; + replace_filter 'abce|b' '[$&]' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1501") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 36: backtrack to the middle of a pending capture (pending: output + capture|rematch +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n a; + echo -n bc; + echo d; + replace_filter 'abce|b' '[$&]' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1501") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 37: backtrack to the middle of a pending capture (pending: output + capture + rematch +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n a; + echo -n b; + echo -n c; + echo d; + replace_filter 'abce|b' '[$&]' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1522") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 38: backtrack to the middle of a pending capture (pending: output|capture|rematch +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + location = /t { + echo -n abc; + echo d; + replace_filter 'abce|b' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 39: backtrack to the middle of a pending capture (pending: output|capture|rematch(2) +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n abcc; + echo d; + replace_filter 'abcce|b' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]ccd + +--- no_error_log +[alert] +[error] + + + +=== TEST 40: backtrack to the middle of a pending capture (pending: output|capture(2)|rematch +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n abbc; + echo d; + replace_filter 'abbce|bb' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[bb]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 41: backtrack to the middle of a pending capture (pending: output(2)|capture|rematch +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n aabc; + echo d; + replace_filter 'aabce|b' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aa[b]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 42: backtrack to the beginning of a pending capture (pending: output + capture|rematch(2) +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n a; + echo -n bcc; + echo d; + replace_filter 'abcce|b' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]ccd + +--- no_error_log +[alert] +[error] + + + +=== TEST 43: backtrack to the beginning of a pending capture (pending: output + capture(2)|rematch +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n a; + echo -n bbc; + echo d; + replace_filter 'abbce|bb' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[bb]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 44: backtrack to the middle of a pending capture (pending: output(2) + capture|rematch +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n aa; + echo -n bc; + echo d; + replace_filter 'aabce|b' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +aa[b]cd + +--- no_error_log +[alert] +[error] + + + +=== TEST 45: assertions across AGAIN +--- config + replace_filter_max_buffered_size 2; + default_type text/html; + location = /t { + echo -n a; + echo -n "\n"; + echo b; + replace_filter 'a\n^b' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +[a +b] + +--- no_error_log +[alert] +[error] + + + +=== TEST 46: assertions when capture backtracking happens +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n a; + echo -n b; + echo -n c; + echo -n d; + echo f; + #echo abcdf; + replace_filter 'abcde|b|\bc' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b]cdf + +--- no_error_log +[alert] +[error] + + + +=== TEST 47: assertions when capture backtracking happens (2 pending matches) +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location = /t { + echo -n a; + echo -n b; + echo -n ' '; + echo -n d; + echo f; + #echo ab df; + replace_filter 'ab de|b|b |\b ' '[$&]' g; + } + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +a[b][ ]df + +--- no_error_log +[alert] +[error] + + + +=== TEST 48: github issue #2: error "general look-ahead not supported", no "g" +--- config + replace_filter_max_buffered_size 13; + location /t { + charset utf-8; + default_type text/html; + echo "ABCabcABCabc"; + #replace_filter_types text/plain; + replace_filter "a.+a" "[$&]" "i"; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +[ABCabcABCa]bc +--- no_error_log +[alert] +[error] + + + +=== TEST 49: nested rematch bufs +--- config + replace_filter_max_buffered_size 5; + location /t { + default_type text/html; + echo -n a; + echo -n b; + echo -n c; + echo -n d; + echo -n e; + echo g; + #echo abcdeg; + replace_filter 'abcdef|b|cdf|c' [$&] g; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +a[b][c]deg +--- no_error_log +[alert] +[error] + + + +=== TEST 50: nested rematch bufs (splitting pending buf) +--- config + replace_filter_max_buffered_size 7; + location /t { + default_type text/html; + echo -n a; + echo -n b; + echo -n cd; + echo -n e; + echo -n f; + echo -n g; + echo i; + #echo abcdefh; + replace_filter 'abcdefgh|b|cdeg|d' [$&] g; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- response_body +a[b]c[d]efgi +--- no_error_log +[alert] +[error] + + + +=== TEST 51: remove C/C++ comments (1 byte at a time) +--- config + replace_filter_max_buffered_size 50; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '/\*.*?\*/|//[^\n]*' '[$&]' g; + } +--- user_files +>>> a.html + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /t +--- response_body eval +" i don't know [// hello // world /* */] +hello world [/** abc * b/c /* + hello ** // world + * + */] +blah [/* hi */] */ b +[//] +[///hi] +" +--- no_error_log +[alert] +[error] + + + +=== TEST 52: remove C/C++ comments (all at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + + location /a.html { + replace_filter '/\*.*?\*/|//[^\n]*' '[$&]' g; + } + +--- user_files +>>> a.html + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /a.html +--- response_body eval +" i don't know [// hello // world /* */] +hello world [/** abc * b/c /* + hello ** // world + * + */] +blah [/* hi */] */ b +[//] +[///hi] +" +--- no_error_log +[alert] +[error] + + + +=== TEST 53: remove C/C++ comments (all at a time) - server-level config +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + + replace_filter '/\*.*?\*/|//[^\n]*' '[$&]' g; + +--- user_files +>>> a.html + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /a.html +--- response_body eval +" i don't know [// hello // world /* */] +hello world [/** abc * b/c /* + hello ** // world + * + */] +blah [/* hi */] */ b +[//] +[///hi] +" +--- no_error_log +[alert] +[error] + + + +=== TEST 54: multiple replace_filter_types settings (server level) +--- config + replace_filter_max_buffered_size 0; + default_type text/plain; + replace_filter_types text/css text/plain; + location /t { + echo abc; + replace_filter b [$&]; + } +--- request +GET /t +--- response_body +a[b]c +--- no_error_log +[alert] +[error] + + + +=== TEST 55: multiple replace_filter_types settings (server level, but overridding in location) +--- config + replace_filter_max_buffered_size 0; + default_type text/plain; + replace_filter_types text/css text/plain; + location /t { + echo abc; + replace_filter_types text/javascript; + replace_filter b [$&]; + } +--- request +GET /t +--- response_body +abc +--- no_error_log +[alert] +[error] + + + +=== TEST 56: github issue #3: data lost in particular situation +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + location /t { + default_type text/html; + echo "ABCabcABC"; + echo "ABCabcABC"; + #echo "ABCabcABC\nABCabcABC"; + replace_filter "(a.+?c){2}" "[$&]" "ig"; + } +--- request +GET /t +--- response_body +[ABCabc][ABC +ABCabc]ABC +--- no_error_log +[alert] +[error] + + + +=== TEST 57: variation +--- config + replace_filter_max_buffered_size 5; + default_type text/html; + location /t { + default_type text/html; + #echo "ABCabcABC"; + #echo "ABCabcABC"; + echo "ACacAC ACacAC"; + replace_filter "(a.+?c){2}" "[$&]" "ig"; + } +--- request +GET /t +--- response_body +[ACacAC AC]acAC +--- no_error_log +[alert] +[error] + + + +=== TEST 58: nested pending matched +--- config + replace_filter_max_buffered_size 9; + default_type text/html; + location /t { + default_type text/html; + echo -n a; + echo -n b; + echo -n c; + echo -n def; + echo -n gh; + echo -n i; + echo k; + #echo abcdefig; + replace_filter "abcdefghij|bcdefg|cd" "[$&]" "ig"; + } +--- request +GET /t +--- response_body +a[bcdefg]hik +--- no_error_log +[alert] +[error] + + + +=== TEST 59: test split chain with b_sane=1, next=NULL +--- config + replace_filter_max_buffered_size 4; + default_type text/html; + + location = /t { + echo -n aba; + echo -n ba; + echo -n bac; + echo d; + #echo abababacd; + replace_filter abacd [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1217") { + print_ubacktrace() +} +--- response_body +abab[abacd] +--- no_error_log +[alert] +[error] + + + +=== TEST 60: test split chain with b_sane=1, next not NULL +--- config + replace_filter_max_buffered_size 6; + default_type text/html; + + location = /t { + echo -n aba; + echo -n ba; + echo -n ba; + echo -n bac; + echo d; + #echo abababacd; + replace_filter ababacd [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1217") { + print_ubacktrace() +} +--- response_body +abab[ababacd] +--- no_error_log +[alert] +[error] + + + +=== TEST 61: trim leading spaces (1 byte at a time) +--- config + replace_filter_max_buffered_size 6; + default_type text/html; + location /a.html { + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '^\s+' '[$&]' g; + } + +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc +--- request +GET /t +--- response_body +[ ]hello, world +blah yeah +hello +[ ]baby! +[ +]abc +--- no_error_log +[alert] +[error] + + + +=== TEST 62: split ctx->pending into ctx->pending and ctx->free +--- config + replace_filter_max_buffered_size 3; + default_type text/html; + + location = /t { + #echo "abc\nd"; + echo -n a; + echo -n b; + echo -n c; + echo -n "\n"; + echo d; + replace_filter "abcd|bc\ne|c$" [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1482") { + print_ubacktrace() +} +--- response_body +ab[c] +d +--- no_error_log +[alert] +[error] + + + +=== TEST 63: trim both leading and trailing spaces (1 byte at a time) +--- config + default_type text/html; + replace_filter_max_buffered_size 5; + location /t { + echo -n 'a'; + echo_sleep 0.001; + echo ' '; + echo_sleep 0.001; + echo ''; + echo_sleep 0.001; + echo ' '; + echo_sleep 0.001; + echo "b"; + echo_sleep 0.001; + echo " "; + replace_filter '^\s+|\s+$' '[$&]' g; + } + + location = /main { + echo_location_async /t1; + echo_location_async /t2; + echo_location_async /t3; + echo_location_async /t4; + echo_location_async /t5; + echo_location_async /t6; + } + +--- stap3 eval: $::StapOutputChains +--- request +GET /main +--- response_body chop +a[ + + ] +b +[ +]a[ + + ] +b +[ +]a[ + + ] +b +[ +]a[ + + ] +b +[ +]a[ + + ] +b +[ +]a[ + + ] +b +[ +] + +--- no_error_log +[alert] +[error] + + + +=== TEST 64: global substitution + nginx vars +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo bbcd; + replace_filter ([bc])|(d) [$1-$2-$foo] g; + } +--- request +GET /t +--- response_body +[b--X][b--X][c--X][-d-X] + +--- no_error_log +[alert] +[error] + + + +=== TEST 65: global substitution + nginx vars (splitted bufs) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo -n b; + echo -n b; + echo -n c; + echo d; + replace_filter ([bc])|(d) [$1-$2-$foo] g; + } +--- request +GET /t +--- response_body +[b--X][b--X][c--X][-d-X] + +--- no_error_log +[alert] +[error] + + + +=== TEST 66: global substitution + nginx vars (out of captures) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + set $foo X; + echo -n b; + echo -n b; + echo -n c; + echo d; + replace_filter [bc]|d [$1-$2-$foo] g; + } +--- request +GET /t + +--- stap +F(ngx_http_replace_complex_value) { + println("complex value") +} + +--- stap_out +complex value +complex value +complex value +complex value + +--- response_body +[--X][--X][--X][--X] + +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/05-capturing-max-buffered.t b/modules/replace-filter-nginx-module/t/05-capturing-max-buffered.t new file mode 100644 index 0000000..17def11 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/05-capturing-max-buffered.t @@ -0,0 +1,311 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4); + +our $StapOutputChains = <<'_EOC_'; +global active + +F(ngx_http_handler) { + active = 1 +} + +/* +F(ngx_http_write_filter) { + if (active && pid() == target()) { + printf("http writer filter: %s\n", ngx_chain_dump($in)) + } +} +*/ + +F(ngx_http_chunked_body_filter) { + if (active && pid() == target()) { + printf("http chunked filter: %s\n", ngx_chain_dump($in)) + } +} + +F(ngx_http_replace_output) { + if (active && pid() == target()) { + printf("http replace output: %s\n", ngx_chain_dump($ctx->out)) + } +} + +probe syscall.writev { + if (active && pid() == target()) { + printf("writev(%s)", ngx_iovec_dump($vec, $vlen)) + /* + for (i = 0; i < $vlen; i++) { + printf(" %p [%s]", $vec[i]->iov_base, text_str(user_string_n($vec[i]->iov_base, $vec[i]->iov_len))) + } + */ + } +} + +probe syscall.writev.return { + if (active && pid() == target()) { + printf(" = %s\n", retstr) + } +} + +_EOC_ + +#no_diff(); +no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: 1-byte chain bufs (0) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1413") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() +} + +--- response_body +ababacd +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (0): 1 +--- no_error_log +[error] + + + +=== TEST 2: 1-byte chain bufs (1) +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1439") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- response_body +ababacd +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (1): 2 +--- no_error_log +[error] + + + +=== TEST 3: 1-byte chain bufs (2) +--- config + default_type text/html; + replace_filter_max_buffered_size 2; + + location = /t { + echo -n a; + echo -n b; + echo -n a; + echo -n b; + echo -n a; + echo -n c; + echo d; + replace_filter abac [$&]; + } +--- request +GET /t +--- stap2 eval: $::StapOutputChains +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1439") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- response_body +ababacd +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (2): 3 +--- no_error_log +[error] + + + +=== TEST 4: trim both leading and trailing spaces (1 byte at a time) (6) +--- config + replace_filter_max_buffered_size 6; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter '^\s+|\s+$' '[$&]' g; + } +--- user_files +>>> a.html + hello, world +blah yeah +hello + baby! + +abc + +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1438") { + //printf("chain: %s", ngx_chain_dump($ctx->busy)) + print_ubacktrace() + exit() +} + +--- request +GET /t +--- response_body +[ ]hello, world[ ] +blah yeah +hello[ ] +[ ]baby! + +abc + +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (6): 7 +--- no_error_log +[error] + + + +=== TEST 5: github issue #2: error "general look-ahead not supported" +--- config + replace_filter_max_buffered_size 0; + location /t { + charset utf-8; + default_type text/html; + echo "ABCabcABCabc"; + #replace_filter_types text/plain; + replace_filter "a.+a" "[$&]" "ig"; + } +--- request +GET /t + +--- stap3 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1481") { + print_ubacktrace() +} + +--- response_body +ABCabcABCabc +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (0): 12 +--- no_error_log +[error] + + + +=== TEST 6: backtrack to the middle of a pending capture (pending: output|capture + rematch) (0) +--- config + replace_filter_max_buffered_size 0; + default_type text/html; + location = /t { + echo -n ab; + echo -n c; + echo d; + replace_filter 'abce|b' '[$&]' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1492") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +abcd + +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (0): 2 +--- no_error_log +[error] + + + +=== TEST 7: backtrack to the middle of a pending capture (pending: output|capture + rematch) (1) +--- config + replace_filter_max_buffered_size 1; + default_type text/html; + location = /t { + echo -n ab; + echo -n c; + echo d; + replace_filter 'abce|b' '[$&]' g; + } + +--- stap2 +probe process("nginx").statement("*@ngx_http_replace_filter_module.c:1501") { + print_ubacktrace() +} + +--- stap3 eval: $::StapOutputChains +--- request +GET /t +--- response_body +abcd + +--- error_log +replace filter: exceeding replace_filter_max_buffered_size (1): 2 +--- no_error_log +[error] + diff --git a/modules/replace-filter-nginx-module/t/06-if.t b/modules/replace-filter-nginx-module/t/06-if.t new file mode 100644 index 0000000..99940d2 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/06-if.t @@ -0,0 +1,65 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4); + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: local if hit +--- config + location /t { + default_type text/plain; + echo abcabcabde; + + if ($arg_disable = "") { + replace_filter_types text/plain; + replace_filter_max_buffered_size 0; + replace_filter abcabd X; + } + } +--- request +GET /t +--- response_body +abcXe +--- no_error_log +[alert] +[error] + + + +=== TEST 2: local if miss +--- config + replace_filter_max_buffered_size 0; + location /t { + default_type text/plain; + echo abcabcabde; + + if ($arg_disable = "") { + replace_filter_types text/plain; + replace_filter_max_buffered_size 0; + replace_filter abcabd X; + } + } +--- request +GET /t?disable=1 +--- response_body +abcabcabde +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/07-multi.t b/modules/replace-filter-nginx-module/t/07-multi.t new file mode 100644 index 0000000..8e57545 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/07-multi.t @@ -0,0 +1,560 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4 + 5); + +our $StapOutputChains = <<'_EOC_'; +global active + +F(ngx_http_handler) { + active = 1 +} + +/* +F(ngx_http_write_filter) { + if (active && pid() == target()) { + printf("http writer filter: %s\n", ngx_chain_dump($in)) + } +} +*/ + +F(ngx_http_chunked_body_filter) { + if (active && pid() == target()) { + printf("http chunked filter: %s\n", ngx_chain_dump($in)) + } +} + +F(ngx_http_replace_output) { + if (active && pid() == target()) { + printf("http replace output: %s\n", ngx_chain_dump($ctx->out)) + } +} + +probe syscall.writev { + if (active && pid() == target()) { + printf("writev(%s)", ngx_iovec_dump($vec, $vlen)) + /* + for (i = 0; i < $vlen; i++) { + printf(" %p [%s]", $vec[i]->iov_base, text_str(user_string_n($vec[i]->iov_base, $vec[i]->iov_len))) + } + */ + } +} + +probe syscall.writev.return { + if (active && pid() == target()) { + printf(" = %s\n", retstr) + } +} + +_EOC_ + +#no_diff(); +#no_long_string(); +run_tests(); + +__DATA__ + +=== TEST 1: once patterns +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'hello world world hello'; + replace_filter world "<$&>"; + replace_filter hello "[$&]"; + } +--- request +GET /t +--- response_body +[hello] world hello + +--- stap +F(ngx_http_replace_non_capturing_parse) { + println("non capturing parse") +} + +F(ngx_http_replace_capturing_parse) { + println("capturing parse") +} + +--- stap_out_like chop +^(capturing parse\n)+$ + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 2: once patterns +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello world Hello world'; + replace_filter world "<$&>"; + replace_filter hello "[$&]"; + } +--- request +GET /t +--- response_body +Hello Hello world + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 3: case-insensitive patterns +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello world WORLD HELLO'; + replace_filter world "<$&>"; + replace_filter hello "[$&]" i; + } +--- request +GET /t +--- response_body +[Hello] WORLD HELLO + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 4: global subs +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'hello world world hello'; + replace_filter world "<$&>" g; + replace_filter hello "[$&]" g; + } +--- request +GET /t +--- response_body +[hello] [hello] + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 5: global subs (case sensitive) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello World worlD hellO'; + replace_filter world "<$&>" g; + replace_filter hello "[$&]" g; + } +--- request +GET /t +--- response_body +Hello World worlD hellO + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 6: global subs (case insensitive) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello World worlD hellO'; + replace_filter world "<$&>" ig; + replace_filter hello "[$&]" g; + } +--- request +GET /t +--- response_body +Hello hellO + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 7: global subs (case insensitive) (2) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello World worlD hellO'; + replace_filter world "<$&>" g; + replace_filter hello "[$&]" ig; + } +--- request +GET /t +--- response_body +[Hello] World worlD [hellO] + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 8: global subs (case insensitive) (3) +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello World worlD hellO'; + replace_filter world "<$&>" gi; + replace_filter hello "[$&]" ig; + } +--- request +GET /t +--- response_body +[Hello] [hellO] + +--- stap +F(ngx_http_replace_non_capturing_parse) { + println("non capturing parse") +} + +F(ngx_http_replace_capturing_parse) { + println("capturing parse") +} + +--- stap_out_like chop +^(capturing parse\n)+$ + +--- no_error_log +[alert] +[error] + + + +=== TEST 9: global subs (case insensitive) - non-capturing +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo 'Hello World'; + replace_filter world "<>" gi; + replace_filter hello "[]" ig; + } +--- request +GET /t +--- response_body +[] <> + +--- stap +F(ngx_http_replace_non_capturing_parse) { + println("non capturing parse") +} + +F(ngx_http_replace_capturing_parse) { + println("capturing parse") +} + +--- stap_out_like chop +^(non capturing parse\n)+$ + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 10: working as a tokenizer +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo -n a; + echo b; + replace_filter a "[$&]" g; + replace_filter ab "<$&>" g; + } +--- request +GET /t +--- response_body +[a]b + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 11: working as a tokenizer (2) +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + location /t { + echo -n a; + echo b; + replace_filter ab "<$&>" g; + replace_filter a "[$&]" g; + } +--- request +GET /t +--- response_body + + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 12: on server level +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + replace_filter ab "<$&>" g; + replace_filter a "[$&]" g; + + location /t { + echo -n a; + echo b; + } +--- request +GET /t +--- response_body + + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 13: mixing once and global patterns +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + location /t { + echo hello world hiya hiya world hello; + replace_filter hello "<$&>"; + replace_filter hiya "{$&}"; + replace_filter world "[$&]" g; + } +--- request +GET /t +--- response_body + [world] {hiya} hiya [world] hello + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 14: all once +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + location /t { + echo hello world hiya hiya world hello; + replace_filter hello "<$&>"; + replace_filter hiya "{$&}"; + replace_filter world "[$&]"; + } +--- request +GET /t +--- response_body + [world] {hiya} hiya world hello + +--- stap +F(ngx_http_replace_complex_value) { + println("complex value") +} + +--- stap_out +complex value +complex value +complex value + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 15: all once (server level) +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + replace_filter hello "<$&>"; + replace_filter hiya "{$&}"; + replace_filter world "[$&]"; + + location /t { + echo hello world hiya hiya world hello; + } +--- request +GET /t +--- response_body + [world] {hiya} hiya world hello + +--- stap +F(ngx_http_replace_complex_value) { + println("complex value") +} + +--- stap_out +complex value +complex value +complex value + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + + + +=== TEST 16: remove C/C++ comments (1 byte at a time) +--- config + replace_filter_max_buffered_size 50; + default_type text/html; + location /a.html { + internal; + } + + location = /t { + content_by_lua ' + local res = ngx.location.capture("/a.html") + local txt = res.body + for i = 1, string.len(txt) do + ngx.print(string.sub(txt, i, i)) + ngx.flush(true) + end + '; + replace_filter "'(?:\\\\[^\n]|[^'\n])*'" $& g; + replace_filter '"(?:\\\\[^\n]|[^"\n])*"' $& g; + replace_filter '/\*.*?\*/|//[^\n]*' '' g; + } +--- user_files +>>> a.html +b = '"'; /* blah */ c = '"' +a = "h\"/* */"; + i don't know // hello // world /* */ +hello world /** abc * b/c /* + hello ** // world + * + */ +blah /* hi */ */ b +// +///hi +--- stap2 +F(ngx_palloc) { + if ($size < 0) { + print_ubacktrace() + exit() + } +} +--- request +GET /t +--- response_body eval +qq{b = '"'; c = '"' +a = "h\\"/* */"; + i don't know +hello world +blah */ b + + +} +--- no_error_log +[alert] +[error] + + + +=== TEST 17: more patterns +--- config + default_type text/html; + replace_filter_max_buffered_size 1; + location /t { + #echo hello world hiya hiya world hello; + replace_filter a A; + replace_filter b B; + replace_filter c C; + replace_filter d D; + replace_filter e E; + replace_filter f F; + replace_filter g G; + replace_filter h H; + replace_filter i I; + replace_filter j J; + replace_filter k K; + replace_filter l L; + replace_filter m M; + replace_filter n N; + replace_filter o O; + replace_filter p P; + replace_filter q Q; + replace_filter r R; + replace_filter s S; + replace_filter t T; + replace_filter u U; + replace_filter v V; + replace_filter w W; + replace_filter x X; + replace_filter y Y; + replace_filter z Z; + } +--- request +GET /t +--- user_files +>>> t +It'll be officially possible when the timer_by_lua directive is +implemented in ngx_lua :) + +For now, people have been using some tricks to do something like that, +i.e., using detached long-running requests (by calling ngx.eof early). +See the related documentation for details: + +--- response_body +IT'Ll BE OFfICiAllY PoSsible WHeN the tiMeR_by_lUa DirectiVe is +implemented in nGX_lua :) + +For now, people have been using some tricKs to do something like that, +i.e., using detached long-running reQuests (by calling ngx.eof early). +See the related documentation for details: + +--- stap2 eval: $::StapOutputChains +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/08-gzip.t b/modules/replace-filter-nginx-module/t/08-gzip.t new file mode 100644 index 0000000..2548390 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/08-gzip.t @@ -0,0 +1,39 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +no_shuffle(); + +plan tests => repeat_each() * (blocks() * 3); + +run_tests(); + +__DATA__ + +=== TEST 1: once patterns +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + content_by_lua ' + ngx.header.content_encoding = "gzip" + ngx.say("hello world world hello"); + '; + replace_filter hello "[$&]"; + replace_filter world "<$&>"; + } +--- request +GET /t +--- response_body +hello world world hello +--- no_error_log +[error] + diff --git a/modules/replace-filter-nginx-module/t/09-unused.t b/modules/replace-filter-nginx-module/t/09-unused.t new file mode 100644 index 0000000..c933434 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/09-unused.t @@ -0,0 +1,121 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 5); + +run_tests(); + +__DATA__ + +=== TEST 1: used +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter abcabd X; + } +--- request +GET /t + +--- stap +F(ngx_http_replace_header_filter) { + println("replace header filter") +} + +F(ngx_http_replace_body_filter) { + println("replace body filter") +} + +--- stap_out +replace header filter +replace body filter +replace body filter + +--- response_body +abcXe +--- no_error_log +[alert] +[error] + + + +=== TEST 2: unused +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + #replace_filter abcabd X; + } +--- request +GET /t + +--- stap +F(ngx_http_replace_header_filter) { + println("replace header filter") +} + +F(ngx_http_replace_body_filter) { + println("replace body filter") +} + +--- stap_out + +--- response_body +abcabcabde +--- no_error_log +[alert] +[error] + + + +=== TEST 3: used (multi http {} blocks) +This test case won't run with nginx 1.9.3+ since duplicate http {} blocks +have been prohibited since then. +--- SKIP +--- config + default_type text/html; + replace_filter_max_buffered_size 0; + location /t { + echo abcabcabde; + replace_filter abcabd X; + } +--- post_main_config + http { + } + +--- request +GET /t + +--- stap +F(ngx_http_replace_header_filter) { + println("replace header filter") +} + +F(ngx_http_replace_body_filter) { + println("replace body filter") +} + +--- stap_out +replace header filter +replace body filter +replace body filter + +--- response_body +abcXe +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/10-last-modified.t b/modules/replace-filter-nginx-module/t/10-last-modified.t new file mode 100644 index 0000000..954c35b --- /dev/null +++ b/modules/replace-filter-nginx-module/t/10-last-modified.t @@ -0,0 +1,90 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 5); + +run_tests(); + +__DATA__ + +=== TEST 1: replace_filter_last_modified clear +--- config + default_type text/html; + replace_filter_last_modified clear; + location /t { + content_by_lua ' + ngx.header["Last-Modified"] = "Wed, 20 Nov 2013 05:30:35 GMT" + ngx.say("ok") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +ok +--- response_headers +!Last-Modified +--- no_error_log +[alert] +[error] + + + +=== TEST 2: replace_filter_last_modified keep +--- config + default_type text/html; + replace_filter_last_modified keep; + location /t { + content_by_lua ' + ngx.header["Last-Modified"] = "Wed, 20 Nov 2013 05:30:35 GMT" + ngx.say("ok") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +ok +--- response_headers +Last-Modified: Wed, 20 Nov 2013 05:30:35 GMT +--- no_error_log +[alert] +[error] + + + +=== TEST 3: replace_filter_last_modified default to clear +--- config + default_type text/html; + #replace_filter_last_modified clear; + location /t { + content_by_lua ' + ngx.header["Last-Modified"] = "Wed, 20 Nov 2013 05:30:35 GMT" + ngx.say("ok") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +ok +--- response_headers +!Last-Modified +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/t/11-skip.t b/modules/replace-filter-nginx-module/t/11-skip.t new file mode 100644 index 0000000..9e14698 --- /dev/null +++ b/modules/replace-filter-nginx-module/t/11-skip.t @@ -0,0 +1,194 @@ +# vim:set ft= ts=4 sw=4 et fdm=marker: + +use lib 'lib'; +use Test::Nginx::Socket; + +#worker_connections(1014); +#master_on(); +#workers(2); +#log_level('warn'); + +repeat_each(2); + +#no_shuffle(); + +plan tests => repeat_each() * (blocks() * 4); + +run_tests(); + +__DATA__ + +=== TEST 1: skip true (constant) +--- config + default_type text/html; + replace_filter_skip 1; + location /t { + content_by_lua ' + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +abcabd +--- no_error_log +[alert] +[error] + + + +=== TEST 2: skip false (constant 0) +--- config + default_type text/html; + replace_filter_skip 0; + location /t { + content_by_lua ' + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +X +--- no_error_log +[alert] +[error] + + + +=== TEST 3: skip false (constant "") +--- config + default_type text/html; + replace_filter_skip ""; + location /t { + content_by_lua ' + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +X +--- no_error_log +[alert] +[error] + + + +=== TEST 4: skip true (constant, random strings) +--- config + default_type text/html; + replace_filter_skip ab; + location /t { + content_by_lua ' + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +abcabd +--- no_error_log +[alert] +[error] + + + +=== TEST 5: skip variable (1) +--- config + default_type text/html; + set $skip ''; + replace_filter_skip $skip; + location /t { + content_by_lua ' + ngx.var.skip = 1 + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +abcabd +--- no_error_log +[alert] +[error] + + + +=== TEST 6: skip variable (0) +--- config + default_type text/html; + set $skip ''; + replace_filter_skip $skip; + location /t { + content_by_lua ' + ngx.var.skip = 0 + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +X +--- no_error_log +[alert] +[error] + + + +=== TEST 7: skip variable ("") +--- config + default_type text/html; + set $skip ''; + replace_filter_skip $skip; + location /t { + content_by_lua ' + ngx.var.skip = "" + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +X +--- no_error_log +[alert] +[error] + + + +=== TEST 8: skip variable (nil) +--- config + default_type text/html; + set $skip ''; + replace_filter_skip $skip; + location /t { + content_by_lua ' + ngx.var.skip = nil + ngx.say("abcabd") + '; + replace_filter abcabd X; + } +--- request +GET /t + +--- response_body +X +--- no_error_log +[alert] +[error] + diff --git a/modules/replace-filter-nginx-module/util/build.sh b/modules/replace-filter-nginx-module/util/build.sh new file mode 100755 index 0000000..c6325b2 --- /dev/null +++ b/modules/replace-filter-nginx-module/util/build.sh @@ -0,0 +1,31 @@ +#!/bin/bash + +# this file is mostly meant to be used by the author himself. + +root=`pwd` +home=~ +version=$1 +force=$2 + +ngx-build $force $version \ + --with-cc-opt="-I$PCRE_INC -I$OPENSSL_INC" \ + --with-ld-opt="-L$PCRE_LIB -L$OPENSSL_LIB -Wl,-rpath,$SREGEX_LIB:$PCRE_LIB:$LIBDRIZZLE_LIB:$OPENSSL_LIB" \ + --with-http_ssl_module \ + --without-mail_pop3_module \ + --without-mail_imap_module \ + --without-mail_smtp_module \ + --without-http_upstream_ip_hash_module \ + --without-http_empty_gif_module \ + --without-http_memcached_module \ + --without-http_referer_module \ + --without-http_autoindex_module \ + --without-http_auth_basic_module \ + --without-http_userid_module \ + --add-module=$root $opts \ + --add-module=$root/../ndk-nginx-module \ + --add-module=$root/../lua-nginx-module \ + --add-module=$root/../echo-nginx-module \ + --with-debug + #--with-cc-opt="-g3 -O0" + #--without-http_ssi_module # we cannot disable ssi because echo_location_async depends on it (i dunno why?!) + diff --git a/nginx-1.19.2.tar.gz b/nginx-1.19.2.tar.gz new file mode 100644 index 0000000..4cd4155 Binary files /dev/null and b/nginx-1.19.2.tar.gz differ diff --git a/nginx.patch b/nginx.patch new file mode 100644 index 0000000..e5a47c7 --- /dev/null +++ b/nginx.patch @@ -0,0 +1,84 @@ +--- nginx-1.19.2/src/http/ngx_http_header_filter_module.c 2020-08-11 10:52:30.000000000 -0400 ++++ ../Khalegh-Backup/source/product/temp/nginx-1.18.0/src/http/ngx_http_header_filter_module.c 2020-08-19 12:34:10.015311438 -0400 +@@ -10,7 +10,6 @@ + #include + #include + +- + static ngx_int_t ngx_http_header_filter_init(ngx_conf_t *cf); + static ngx_int_t ngx_http_header_filter(ngx_http_request_t *r); + +@@ -46,9 +45,9 @@ + }; + + +-static u_char ngx_http_server_string[] = "Server: nginx" CRLF; +-static u_char ngx_http_server_full_string[] = "Server: " NGINX_VER CRLF; +-static u_char ngx_http_server_build_string[] = "Server: " NGINX_VER_BUILD CRLF; ++static u_char ngx_http_server_string[] = "Server: " IRON_FOX CRLF; ++static u_char ngx_http_server_full_string[] = "Server: " IRON_FOX_VERSION CRLF; ++static u_char ngx_http_server_build_string[] = "Server: " IRON_FOX_VERSION CRLF; + + + static ngx_str_t ngx_http_status_lines[] = { +--- nginx-1.19.2/src/core/nginx.h 2020-08-11 10:52:30.000000000 -0400 ++++ ../Khalegh-Backup/source/product/temp/nginx-1.18.0/src/core/nginx.h 2020-08-19 12:34:09.999311199 -0400 +@@ -9,9 +9,19 @@ + #define _NGINX_H_INCLUDED_ + + +-#define nginx_version 1019002 +-#define NGINX_VERSION "1.19.2" ++#define IRON_FOX "ironfox" ++#define IRON_FOX_VERSION "0.1.0" ++ ++ ++#define nginx_version 1018000 ++#define NGINX_VERSION "1.18.0" ++#define IRONFOX_VERSION "0.1.0" ++ ++#ifdef IRON_FOX ++#define NGINX_VER "ironfox/" IRONFOX_VERSION ++#else + #define NGINX_VER "nginx/" NGINX_VERSION ++#endif + + #ifdef NGX_BUILD + #define NGINX_VER_BUILD NGINX_VER " (" NGX_BUILD ")" +--- nginx-1.19.2/src/core/ngx_connection.c 2020-08-11 10:52:30.000000000 -0400 ++++ ../Khalegh-Backup/source/product/temp/nginx-1.18.0/src/core/ngx_connection.c 2020-08-24 11:13:46.831740051 -0400 +@@ -594,6 +579,17 @@ + return NGX_ERROR; + } + } ++ ngx_log_debug0(NGX_LOG_DEBUG_CORE, log, 0, ++ "\n_____ ______\n" ++ " |_ _| | ____|\n" ++ " | | _ __ ___ _ __ | |__ _____ __\n" ++ " | | | '__/ _ \\| '_ \\| __/ _ \\ \\/ /\n" ++ " _| |_| | | (_) | | | | | | (_) > <\n" ++ " |_____|_| \\___/|_| |_|_| \\___/_/\\_\\\n" ++ "\n" ++ "\n" ++ " By: Innovera Technology\n" ++ " CodeName: The Desert Fox (0.1.0)\n"); + + ngx_log_debug2(NGX_LOG_DEBUG_CORE, log, 0, + "bind() %V #%d ", &ls[i].addr_text, s); + +--- nginx-1.19.2/src/core/ngx_conf_file.c 2020-08-11 10:52:30.000000000 -0400 ++++ ../Khalegh-Backup/source/product/temp/nginx-1.18.0/src/core/ngx_conf_file.c 2020-08-19 12:34:10.003311259 -0400 +@@ -8,7 +8,13 @@ + #include + #include + ++#define IRONFOX ++#ifdef IRONFOX ++#define NGX_CONF_BUFFER 262144 ++#elif + #define NGX_CONF_BUFFER 4096 ++#endif ++ + + static ngx_int_t ngx_conf_add_dump(ngx_conf_t *cf, ngx_str_t *filename); + static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last);