From ee1236fa5cad19c41393b208dad3320248295d87 Mon Sep 17 00:00:00 2001 From: Brian Rogers Date: Mon, 25 Jul 2022 09:01:27 -0600 Subject: [PATCH] adding zephyr-im master branch --- .gitattributes | 14 + .gitignore | 89 + INSTALL | 78 + Makefile.in | 65 + NOTES | 27 + OPERATING | 58 + README.in | 25 + USING | 77 + clients/Makefile.in | 13 + clients/zaway/Makefile.in | 56 + clients/zaway/zaway.1 | 120 + clients/zaway/zaway.c | 270 + clients/zctl/Makefile.in | 71 + clients/zctl/zctl.1.in | 319 + clients/zctl/zctl.c | 1391 ++ clients/zctl/zctl_cmds.ct | 101 + clients/zleave/Makefile.in | 56 + clients/zleave/zleave.1 | 107 + clients/zleave/zleave.c | 424 + clients/zlocate/Makefile.in | 56 + clients/zlocate/zlocate.1 | 76 + clients/zlocate/zlocate.c | 182 + clients/znol/Makefile.in | 56 + clients/znol/znol.1 | 109 + clients/znol/znol.c | 256 + clients/zshutdown_notify/Makefile.in | 57 + clients/zshutdown_notify/zshutdown_notify.8 | 43 + clients/zshutdown_notify/zshutdown_notify.c | 143 + clients/zstat/Makefile.in | 56 + clients/zstat/zserver.h | 26 + clients/zstat/zstat.8 | 51 + clients/zstat/zstat.c | 312 + clients/zwrite/Makefile.in | 56 + clients/zwrite/zwrite.1 | 290 + clients/zwrite/zwrite.c | 568 + configure.ac | 414 + contrib/zephyr-dissector.lua | 233 + debian/.gitattributes | 1 + debian/README.krb4-5 | 1 + debian/acl/class-registry.acl | 9 + debian/acl/iui-hm_ctl.acl | 1 + debian/acl/iui-hm_stat.acl | 1 + debian/acl/iui-login.acl | 1 + debian/acl/iui-operations.acl | 1 + debian/acl/iui-user_locate.acl | 1 + debian/acl/iui-wg_ctl.acl | 1 + debian/acl/iui-zephyr_admin.acl | 1 + debian/acl/iui-zephyr_ctl.acl | 1 + debian/acl/iws-hm_ctl.acl | 1 + debian/acl/iws-hm_stat.acl | 1 + debian/acl/iws-login.acl | 1 + debian/acl/iws-operations.acl | 1 + debian/acl/iws-user_locate.acl | 1 + debian/acl/iws-wg_ctl.acl | 1 + debian/acl/iws-zephyr_admin.acl | 1 + debian/acl/iws-zephyr_ctl.acl | 1 + debian/acl/sub-hm_ctl.acl | 1 + debian/acl/sub-hm_stat.acl | 1 + debian/acl/sub-login.acl | 1 + debian/acl/sub-operations.acl | 1 + debian/acl/sub-user_locate.acl | 1 + debian/acl/sub-wg_ctl.acl | 1 + debian/acl/sub-zephyr_admin.acl | 1 + debian/acl/sub-zephyr_ctl.acl | 1 + debian/acl/xmt-hm_ctl.acl | 1 + debian/acl/xmt-hm_stat.acl | 1 + debian/acl/xmt-login.acl | 1 + debian/acl/xmt-operations.acl | 1 + debian/acl/xmt-user_locate.acl | 1 + debian/acl/xmt-wg_ctl.acl | 1 + debian/acl/xmt-zephyr_admin.acl | 1 + debian/acl/xmt-zephyr_ctl.acl | 1 + debian/changelog | 89 + debian/compat | 1 + debian/control | 191 + debian/copyright | 125 + debian/default.subscriptions | 3 + debian/dirs | 2 + debian/libzephyr-dev.files | 6 + debian/libzephyr-python.files | 1 + debian/libzephyr4-krb5.templates | 15 + debian/libzephyr4.files | 1 + debian/po/POTFILES.in | 2 + debian/po/cs.po | 91 + debian/po/es.po | 65 + debian/po/fr.po | 56 + debian/po/gl.po | 100 + debian/po/ja.po | 45 + debian/po/nl.po | 112 + debian/po/pt.po | 98 + debian/po/pt_BR.po | 111 + debian/po/ru.po | 61 + debian/po/sv.po | 57 + debian/po/templates.pot | 45 + debian/rules | 177 + debian/zephyr-clients.config | 42 + debian/zephyr-clients.docs | 1 + debian/zephyr-clients.files | 24 + debian/zephyr-clients.init | 74 + debian/zephyr-clients.postinst | 84 + debian/zephyr-clients.prerm | 49 + debian/zephyr-clients.templates | 30 + debian/zephyr-server-krb.README.Debian | 30 + debian/zephyr-server-krb.docs | 1 + debian/zephyr-server-krb.init | 77 + debian/zephyr-server-krb.postrm | 9 + debian/zephyr-server-krb5.init | 78 + debian/zephyr-server.config | 33 + debian/zephyr-server.docs | 1 + debian/zephyr-server.files | 36 + debian/zephyr-server.init | 72 + debian/zephyr-server.postinst | 61 + debian/zephyr-server.postrm | 9 + debian/zephyr-server.templates | 45 + debian/zephyr.vars | 11 + get_vers.sh | 24 + h/internal.h | 208 + h/sysdep.h | 191 + h/zephyr/mit-copyright.h | 24 + h/zephyr/zephyr.h | 385 + lib/Makefile.in | 81 + lib/ZAsyncLocate.c | 168 + lib/ZCkAuth.c | 67 + lib/ZCkIfNot.c | 57 + lib/ZCkZAut.c | 232 + lib/ZClosePort.c | 29 + lib/ZCmpUID.c | 24 + lib/ZCmpUIDP.c | 31 + lib/ZDumpSession.c | 138 + lib/ZExpnRlm.c | 101 + lib/ZFlsLocs.c | 39 + lib/ZFlsSubs.c | 40 + lib/ZFmtAuth.c | 134 + lib/ZFmtList.c | 59 + lib/ZFmtNotice.c | 69 + lib/ZFmtRaw.c | 42 + lib/ZFmtRawLst.c | 55 + lib/ZFmtSmRLst.c | 52 + lib/ZFmtSmRaw.c | 62 + lib/ZFreeNot.c | 24 + lib/ZGetLocs.c | 42 + lib/ZGetSender.c | 77 + lib/ZGetSubs.c | 44 + lib/ZGetWGPort.c | 41 + lib/ZIfNotice.c | 62 + lib/ZInit.c | 435 + lib/ZLocations.c | 192 + lib/ZMakeAscii.c | 92 + lib/ZMakeZcode.c | 80 + lib/ZMkAuth.c | 327 + lib/ZNewLocU.c | 49 + lib/ZOpenPort.c | 73 + lib/ZParseNot.c | 315 + lib/ZPeekIfNot.c | 57 + lib/ZPeekNot.c | 31 + lib/ZPeekPkt.c | 43 + lib/ZPending.c | 35 + lib/ZReadAscii.c | 88 + lib/ZReadZcode.c | 48 + lib/ZRecvNot.c | 52 + lib/ZRecvPkt.c | 44 + lib/ZRetSubs.c | 185 + lib/ZSendList.c | 52 + lib/ZSendNot.c | 53 + lib/ZSendPkt.c | 68 + lib/ZSendRLst.c | 48 + lib/ZSendRaw.c | 39 + lib/ZSetDest.c | 27 + lib/ZSetFD.c | 28 + lib/ZSetSrv.c | 25 + lib/ZSubs.c | 258 + lib/ZVariables.c | 195 + lib/ZWait4Not.c | 70 + lib/ZhmStat.c | 72 + lib/Zinternal.c | 1422 ++ lib/charset.c | 139 + lib/mit-copyright.h | 24 + lib/quad_cksum.c | 196 + lib/smwgc.c | 64 + lib/zephyr.1 | 93 + lib/zephyr_err.et | 57 + lib/zephyr_run_doctests | 12 + lib/zephyr_tests.py | 187 + lib/zephyr_tests.txt | 362 + new_vers.sh | 11 + python/zephyr_ctypes.py | 486 + release | 38 + server/Makefile.in | 89 + server/access.c | 251 + server/access.h | 38 + server/acl.h | 25 + server/acl_files.c | 375 + server/bdump.c | 1702 +++ server/class.c | 392 + server/client.c | 234 + server/common.c | 130 + server/default.subscriptions | 3 + server/dispatch.c | 1239 ++ server/global.c | 75 + server/kstuff.c | 755 + server/main.c | 705 + server/realm.c | 1664 +++ server/server.c | 1485 ++ server/subscr.c | 1317 ++ server/test_server.c | 348 + server/timer.c | 250 + server/timer.h | 54 + server/uloc.c | 932 ++ server/utf8proc.c | 585 + server/utf8proc.h | 367 + server/utf8proc_data.c | 13383 ++++++++++++++++++ server/version.c | 51 + server/zephyrd.8.in | 129 + server/zserver.h | 532 + server/zsrv_conf.h | 55 + server/zsrv_err.et | 43 + server/zstring.c | 191 + server/zstring.h | 33 + zephyr.pc.in | 12 + zhm/Makefile.in | 68 + zhm/queue.c | 264 + zhm/timer.c | 251 + zhm/timer.h | 54 + zhm/zhm.8.in | 106 + zhm/zhm.c | 623 + zhm/zhm.h | 92 + zhm/zhm_client.c | 101 + zhm/zhm_server.c | 313 + zwgc/.gitattributes | 4 + zwgc/Makefile.in | 167 + zwgc/X_driver.c | 412 + zwgc/X_driver.h | 32 + zwgc/X_fonts.c | 255 + zwgc/X_fonts.h | 46 + zwgc/X_gram.c | 562 + zwgc/X_gram.h | 92 + zwgc/browser.c | 55 + zwgc/browser.h | 40 + zwgc/buffer.c | 46 + zwgc/buffer.h | 26 + zwgc/character_class.c | 45 + zwgc/character_class.h | 28 + zwgc/dictionary.c | 260 + zwgc/dictionary.h | 112 + zwgc/error.c | 22 + zwgc/error.h | 59 + zwgc/eval.c | 300 + zwgc/eval.h | 43 + zwgc/exec.c | 482 + zwgc/exec.h | 22 + zwgc/file.c | 119 + zwgc/file.h | 24 + zwgc/formatter.c | 562 + zwgc/formatter.h | 43 + zwgc/instantiate | 39 + zwgc/lexer.c | 673 + zwgc/lexer.h | 59 + zwgc/main.c | 730 + zwgc/main.h | 54 + zwgc/mux.c | 239 + zwgc/mux.h | 72 + zwgc/new_memory.c | 244 + zwgc/new_memory.h | 84 + zwgc/new_string.c | 193 + zwgc/new_string.h | 134 + zwgc/node.c | 331 + zwgc/node.h | 126 + zwgc/notice.c | 351 + zwgc/notice.h | 75 + zwgc/parser.h | 54 + zwgc/parser.y | 387 + zwgc/plus.c | 499 + zwgc/plus.h | 29 + zwgc/pointer.h | 26 + zwgc/port.c | 656 + zwgc/port.h | 124 + zwgc/regexp.c | 46 + zwgc/regexp.h | 24 + zwgc/stack.h | 65 + zwgc/standard_ports.c | 305 + zwgc/string_dictionary_aux.c | 102 + zwgc/string_dictionary_aux.h | 57 + zwgc/subscriptions.c | 402 + zwgc/subscriptions.h | 30 + zwgc/substitute.c | 169 + zwgc/substitute.h | 45 + zwgc/text_operations.c | 129 + zwgc/text_operations.h | 29 + zwgc/tty_filter.c | 597 + zwgc/tty_filter.h | 2 + zwgc/unsigned_long.h | 4 + zwgc/variables.c | 243 + zwgc/variables.h | 96 + zwgc/xcut.c | 437 + zwgc/xcut.h | 5 + zwgc/xerror.c | 55 + zwgc/xerror.h | 28 + zwgc/xmark.c | 418 + zwgc/xmark.h | 52 + zwgc/xrevstack.c | 271 + zwgc/xrevstack.h | 33 + zwgc/xselect.c | 214 + zwgc/xselect.h | 28 + zwgc/xshow.c | 833 ++ zwgc/zephyr.c | 267 + zwgc/zephyr.h | 26 + zwgc/zwgc.1.in | 1067 ++ zwgc/zwgc.desc | 136 + zwgc/zwgc.el | 184 + zwgc/zwgc.h | 28 + zwgc/zwgc_resources | 102 + 311 files changed, 62265 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 INSTALL create mode 100644 Makefile.in create mode 100644 NOTES create mode 100644 OPERATING create mode 100644 README.in create mode 100644 USING create mode 100644 clients/Makefile.in create mode 100644 clients/zaway/Makefile.in create mode 100644 clients/zaway/zaway.1 create mode 100644 clients/zaway/zaway.c create mode 100644 clients/zctl/Makefile.in create mode 100644 clients/zctl/zctl.1.in create mode 100644 clients/zctl/zctl.c create mode 100644 clients/zctl/zctl_cmds.ct create mode 100644 clients/zleave/Makefile.in create mode 100644 clients/zleave/zleave.1 create mode 100644 clients/zleave/zleave.c create mode 100644 clients/zlocate/Makefile.in create mode 100644 clients/zlocate/zlocate.1 create mode 100644 clients/zlocate/zlocate.c create mode 100644 clients/znol/Makefile.in create mode 100644 clients/znol/znol.1 create mode 100644 clients/znol/znol.c create mode 100644 clients/zshutdown_notify/Makefile.in create mode 100644 clients/zshutdown_notify/zshutdown_notify.8 create mode 100644 clients/zshutdown_notify/zshutdown_notify.c create mode 100644 clients/zstat/Makefile.in create mode 100644 clients/zstat/zserver.h create mode 100644 clients/zstat/zstat.8 create mode 100644 clients/zstat/zstat.c create mode 100644 clients/zwrite/Makefile.in create mode 100644 clients/zwrite/zwrite.1 create mode 100644 clients/zwrite/zwrite.c create mode 100644 configure.ac create mode 100644 contrib/zephyr-dissector.lua create mode 100644 debian/.gitattributes create mode 100644 debian/README.krb4-5 create mode 100644 debian/acl/class-registry.acl create mode 100644 debian/acl/iui-hm_ctl.acl create mode 100644 debian/acl/iui-hm_stat.acl create mode 100644 debian/acl/iui-login.acl create mode 100644 debian/acl/iui-operations.acl create mode 100644 debian/acl/iui-user_locate.acl create mode 100644 debian/acl/iui-wg_ctl.acl create mode 100644 debian/acl/iui-zephyr_admin.acl create mode 100644 debian/acl/iui-zephyr_ctl.acl create mode 100644 debian/acl/iws-hm_ctl.acl create mode 100644 debian/acl/iws-hm_stat.acl create mode 100644 debian/acl/iws-login.acl create mode 100644 debian/acl/iws-operations.acl create mode 100644 debian/acl/iws-user_locate.acl create mode 100644 debian/acl/iws-wg_ctl.acl create mode 100644 debian/acl/iws-zephyr_admin.acl create mode 100644 debian/acl/iws-zephyr_ctl.acl create mode 100644 debian/acl/sub-hm_ctl.acl create mode 100644 debian/acl/sub-hm_stat.acl create mode 100644 debian/acl/sub-login.acl create mode 100644 debian/acl/sub-operations.acl create mode 100644 debian/acl/sub-user_locate.acl create mode 100644 debian/acl/sub-wg_ctl.acl create mode 100644 debian/acl/sub-zephyr_admin.acl create mode 100644 debian/acl/sub-zephyr_ctl.acl create mode 100644 debian/acl/xmt-hm_ctl.acl create mode 100644 debian/acl/xmt-hm_stat.acl create mode 100644 debian/acl/xmt-login.acl create mode 100644 debian/acl/xmt-operations.acl create mode 100644 debian/acl/xmt-user_locate.acl create mode 100644 debian/acl/xmt-wg_ctl.acl create mode 100644 debian/acl/xmt-zephyr_admin.acl create mode 100644 debian/acl/xmt-zephyr_ctl.acl create mode 100644 debian/changelog create mode 100644 debian/compat create mode 100644 debian/control create mode 100644 debian/copyright create mode 100644 debian/default.subscriptions create mode 100644 debian/dirs create mode 100644 debian/libzephyr-dev.files create mode 100644 debian/libzephyr-python.files create mode 100644 debian/libzephyr4-krb5.templates create mode 100644 debian/libzephyr4.files create mode 100644 debian/po/POTFILES.in create mode 100644 debian/po/cs.po create mode 100644 debian/po/es.po create mode 100644 debian/po/fr.po create mode 100644 debian/po/gl.po create mode 100644 debian/po/ja.po create mode 100644 debian/po/nl.po create mode 100644 debian/po/pt.po create mode 100644 debian/po/pt_BR.po create mode 100644 debian/po/ru.po create mode 100644 debian/po/sv.po create mode 100644 debian/po/templates.pot create mode 100755 debian/rules create mode 100644 debian/zephyr-clients.config create mode 100644 debian/zephyr-clients.docs create mode 100644 debian/zephyr-clients.files create mode 100644 debian/zephyr-clients.init create mode 100644 debian/zephyr-clients.postinst create mode 100644 debian/zephyr-clients.prerm create mode 100644 debian/zephyr-clients.templates create mode 100644 debian/zephyr-server-krb.README.Debian create mode 100644 debian/zephyr-server-krb.docs create mode 100644 debian/zephyr-server-krb.init create mode 100644 debian/zephyr-server-krb.postrm create mode 100644 debian/zephyr-server-krb5.init create mode 100644 debian/zephyr-server.config create mode 100644 debian/zephyr-server.docs create mode 100644 debian/zephyr-server.files create mode 100644 debian/zephyr-server.init create mode 100644 debian/zephyr-server.postinst create mode 100644 debian/zephyr-server.postrm create mode 100644 debian/zephyr-server.templates create mode 100644 debian/zephyr.vars create mode 100755 get_vers.sh create mode 100644 h/internal.h create mode 100644 h/sysdep.h create mode 100644 h/zephyr/mit-copyright.h create mode 100644 h/zephyr/zephyr.h create mode 100644 lib/Makefile.in create mode 100644 lib/ZAsyncLocate.c create mode 100644 lib/ZCkAuth.c create mode 100644 lib/ZCkIfNot.c create mode 100644 lib/ZCkZAut.c create mode 100644 lib/ZClosePort.c create mode 100644 lib/ZCmpUID.c create mode 100644 lib/ZCmpUIDP.c create mode 100644 lib/ZDumpSession.c create mode 100644 lib/ZExpnRlm.c create mode 100644 lib/ZFlsLocs.c create mode 100644 lib/ZFlsSubs.c create mode 100644 lib/ZFmtAuth.c create mode 100644 lib/ZFmtList.c create mode 100644 lib/ZFmtNotice.c create mode 100644 lib/ZFmtRaw.c create mode 100644 lib/ZFmtRawLst.c create mode 100644 lib/ZFmtSmRLst.c create mode 100644 lib/ZFmtSmRaw.c create mode 100644 lib/ZFreeNot.c create mode 100644 lib/ZGetLocs.c create mode 100644 lib/ZGetSender.c create mode 100644 lib/ZGetSubs.c create mode 100644 lib/ZGetWGPort.c create mode 100644 lib/ZIfNotice.c create mode 100644 lib/ZInit.c create mode 100644 lib/ZLocations.c create mode 100644 lib/ZMakeAscii.c create mode 100644 lib/ZMakeZcode.c create mode 100644 lib/ZMkAuth.c create mode 100644 lib/ZNewLocU.c create mode 100644 lib/ZOpenPort.c create mode 100644 lib/ZParseNot.c create mode 100644 lib/ZPeekIfNot.c create mode 100644 lib/ZPeekNot.c create mode 100644 lib/ZPeekPkt.c create mode 100644 lib/ZPending.c create mode 100644 lib/ZReadAscii.c create mode 100644 lib/ZReadZcode.c create mode 100644 lib/ZRecvNot.c create mode 100644 lib/ZRecvPkt.c create mode 100644 lib/ZRetSubs.c create mode 100644 lib/ZSendList.c create mode 100644 lib/ZSendNot.c create mode 100644 lib/ZSendPkt.c create mode 100644 lib/ZSendRLst.c create mode 100644 lib/ZSendRaw.c create mode 100644 lib/ZSetDest.c create mode 100644 lib/ZSetFD.c create mode 100644 lib/ZSetSrv.c create mode 100644 lib/ZSubs.c create mode 100644 lib/ZVariables.c create mode 100644 lib/ZWait4Not.c create mode 100644 lib/ZhmStat.c create mode 100644 lib/Zinternal.c create mode 100644 lib/charset.c create mode 100644 lib/mit-copyright.h create mode 100644 lib/quad_cksum.c create mode 100644 lib/smwgc.c create mode 100644 lib/zephyr.1 create mode 100644 lib/zephyr_err.et create mode 100755 lib/zephyr_run_doctests create mode 100755 lib/zephyr_tests.py create mode 100644 lib/zephyr_tests.txt create mode 100755 new_vers.sh create mode 100755 python/zephyr_ctypes.py create mode 100755 release create mode 100644 server/Makefile.in create mode 100644 server/access.c create mode 100644 server/access.h create mode 100644 server/acl.h create mode 100644 server/acl_files.c create mode 100644 server/bdump.c create mode 100644 server/class.c create mode 100644 server/client.c create mode 100644 server/common.c create mode 100644 server/default.subscriptions create mode 100644 server/dispatch.c create mode 100644 server/global.c create mode 100644 server/kstuff.c create mode 100644 server/main.c create mode 100644 server/realm.c create mode 100644 server/server.c create mode 100644 server/subscr.c create mode 100644 server/test_server.c create mode 100644 server/timer.c create mode 100644 server/timer.h create mode 100644 server/uloc.c create mode 100644 server/utf8proc.c create mode 100644 server/utf8proc.h create mode 100644 server/utf8proc_data.c create mode 100644 server/version.c create mode 100644 server/zephyrd.8.in create mode 100644 server/zserver.h create mode 100644 server/zsrv_conf.h create mode 100644 server/zsrv_err.et create mode 100644 server/zstring.c create mode 100644 server/zstring.h create mode 100644 zephyr.pc.in create mode 100644 zhm/Makefile.in create mode 100644 zhm/queue.c create mode 100644 zhm/timer.c create mode 100644 zhm/timer.h create mode 100644 zhm/zhm.8.in create mode 100644 zhm/zhm.c create mode 100644 zhm/zhm.h create mode 100644 zhm/zhm_client.c create mode 100644 zhm/zhm_server.c create mode 100644 zwgc/.gitattributes create mode 100644 zwgc/Makefile.in create mode 100644 zwgc/X_driver.c create mode 100644 zwgc/X_driver.h create mode 100644 zwgc/X_fonts.c create mode 100644 zwgc/X_fonts.h create mode 100644 zwgc/X_gram.c create mode 100644 zwgc/X_gram.h create mode 100644 zwgc/browser.c create mode 100644 zwgc/browser.h create mode 100644 zwgc/buffer.c create mode 100644 zwgc/buffer.h create mode 100644 zwgc/character_class.c create mode 100644 zwgc/character_class.h create mode 100644 zwgc/dictionary.c create mode 100644 zwgc/dictionary.h create mode 100644 zwgc/error.c create mode 100644 zwgc/error.h create mode 100644 zwgc/eval.c create mode 100644 zwgc/eval.h create mode 100644 zwgc/exec.c create mode 100644 zwgc/exec.h create mode 100644 zwgc/file.c create mode 100644 zwgc/file.h create mode 100644 zwgc/formatter.c create mode 100644 zwgc/formatter.h create mode 100755 zwgc/instantiate create mode 100644 zwgc/lexer.c create mode 100644 zwgc/lexer.h create mode 100644 zwgc/main.c create mode 100644 zwgc/main.h create mode 100644 zwgc/mux.c create mode 100644 zwgc/mux.h create mode 100644 zwgc/new_memory.c create mode 100644 zwgc/new_memory.h create mode 100644 zwgc/new_string.c create mode 100644 zwgc/new_string.h create mode 100644 zwgc/node.c create mode 100644 zwgc/node.h create mode 100644 zwgc/notice.c create mode 100644 zwgc/notice.h create mode 100644 zwgc/parser.h create mode 100644 zwgc/parser.y create mode 100644 zwgc/plus.c create mode 100644 zwgc/plus.h create mode 100644 zwgc/pointer.h create mode 100644 zwgc/port.c create mode 100644 zwgc/port.h create mode 100644 zwgc/regexp.c create mode 100644 zwgc/regexp.h create mode 100644 zwgc/stack.h create mode 100644 zwgc/standard_ports.c create mode 100644 zwgc/string_dictionary_aux.c create mode 100644 zwgc/string_dictionary_aux.h create mode 100644 zwgc/subscriptions.c create mode 100644 zwgc/subscriptions.h create mode 100644 zwgc/substitute.c create mode 100644 zwgc/substitute.h create mode 100644 zwgc/text_operations.c create mode 100644 zwgc/text_operations.h create mode 100644 zwgc/tty_filter.c create mode 100644 zwgc/tty_filter.h create mode 100644 zwgc/unsigned_long.h create mode 100644 zwgc/variables.c create mode 100644 zwgc/variables.h create mode 100644 zwgc/xcut.c create mode 100644 zwgc/xcut.h create mode 100644 zwgc/xerror.c create mode 100644 zwgc/xerror.h create mode 100644 zwgc/xmark.c create mode 100644 zwgc/xmark.h create mode 100644 zwgc/xrevstack.c create mode 100644 zwgc/xrevstack.h create mode 100644 zwgc/xselect.c create mode 100644 zwgc/xselect.h create mode 100644 zwgc/xshow.c create mode 100644 zwgc/zephyr.c create mode 100644 zwgc/zephyr.h create mode 100644 zwgc/zwgc.1.in create mode 100644 zwgc/zwgc.desc create mode 100644 zwgc/zwgc.el create mode 100644 zwgc/zwgc.h create mode 100644 zwgc/zwgc_resources diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b79747c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,14 @@ +*.c ident +*.h ident +*.y ident +*.et ident +*.ct ident +*.py ident +*.1.in ident +*.1 ident +*.8.in ident +*.8 ident +debian export-ignore +.gitignore export-ignore +.gitattributes export-ignore +release export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..17e8fa4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,89 @@ +*~ +.\#* +\#*# +autom4te.cache +TAGS +*.pyc +/build-stamp +/debian/files +/debian/*.substvars +/debian/*.debhelper.log +/configure-stamp +/debian/libzephyr-dev/* +/debian/*.debhelper +/debian/libzephyr-python/* +/debian/libzephyr4-krb/* +/debian/libzephyr4-krb45/* +/debian/libzephyr4-krb5/* +/debian/libzephyr4/* +/debian/tmp-krb5/* +/debian/tmp/* +/debian/zephyr-clients/* +/debian/zephyr-server-krb/* +/debian/zephyr-server-krb45/* +/debian/zephyr-server-krb5.README.Debian +/debian/zephyr-server-krb5.docs +/debian/zephyr-server-krb5.files +/debian/zephyr-server-krb5.postinst +/debian/zephyr-server-krb5.postrm +/debian/zephyr-server-krb5.templates +/debian/zephyr-server-krb5/* +/debian/zephyr-server/* +/krb5/* +/no-krb/* +/debian/libzephyr4-krb5.files +aclocal.m4 +configure +h/config.h.in +ltmain.sh +m4 +config.guess +config.sub +libtool +install-sh +config.log +config.status +*.o +*.lo +*.la +/lib/zephyr_err.c +/lib/zephyr_err.h +/server/zsrv_err.c +/server/zsrv_err.h +.libs +Makefile +/server/test_server +/server/zephyrd +/server/zephyrd.8 +/zhm/zhm +/zhm/zhm.8 +/zwgc/char_stack.h +/zwgc/int_dictionary.c +/zwgc/int_dictionary.h +/zwgc/pointer_dictionary.c +/zwgc/pointer_dictionary.h +/zwgc/port_dictionary.c +/zwgc/port_dictionary.h +/zwgc/string_dictionary.c +/zwgc/string_dictionary.h +/zwgc/string_stack.h +/zwgc/unsigned_long_dictionary.c +/zwgc/unsigned_long_dictionary.h +/zwgc/xmode_stack.h +/zwgc/y.tab.c +/zwgc/y.tab.h +/zwgc/zwgc +/zwgc/zwgc.1 +/clients/zaway/zaway +/clients/zctl/zctl +/clients/zctl/zctl.1 +/clients/zctl/zctl_cmds.c +/clients/zleave/zleave +/clients/zlocate/zlocate +/clients/znol/znol +/clients/zshutdown_notify/zshutdown_notify +/clients/zstat/zstat +/clients/zwrite/zwrite +/h/config.h +/h/zephyr/zephyr_err.h +/h/zephyr_version.h diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..04f62fd --- /dev/null +++ b/INSTALL @@ -0,0 +1,78 @@ +This file explains how to build and install Zephyr on a machine. To +learn how to use Zephyr once you've installed it, read the file USING. +To learn how to set up Zephyr service at a site, read the file +OPERATING. + +To build and install Zephyr, run: + + ./configure + make + make install + +This will build Zephyr without Hesiod or Kerberos support, and install +in /usr/local. To install in a location other than /usr/local, add +"--prefix=INSTPREFIX" to the configure line, where INSTPREFIX is the +directory you want to install Zephyr in. + +If your site has a Hesiod service with a valid zephyr.sloc entry (or +you can add one), you can enable Hesiod support by adding the option +"--with-hesiod=HESPREFIX" to the configure line, where +HESPREFIX/include and HESPREFIX/lib are the directories you have the +Hesiod libraries installed in. + +If your site has a Kerberos 5 service, you can enable Kerberos 5 support +by adding the option "--with-krb5=KRBPREFIX" to the configure line, +where KRBPREFIX/include and KRBPREFIX/lib are the directories you +have the Kerberos libraries installed in. + +If your site has a Kerberos 4 service, you can enable Kerberos 4 support +by adding the option "--with-krb4=KRBPREFIX" to the configure line, +where KRBPREFIX/include and KRBPREFIX/lib are the directories you +have the Kerberos libraries installed in. Note that this is +deprecated, and should only be enabled for transitions. + +If you build with both krb5 and krb4, you will get a client that only +knows how to authenticate with krb5 servers, but a server that can +understand authentication from both krb4 and krb5 clients. + +If you want/need a krb4 client, you have to build without krb5. + +If you have a make which supports VPATH in a manner compatible with +GNU make, you can build in a separate directory. Simply invoke the +configure script from within the build directory and configure will +locate the source directory for you. (If that doesn't work for some +reason, you can also specify "--srcdir=SOURCEDIR" on the configuration +line.) + +If configure can't properly find your X11 include or library +directories, add "--x-includes=INCDIR" and "--x-libraries=LIBDIR" to +the configure line. To build without X11 support, add "--without-x" +to the configure line. + +If you have Hesiod and/or Kerberos installed such that you can't +specify a single prefix for both include files and libraries, set the +environment variables CPPFLAGS and LDFLAGS to include the relevant +directories, and just configure with "--with-krb4" and +"--with-hesiod". For instance (for a csh-like shell): + + setenv CPPFLAGS "-I/opt/athena/include" + setenv LDFLAGS "-I/opt/athena/arch/sparc/lib" + ./configure --with-hesiod --with-krb4 + make + make install + +Although it's not necessary for Zephyr to function correctly, you +should add the following services to /etc/services if possible: + +zephyr-clt 2103/udp # Zephyr serv-hm connection +zephyr-hm 2104/udp # Zephyr hostmanager +zephyr-hm-srv 2105/udp # Zephyr hm-serv connection + +To learn how to use Zephyr, read the file USING and the man pages for +the various Zephyr programs. To learn how to operate a Zephyr +service, read the file OPERATING. + +We have tried to make Zephyr as portable as is reasonably possible, +but have not taken into account every possible kind of system. If you +have any problems building or installing Zephyr according to these +instructions, please go to http://zephyr.1ts.org and open a ticket. diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..a21ce15 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,65 @@ +SHELL = /bin/sh + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +bindir=@bindir@ +libdir=@libdir@ + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +INSTALL=@INSTALL@ + +SUBDIRS=lib clients server zhm zwgc + +build: + $(MAKE) all + +h/zephyr_version.h: always + sh -x ${srcdir}/new_vers.sh $(top_srcdir) + +clean: clean_version + +clean_version: + $(RM) h/zephyr_version.h + +all: h/zephyr_version.h + +all check clean: + for i in ${SUBDIRS}; do (cd $$i; ${MAKE} $@) || exit 1; done + +install: + ${INSTALL} -d ${DESTDIR}${prefix} + ${INSTALL} -d ${DESTDIR}${exec_prefix} + ${INSTALL} -d ${DESTDIR}${bindir} + ${INSTALL} -d ${DESTDIR}${libdir} + ${INSTALL} -d ${DESTDIR}${libdir}/pkgconfig + ${INSTALL} -d ${DESTDIR}${datadir} + ${INSTALL} -d ${DESTDIR}${datadir}/zephyr + ${INSTALL} -d ${DESTDIR}${sysconfdir} + ${INSTALL} -d ${DESTDIR}${sysconfdir}/zephyr/acl + ${INSTALL} -d ${DESTDIR}${sbindir} + ${INSTALL} -d ${DESTDIR}${includedir} + ${INSTALL} -d ${DESTDIR}${includedir}/zephyr + ${INSTALL} -d ${DESTDIR}${mandir} + ${INSTALL} -d ${DESTDIR}${mandir}/man1 + ${INSTALL} -d ${DESTDIR}${mandir}/man3 + ${INSTALL} -d ${DESTDIR}${mandir}/man8 + ${INSTALL} -m 644 ${srcdir}/h/zephyr/mit-copyright.h \ + ${DESTDIR}${includedir}/zephyr + ${INSTALL} -m 644 ${srcdir}/h/zephyr/zephyr.h \ + ${DESTDIR}${includedir}/zephyr + ${INSTALL} -m 644 zephyr.pc ${DESTDIR}${libdir}/pkgconfig + ${INSTALL} -m 644 h/zephyr/zephyr_err.h ${DESTDIR}${includedir}/zephyr + for i in ${SUBDIRS}; do (cd $$i; ${MAKE} $@) || exit 1; done + +always: + +.PHONY: all build check install clean clean_version always + diff --git a/NOTES b/NOTES new file mode 100644 index 0000000..7a125d6 --- /dev/null +++ b/NOTES @@ -0,0 +1,27 @@ +Please observe the following notes when making changes to the source +tree. + +The directory h contains header files used internally in the zephyr +source tree. The directory h/zephyr contains header files containing +declarations for the Zephyr API. h/zephyr/zephyr_err.h is generated +from lib/zephyr/zephyr_err.et when lib/zephyr is built. +h/zephyr/zephyr.h is generated by configure, as is h/config.h. Those +header files live in the build tree. All other header files in h live +in the source tree. + +h/config.h is generated by configure and contains the results of +configure tests as well as definitions for the installation +configuration directory and data directory. h/sysdep.h uses +h/config.h to include various header files or make various external +declarations which many programs might be interested in. h/internal.h +contains declarations internal to the "Zephyr system proper," which +includes the Zephyr library, the server, the hostmanager, and (for +now) zstat. + +h/zephyr/zephyr.h is a public header file; that is, it is installed +with the Zephyr system. As such, this header file may need to work +with compilers other than the compiler used to build the Zephyr system +itself. Thus, we use __STDC__ (both in h/sysdep.h and in zephyr.h) to +guess whether the compiler will handle const, prototypes, and stdarg. +This is unfortunately not as reliable as using autoconf features like +AC_C_CONST. diff --git a/OPERATING b/OPERATING new file mode 100644 index 0000000..e31e067 --- /dev/null +++ b/OPERATING @@ -0,0 +1,58 @@ +This file explains how to operate a Zephyr service once you have +installed Zephyr on all the relevant machines and file servers in your +environment. To learn how to configure, build, and install Zephyr, +read the file INSTALL. + +To set up Zephyr service at a site, follow these steps: + +1. Choose the machines you wish to have act as Zephyr servers at your +site. Expect the server to be CPU-efficient but to consume a bit more +memory than you might expect (at MIT, with around a thousand +simultaneous users, the Zephyr server's data size is 40MB). If you +have a lot of users, the server should have enough memory so that the +process doesn't swap. + +2a. If you configured Zephyr with Hesiod support, make sure your +Hesiod realm has a "zephyr.sloc" entry containing a record for each +server. (Each entry should contain the name of the server, nothing +else.) The Zephyr servers will use the zephyr.sloc entry to find the +other servers. Host managers will use the zephyr.sloc entry to find +the Zephyr servers by default; however, you can control the set of +servers for each host manager by giving each host a +".cluster" entry containing a record "zcluster ". +If such a record is found, the host manager will resolve +".sloc" instead of "zephyr.sloc". + +2b. If you configured Zephyr without Hesiod support, and you have +multiple Zephyr servers, each server should have a file "server.list" +in the configuration directory (which is /etc/athena/zephyr if you +configured with --enable-athena, or /usr/local/etc/zephyr if you +installed Zephyr in /usr/local and didn't use --enable-athena). This +file should contain a list of the servers, one per line. The server +will read and use this file if it exists even if the server was built +with hesiod support. + +3. If you configured Zephyr with Kerberos 5 support, make a service +key "zephyr/zephyr@" and install a keytab for that service +as "krb5.keytab" in the configuration directory of each of your zephyr +servers. Note that you need to ktadd the keytab only once and copy it +around; the files on all the servers should be identical. + +4. Start zephyrd from the system binary directory (/usr/athena/etc if +you configured with --enable-athena, /usr/local/sbin if you installed +in /usr/local and didn't use --enable-athena). zephyrd logs as +service "local6"; watch the syslogs for error messages. Arrange for +zephyrd to be run at boot time on your server machines. + +5. Each client machine should run zhm (the Zephyr Host Manager) from +the local system binary directory (/etc/athena for --enable-athena, +/usr/local/sbin if you installed in /usr/local and didn't use +--enable-athena). If you built Zephyr without Hesiod support, you +should start zhm as "zhm server1 server2 server3 ..." so that zhm +knows where the Zephyr servers are. Do not use "localhost" or +"127.0.0.1" as a server name, or zhm will become confused. + +You can send a SIGFPE signal to the server process to make it dump its +subscription database to /var/tmp/zephyr.db. (If /var/tmp didn't +exist when Zephyr was built, the subscription database will be dumped +in /usr/tmp or /tmp instead.) diff --git a/README.in b/README.in new file mode 100644 index 0000000..9011c94 --- /dev/null +++ b/README.in @@ -0,0 +1,25 @@ +This is version @VERSION@ of the Project Athena Zephyr +notification system. + +Zephyr allows users to send messages to other users or to groups of +users. Users can view incoming Zephyr messages as windowgrams +(transient X windows) or as text on a terminal. Zephyr can optionally +make use of the Kerberos version 4 security library or the Hesiod +service name resolution library. + +Bug reports or patches should go to bug-zephyr@mit.edu. Please do not +send questions about snapshots; they are not supported. + +To find out how to configure, build, and install Zephyr, read the file +INSTALL. + +To find out how to operate a Zephyr service, read the file OPERATING. + +To find out how to use an existing Zephyr service, read the file +USING. + +Please read the file NOTES before making any modifications to the +source tree. + +--Karl Ramm +http://zephyr.1ts.org/ diff --git a/USING b/USING new file mode 100644 index 0000000..ee36205 --- /dev/null +++ b/USING @@ -0,0 +1,77 @@ +This file explains how to use an existing Zephyr service once you've +built and installed the Zephyr distribution. To learn how to build +and install Zephyr, read the file INSTALL. To learn how to set up +Zephyr service at a site, read the file OPERATING. + +First, before you can do anything else, your client machine must be +running zhm from the local system binary directory (/etc/athena/zephyr +if you built Zephyr with --enable-athena, /usr/local/sbin/zephyr if +you installed Zephyr in /usr/local and didn't use --enable-athena). +Only one copy of zhm can be running on a given machine, and it can be +started by any user. If you're using a machine you don't administer, +you may want to check if the machine is configured to start up zhm +automatically at boot time. + +Once you have zhm running, you can start receiving zephyrgrams by +running the command: + + zwgc + +"zwgc" stands for "Zephyr WindowGram Client". If you built Zephyr +with X support and are using an X display, you will receive messages +as windows on your screen (click on them to get rid of them); +otherwise, you will receive messages in your terminal as text. Read +the man page on zwgc to find out how to configure it using the +.zwgc.desc file in your home directory. + +You can send messages to another user with: + + zwrite username + +To write to groups of users, you must agree on a "class" and/or +"instance" to write to (this will be explained in greater detail +below). At MIT, most users communicate in private groups via classes. +Suppose a bunch of people wanted to communicate on a class "newclass". +They would all subscribe to the class with the command: + + zctl add newclass \* \* + +and send messages with: + + zwrite -c newclass + +The "zctl add" command adds the subscription to the .zephyr.subs file +in your home directory, so that you will automatically be subscribed +to the class the next time you run zwgc. If you just want to +subscribe without adding the subscription to your .zephyr.subs file, +use "zctl sub" instead of "zctl add". + +Now for a bit more explanation about what classes and instances are: +every Zephyr message is send to a class, an instance, and a recipient, +commonly written as . The default class is +"MESSAGE"; the default instance is "PERSONAL". When you use "zwrite +username", you are sending a message to . +If you don't specify a username on the zwrite command line, you will +be sending to the recipient "*", so when you use "zwrite -c newclass", +you are sending a message to . + +Similarly, every time you request a subscription, you are subscribing +to a class, an instance, and a recipient. The recipient must be +either "*" or your username. The instance can be any string; however, +if you subscribe to instance "*", you will receive messages to any +instance as long as the class and recipient also match. The class can +be any string; "*" has no special meaning for class names. When you +start zwgc, you are automatically subscribed to + and even +if you don't explicitly request those subscriptions. + +As an example of how you might use these features, at MIT we have +several frequently-used instances of class MESSAGE, called +"white-magic", "help", "weather", "tmbg" and so forth. These are +commonly known as "public" instances because they are not intended to +exclude anyone. Users can subscribe to individual instances using +"zctl add message help \*", or they can subscribe to all of them at +once using "zctl add message \* \*". (If users do this, they can tell +zwgc to filter out messages from certain instances; see the man page +for zwgc.) If users want to have semi-private group conversations, +they use separate classes, as described earlier. diff --git a/clients/Makefile.in b/clients/Makefile.in new file mode 100644 index 0000000..2ae4614 --- /dev/null +++ b/clients/Makefile.in @@ -0,0 +1,13 @@ +SHELL = /bin/sh + +SUBDIRS=zaway zctl zleave zlocate znol \ + zshutdown_notify zstat zwrite + +all: + for i in ${SUBDIRS}; do (cd $$i; ${MAKE} $@) || exit 1; done + +check install clean: + for i in ${SUBDIRS}; do (cd $$i; ${MAKE} $@) || exit 1; done + +.PHONY: all check install clean + diff --git a/clients/zaway/Makefile.in b/clients/zaway/Makefile.in new file mode 100644 index 0000000..550a786 --- /dev/null +++ b/clients/zaway/Makefile.in @@ -0,0 +1,56 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ +top_builddir=../.. + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err + +OBJS= zaway.o + +all: zaway + +zaway: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: zaway + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zaway ${DESTDIR}${bindir} + ${INSTALL} -m 644 ${srcdir}/zaway.1 ${DESTDIR}${mandir}/man1 + +clean: + ${LIBTOOL} --mode=clean rm -f zaway + rm -f ${OBJS} + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/zaway/zaway.1 b/clients/zaway/zaway.1 new file mode 100644 index 0000000..85d0bce --- /dev/null +++ b/clients/zaway/zaway.1 @@ -0,0 +1,120 @@ +.\" $Id$ +.\" +.\" Copyright 1987,1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)zaway.1 6.1 (MIT) 7/9/87 +.\" +.TH ZAWAY 1 "July 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zaway \- tell other people via Zephyr that you aren't around +.SH SYNOPSIS +.B zaway +[ +.I OPTIONS +] +[ +.I FILE +] +.SH DESCRIPTION +.I zaway +provides a way for you to automatically send replies when other people +contact you using +.I zwrite(1). zaway +subscribes itself to class "MESSAGE", instance "*", so that it can +monitor your incoming messages. It does not affect the operation of any +other client receiving messages. +.I zaway +is typically run when you are leaving your terminal or display +temporarily. +.I zaway +usually never exits; when you return to your terminal you should type +the interrupt character (usually ^C) in order to make +.I zaway +exit. +.SS OPTIONS +.TP +.I "\-m STRING" +Use STRING as the body of the auto-reply message. Any message file +(specified on the command line or the default) is ignored. +.TP +.I "\-w" +Watch the invoking user's location status. If the user is locatable +anywhere, no auto-replies will be sent. +.TP +.I "\-h" +Displays a short usage message and exits. +.PP +.I zaway +uses a message file (which defaults +to $HOME/.away) to describe what reponses should be sent to which +senders. The general format of this file +is: +.PP +.nf + >name + >name + message + >name + message +.fi +.PP +Any number of user names may be specified preceding the message to send +to those senders. If a user name appears more than once, the message will +be a concatenation of each of the appropriate messages. There are +two special names: "*" indicates that the following message should be +sent to all senders and "%" indicates that the following message should +only be sent if the user name has not matched yet. +.PP +If no file is specified, +and no default file can be found, the following message is returned: +.sp +.in +5 +I'm sorry, but I am currently away from the terminal and am +not able to receive your message. +.in -5 +.sp +If a user name does not match any of those listed in the file, and no +"*" or "%" field is specified, no return message is sent. All +messages are preceded by a signature "Automated reply:". To avoid +loops, messages are not sent in response to messages beginning with an +"Automated reply:" signature or sent by the same Kerberos principal as +the user running +.I zaway. + +.SH SAMPLE FILE +.nf +>eichin +>tony +Hi there guys! I'm in the other room right now. +I'll be back in 5 minutes or so. +>jruser +Sorry, but I'm gone for the day... +>% +Hello...I'm not sure who you are. I'll be back soon, +though. +>* +This message comes to you compliments of zaway! +.fi + +The final "compliments" message will be included in all messages, +whereas the "I'm not sure" message will only be included in messages that +are not from "eichin", "tony", or "jruser". +.SH FILES +$HOME/.away +.SH SEE ALSO +zephyr(1), zwgc(1), zwrite(1), zhm(8), zephyrd(8) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH AUTHOR +.PP +Robert S. French (MIT-Project Athena) +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/zaway/zaway.c b/clients/zaway/zaway.c new file mode 100644 index 0000000..cb72c34 --- /dev/null +++ b/clients/zaway/zaway.c @@ -0,0 +1,270 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for the "zaway" command. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987, 1993 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include +#include + +#ifndef lint +static const char rcsid_zaway_c[] = "$Id$"; +#endif + +#define MESSAGE_CLASS "MESSAGE" +#define DEFAULT_MSG "I'm sorry, but I am currently away from the terminal and am\nnot able to receive your message.\n" +#define RESPONSE_OPCODE "" + +static char *find_message(ZNotice_t *, FILE *); + +RETSIGTYPE cleanup(int); +u_short port; + +static void +usage(char *name) +{ + printf("Usage: %s [OPTIONS] [FILE]\n" + "\n" + " -m STRING use STRING as the body of the reply message\n" + " -w watch your location and only reply if you aren't locatable\n" + " -h display this help and exit\n", + name); +} + +int +main(int argc, + char *argv[]) +{ + FILE *fp; + ZNotice_t notice; + ZSubscription_t sub; + register int retval; + struct passwd *pw; + register char *ptr; + char awayfile[BUFSIZ],*msg[2],*envptr; + int optchar, watch_location; + char *cmdline_msg; + int nlocs; + char *charset = NULL; + unsigned short zcharset; + +#ifdef _POSIX_VERSION + struct sigaction sa; +#endif + + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err(argv[0],retval,"while initializing"); + exit(1); + } + + port = 0; + if ((retval = ZOpenPort(&port)) != ZERR_NONE) { + com_err(argv[0],retval,"while opening port"); + exit(1); + } + + sub.zsub_class = MESSAGE_CLASS; + sub.zsub_classinst = "*"; + sub.zsub_recipient = ZGetSender(); + + cmdline_msg = 0; + watch_location = 0; + while ((optchar = getopt(argc, argv, "m:whx:")) != EOF) { + switch (optchar) { + case 'm': + cmdline_msg = optarg; + break; + + case 'w': + watch_location = 1; + break; + + case 'h': + usage(argv[0]); + return 0; + + case 'x': + charset = optarg; + break; + + case '?': + fprintf(stderr, + "Unrecognized option '-%c'.\n" + "Try '%s -h' for more information.\n", + optopt, argv[0]); + return 1; + } + } + + zcharset = ZGetCharset(charset); + + if (argc > optind) + (void) strcpy(awayfile,argv[optind]); + else { + envptr = getenv("HOME"); + if (envptr) + (void) sprintf(awayfile,"%s/.away",envptr); + else { + if (!(pw = getpwuid((int) getuid()))) { + fprintf(stderr,"Who are you?\n"); + exit(1); + } + (void) sprintf(awayfile,"%s/.away",pw->pw_dir); + } + } + + fp = fopen(awayfile,"r"); + if (!fp && argc > optind) { + fprintf(stderr,"File %s not found!\n",awayfile); + exit(1); + } +#ifdef _POSIX_VERSION + (void) sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = cleanup; + (void) sigaction(SIGINT, &sa, (struct sigaction *)0); + (void) sigaction(SIGTERM, &sa, (struct sigaction *)0); + (void) sigaction(SIGHUP, &sa, (struct sigaction *)0); +#else + (void) signal(SIGINT, cleanup); + (void) signal(SIGTERM, cleanup); + (void) signal(SIGHUP, cleanup); +#endif + if ((retval = ZSubscribeToSansDefaults(&sub,1,port)) != ZERR_NONE) { + com_err(argv[0],retval,"while subscribing"); + exit(1); + } + + for (;;) { + if ((retval = ZReceiveNotice(¬ice, (struct sockaddr_in *)0)) != ZERR_NONE) { + if (retval != ETIMEDOUT) + com_err(argv[0],retval,"while receiving notice"); + continue; + } + + if (strcmp(notice.z_sender,ZGetSender()) == 0 || + strcmp(notice.z_opcode,"PING") == 0 || + strcmp(notice.z_opcode,"AUTO") == 0 || + strcmp(notice.z_message,"Automated reply:") == 0) { + ZFreeNotice(¬ice); + continue; + } + + if (watch_location) { + if ((retval = ZLocateUser(ZGetSender(), &nlocs, ZNOAUTH)) + != ZERR_NONE) { + com_err(argv[0],retval,"while locating self"); + continue; + } + + if (nlocs != 0) { + /* User is logged in. Don't send an autoreply. */ + continue; + } + + ZFlushLocations(); + } + + if (cmdline_msg) { + ptr = strdup(cmdline_msg); + if (!ptr) { + com_err(argv[0],ENOMEM,"while getting cmdline message"); + exit(1); + } + } + else if (fp) { + if (!(ptr = find_message(¬ice,fp))) { + ZFreeNotice(¬ice); + continue; + } + } + else { + ptr = malloc(sizeof(DEFAULT_MSG)+1); + if (!ptr) { + com_err(argv[0],ENOMEM,"while getting default message"); + exit(1); + } + (void) strcpy(ptr,DEFAULT_MSG); + } + notice.z_recipient = notice.z_sender; + notice.z_sender = 0; + notice.z_default_format = ""; + notice.z_opcode = RESPONSE_OPCODE; + notice.z_charset = zcharset; + + msg[0] = "Automated reply:"; + msg[1] = ptr; + + notice.z_message_len = strlen(notice.z_message)+1; + if ((retval = ZSendList(¬ice,msg,2,ZNOAUTH)) != ZERR_NONE) { + com_err(argv[0],retval,"while sending notice"); + } + free(ptr); + ZFreeNotice(¬ice); + } +} + +char * +find_message(ZNotice_t *notice, + FILE *fp) +{ + char *ptr,*ptr2; + char bfr[BUFSIZ],sender[BUFSIZ]; + int gotone,lastwasnt; + + rewind(fp); + + (void) strcpy(sender,notice->z_sender); + ptr2 = strchr(sender,'@'); + if (ptr2) + *ptr2 = '\0'; + + ptr = 0; + gotone = 0; + lastwasnt = 0; + + while (fgets(bfr,sizeof bfr,fp) != (char *)0) { + if (*bfr == '>') { + if (lastwasnt) + gotone = 0; + bfr[strlen(bfr)-1] = '\0'; + ptr2 = strchr(bfr,'@'); + if (ptr2) + *ptr2 = '\0'; + if (!strcmp(bfr+1,sender) || + !strcmp(bfr+1,"*") || + (!strcmp(bfr+1,"%") && !ptr)) + gotone = 1; + lastwasnt = 0; + } + else { + if (gotone) { + if (!ptr) { + ptr = malloc((unsigned)(strlen(bfr)+1)); + *ptr = '\0'; + } + else + ptr = realloc(ptr,(unsigned)(strlen(bfr)+strlen(ptr)+1)); + (void) strcat(ptr,bfr); + } + lastwasnt = 1; + } + } + + return (ptr); +} + +RETSIGTYPE +cleanup(int ignored) +{ + ZCancelSubscriptions(port); + exit(1); +} diff --git a/clients/zctl/Makefile.in b/clients/zctl/Makefile.in new file mode 100644 index 0000000..664cbd9 --- /dev/null +++ b/clients/zctl/Makefile.in @@ -0,0 +1,71 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=../.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +editman = sed \ + -e 's|@datadir[@]|${datadir}|g' \ + -e 's|@sysconfdir[@]|${sysconfdir}|g' \ + -e 's|@sbindir[@]|${sbindir}|g' \ + -e 's|@lsbindir[@]|${lsbindir}|g' + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h @X_CFLAGS@ ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @SS_LIBS@ @LIBS@ -lcom_err + +SS_OBJS=zctl_cmds.o +OBJS= zctl.o @SS_OBJS@ + +all: zctl zctl.1 + +zctl: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +zctl_cmds.c: zctl_cmds.ct + mk_cmds ${srcdir}/zctl_cmds.ct + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +zctl.1: ${srcdir}/zctl.1.in Makefile + ${editman} ${srcdir}/$@.in > $@.tmp + mv $@.tmp $@ + +check: + +install: zctl zctl.1 + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zctl ${DESTDIR}${bindir} + ${INSTALL} -m 644 zctl.1 ${DESTDIR}${mandir}/man1 + +clean: + ${LIBTOOL} --mode=clean rm -f zctl + rm -f ${OBJS} zctl_cmds.c + rm -f zctl.1 + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/zctl/zctl.1.in b/clients/zctl/zctl.1.in new file mode 100644 index 0000000..5b73b6e --- /dev/null +++ b/clients/zctl/zctl.1.in @@ -0,0 +1,319 @@ +.\" $Id$ +.\" +.\" Copyright 1987,1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" +.TH ZCTL 1 "July 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zctl \- zephyr control program +.SH SYNOPSIS +.B zctl +[ +.I options +] +.SH DESCRIPTION +.I Zctl +is a general purpose control program for the +.I Zephyr(1) +Notification Service. It allows the user to subscribe to specific +notice types, to save the subscriptions in a file (default +$HOME/.zephyr.subs), to change his location information, and to send +control messages to the HostManager, +.I zhm(8), +and the WindowGram client, +.I zwgc(1). +.PP +The commands may be typed on the command line, or may be entered +interactively by just typing +.I zctl +and then typing commands to the prompt. +.br +.B NOTE: +For all commands accepting an optional \fIrecipient\fR argument, the +\fIrecipient\fR defaults to your Kerberos principal. You may also +subscribe to recipient ``\fI*\fR''. If you specify a recipient, it is +silently converted to ``\fI*\fR''. +.br +The commands are as follows: +.TP 15 +.B add \fIclass instance\fR [ \fIrecipient\fR ] +Subscribe to \fIclass, instance, recipient\fR, and add this triplet to +the subscriptions file. +.TP +.B add_unsubscription \fIclass instance\fR [ \fIrecipient\fR ] +Unsubscribe to \fIclass, instance, recipient\fR, and add this triplet +to the subscriptions file as an un-subscription. +For an explanation of un-subscriptions, see below. +.TP +.B cancel +Cancel all subscriptions. +.TP +.B defaults +Retrieve the default subscription list from the Zephyr server. +.TP +.B delete \fIclass instance\fR [ \fIrecipient\fR ] +Unsubscribe to \fIclass, instance, recipient\fR, and remove this triplet +from the subscriptions file. +.TP +.B delete_unsubscription \fIclass instance\fR [ \fIrecipient\fR ] +Unsubscribe to \fIclass, instance, recipient\fR, and remove this triplet +from the subscriptions file as an un-subscription. +.TP +.B file \fR[ \fIfile\fR ] +Set default subscriptions file to \fIfile\fR. If \fIfile\fR isn't specified, +show what the current subscriptions file is. +.TP +.B flush_locs \fR[ \fIuser\fR ] +Tell the Zephyr servers to flush all location information associated with +\fIuser\fR, or with the user running the command if none is given. This +should only be used to remove any incorrect data that may have been left +after a system crash. Note that only Operations staff may flush location +information associated with another user. +.TP +.B flush_subs \fR[ \fIrecipient\fR ] +Tell the Zephyr servers to flush all of \fIrecipient\fR's subscriptions, +This differs from the cancel command in that it affects subscriptions for +all of \fIrecipient\fR's clients. Note that only Operations staff may flush +the subscriptions of another user. +.TP +.B hide +Hide your location as maintained by the Zephyr server. This does not +affect the value of the exposure variable (see below, under +.B set). +.TP +.B hm_flush +Tell the HostManager, +.I zhm(8), +to ask the server to flush all state associated with the current host. +.TP +.B list \fR[ \fIfile\fR ] +List contents of current subscriptions file or +.I file. +Any macros in the file (see below) are displayed verbatim and not expanded. +.TP +.B list_requests +List all available commands. May be abbreviated by '?'. +.TP +.B load \fR[ \fIfile\fR ] +Subscribe to all subscription triplets and unsubscribe to all +un-subscription triplets in current subscriptions file or \fIfile\fR. +.TP +.B new_server +Tell the HostManager, +.I zhm(8), +to find a new Zephyr server. +.TP +.B quit +Exit from \fIzctl. +.TP +.B retrieve +Retrieve all current subscriptions from the Zephyr server. These include +subscriptions that might have been made by other programs, such as +.I znol(1). +.TP +.B save \fR[ \fIfile\fR ] +Save all current subscriptions (as returned by the Zephyr server) +into current subscriptions file or \fIfile\fR. The +file will be replaced. +.TP +.B set \fIvar\fR [ \fIvalue\fR ] +Set the value of Zephyr variable \fIvar\fR to \fIvalue\fR, or null if +no \fIvalue\fR is specified. The variable \fBexposure\fR has special +significance, and can only be set to the values none, opstaff, realm-visible, +realm-announced, net-visible, and net-announced. Setting this variable +immediately updates the information in the Zephyr servers (see below for +an explanation of the exposure levels). In addition, +setting this variable to none automatically performs the equivalent of a +.B wg_shutdown +command, and setting it to one of the other values automatically +performs the equivalent of a +.B wg_startup +command. +.br +The variable \fBresolved_addresses\fR determines whether zwgc will, +for an IP address indicating the origin of a message, attempt to look +up the hostname corresponding to that IP address. The value none +indicates that hostnames will never be found, and that the zwgc +fromhost variable will thus always contain an IP address (in +dotted-decimal form). The value all indicates that there will always +be an attempt to look up a hostname. Note that in this case, if you +have any subscriptions with recipient ``\fI*\fR'', these subscriptions +may be revealed to other Zephyr users who operate their own DNS name +servers. Any other value is interpreted as a regular expression; +hostname lookup attempts will occur only if the IP address matches +this regular expression. +.br +Any variable settings you make will be stored in \fI$HOME/.zephyr.vars\fR +.TP +.B show \fIvar\fR [ \fIvar\fR \ ... ] +Show the value of the specified Zephyr variables. If a variable is not +defined in the user's own variables file, the system variables file +(\fI@sysconfdir@/zephyr/zephyr.vars\fR) is searched for a default value. +.TP +.B subscribe \fIclass instance\fR [ \fIrecipient\fR ] +Subscribe to \fIclass, instance, recipient\fR, but don't add this triplet to +the subscriptions file. +.TP +.B unhide +Make your location as maintained by the Zephyr server visible. This does not +affect the value of the exposure variable. +.TP +.B unload \fR[ \fIfile\fR ] +Unsubscribe to all subscription triplets in current subscriptions file +or \fIfile\fR. Un-subscriptions in the file are ignored. +.TP +.B unset \fIvar\fR [ \fIvar\fR \ ... ] +Delete the definitions of the specified Zephyr variables. +.TP +.B unsubscribe \fIclass instance\fR [ \fIrecipient\fR ] +Unsubscribe to \fIclass, instance, recipient\fR, but don't remove this triplet +from the subscriptions file. +.TP +.B wg_exit +Tell the WindowGram client, +.I zwgc(1), +to exit. +.TP +.B wg_read +Tell the WindowGram client, +.I zwgc(1), +to reread its description file. +.TP +.B wg_shutdown +Tell the WindowGram client to shutdown; this causes it to ignore all +notices until a wg_startup command is issued. +.TP +.B wg_startup +Tell the WindowGram client to start accepting notices again; useful +after a wg_shutdown command has been issued. +.SH MACROS and SUBSCRIPTION FILES +There are three macros, +.I %host%, %canon%, \fRand\fI %me%. %host% +is converted to the current hostname, \fI%canon%\fR is converted to the +official hostname as returned by +.I gethostbyname(3), +and \fI%me%\fR is converted to your Kerberos principal. These macros can be +used in your \fI$HOME/.zephyr.subs\fR file or as arguments to commands +to specify the +.I class +or +.I instance +fields. A sample \fI$HOME/.zephyr.subs\fR file might contain the following: +.PP +.nf + message,urgent,%me% + syslog,%host%,* + mail,pop,%me% +.fi +.PP +.I Zctl +reads the environment variable \fBWGFILE\fR, to find the name of the +file where the windowgram port resides. If \fBWGFILE\fR is not set, +the file name defaults to /tmp/wg.\fIuid\fR, where \fIuid\fR is the +user's UNIX uid. +.SH UN-SUBSCRIPTIONS +The zephyr server, +.I zephyrd(8), +maintains default subscriptions which are automatically added to all +users' subscriptions at the time of their first subscription during a +login session. If you wish to automatically remove some of these +default subscriptions, you use +.B un-subscriptions. +When you +.B load +a subscription file containing +un-subscriptions, the un-subscriptions are automatically sent to the +server as if you had used the +.B unsubscribe +command. +.SH EXPOSURE LEVELS +The different exposure levels affect the operation of zephyr and its +interaction with the user, as follows: +.TP 10 +.I none +This completely disables Zephyr for the user. The user is not +registered with Zephyr. No user location information is +retained by Zephyr. No login or logout announcements will be +sent. No subscriptions will be entered for the user, and no notices +will be displayed by +.I zwgc(1). +.TP +.I opstaff +The user is registered with Zephyr. No login or logout +announcements will be sent, and location information will only be +visible to Operations staff. Default subscriptions and any additional +personal subscriptions will be entered for the user. +.TP +.I realm-visible +The user is registered with Zephyr. User location information is retained by +Zephyr and made available only to users within the user's +Kerberos realm. No login or logout announcements will be sent. This +is the system default. Default subscriptions and any additional +personal subscriptions will be entered for the user. +.TP +.I realm-announced +The user is registered with Zephyr. User location information is retained by +Zephyr and made available only to users authenticated within the user's +Kerberos realm. Login and logout announcements will be sent, but only to +users within the user's Kerberos realm who have explicitly requested +such via subscriptions. Default subscriptions and any additional +personal subscriptions will be entered for the user. +.TP +.I net-visible +The user is registered with Zephyr. User location information is +retained by Zephyr and made available to any authenticated user who +requests such. Login and logout announcements will be sent only to users +within the user's Kerberos realm who have explicitly requested such via +subscriptions. Default subscriptions and any additional personal +subscriptions will be entered for the user. +.TP +.I net-announced +The user is registered with Zephyr. User location information is retained by +Zephyr and made available to any authenticated user who requests such. Login +and logout announcements will be sent to any user has requested such. +Default subscriptions and any additional personal +subscriptions will be entered for the user. +.SH EXAMPLES +.TP 25 +.B zctl +Runs \fIzctl\fR in interactive mode. +.TP +.B zctl load +Load subscriptions and un-subscriptions from \fI$HOME/.zephyr.subs\fR file. +.TP +.B zctl sub message personal +Subscribe to personal messages, but don't add this to the +subscriptions file. +.TP +.B zctl save +Save all current subscriptions to the default subscriptions file. +.TP +.B zctl set exposure none +Set your exposure level to `none', effectively turning off Zephyr. +.SH SEE ALSO +zephyr(1), zwgc(1), zhm(8), zephyrd(8) +gethostbyname(3) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH FILES +/tmp/wg.* +.br +$HOME/.zephyr.subs +.br +$ZEPHYR_VARS or $HOME/.zephyr.vars +.br +@sysconfdir@/zephyr/zephyr.vars +.SH AUTHOR +.PP +Robert S. French (MIT-Project Athena) +.sp +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/zctl/zctl.c b/clients/zctl/zctl.c new file mode 100644 index 0000000..f18df10 --- /dev/null +++ b/clients/zctl/zctl.c @@ -0,0 +1,1391 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for the "zctl" command. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#ifdef HAVE_SS +#include +#endif +#include +#include +#include +#ifndef lint +static const char rcsid_zctl_c[] = "$Id$"; +#endif + +#define SUBSATONCE 7 +#define SUB 0 +#define UNSUB 1 +#define LIST 2 + +#define USERS_SUBS "/.zephyr.subs" +#define OLD_SUBS "/.subscriptions" + +#define TOKEN_HOSTNAME "%host%" +#define TOKEN_CANONNAME "%canon%" +#define TOKEN_ME "%me%" +#define TOKEN_WILD "*" + +#define ALL 0 +#define UNSUBONLY 1 +#define SUBONLY 2 + +#define ERR (-1) +#define NOT_REMOVED 0 +#define REMOVED 1 + +#ifdef HAVE_SS +int sci_idx; +#endif +char subsname[BUFSIZ]; +char ourhost[NS_MAXDNAME], ourhostcanon[NS_MAXDNAME]; + +#ifdef HAVE_SS +extern ss_request_table zctl_cmds; +#endif + +int purge_subs(register ZSubscription_t *, int); +void add_file(short, ZSubscription_t *, int); +void del_file(short, ZSubscription_t *, int); +void fix_macros(ZSubscription_t *, ZSubscription_t *, int); +void fix_macros2(char *, char **); +int make_exist(char *); +char *whoami; + +#ifndef HAVE_SS +static void run_command(int, char *[]); +static void show_commands(int, char *[]); +#endif + +/* Prototype all of the commands. + * These really should be in a header also visible to zctl_cmds.c, + * but mk_cmds doesn't make that easy. + */ +void cancel_subs(int argc, char *argv[]); +void current(int argc, char *argv[]); +void do_hide(int argc, char *argv[]); +void do_punt(int argc, char *argv[]); +void flush_locations(int argc, char *argv[]); +void flush_subscr(int argc, char *argv[]); +void hm_control(int argc, char *argv[]); +void list_punts(int argc, char *argv[]); +void load_subs(int argc, char *argv[]); +void set_file(int argc, char *argv[]); +void set_var(int argc, char *argv[]); +void show_var(int argc, char *argv[]); +void sub_file(int argc, char *argv[]); +void subscribe(int argc, char *argv[]); +void unset_var(int argc, char *argv[]); +void wgc_control(int argc, char *argv[]); + + +int +main(int argc, + char *argv[]) +{ + struct passwd *pwd; + struct hostent *hent; + char ssline[BUFSIZ],oldsubsname[BUFSIZ],*envptr,*tty = NULL; + int retval,code,i; +#ifdef HAVE_SYS_UTSNAME + struct utsname name; +#endif + + whoami = argv[0]; + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err(argv[0],retval,"while initializing"); + exit (1); + } + + /* Set hostname and tty for locations. If we support X, use the + * DISPLAY environment variable for the tty name. */ +#ifndef X_DISPLAY_MISSING + tty = getenv("DISPLAY"); +#endif + if ((retval = ZInitLocationInfo(NULL, tty)) != ZERR_NONE) + com_err(argv[0], retval, "initializing location information"); + + envptr = getenv("ZEPHYR_SUBS"); + if (envptr) + strcpy(subsname,envptr); + else { + envptr = getenv("HOME"); + if (envptr) + strcpy(subsname,envptr); + else { + if (!(pwd = getpwuid((int) getuid()))) { + fprintf(stderr,"Who are you?\n"); + exit (1); + } + + strcpy(subsname,pwd->pw_dir); + } + strcpy(oldsubsname,subsname); + strcat(oldsubsname,OLD_SUBS); + strcat(subsname,USERS_SUBS); + if (!access(oldsubsname,F_OK) && access(subsname, F_OK)) { + /* only if old one exists and new one does not exist */ + printf("The .subscriptions file in your home directory is now being used as\n.zephyr.subs . I will rename it to .zephyr.subs for you.\n"); + if (rename(oldsubsname,subsname)) + com_err(argv[0], errno, "renaming .subscriptions"); + } + } + +#ifdef HAVE_SYS_UTSNAME + uname(&name); + strcpy(ourhost, name.nodename); +#else + if (gethostname(ourhost, sizeof(ourhost)) == -1) { + com_err(argv[0],errno,"while getting host name"); + exit (1); + } +#endif + + if (!(hent = gethostbyname(ourhost))) { + fprintf(stderr,"%s: Can't resolve hostname %s; %s may be " + "wrong in subscriptions\n",argv[0],ourhost, + TOKEN_CANONNAME); + strncpy(ourhostcanon,ourhost,sizeof(ourhostcanon)-1); + } else + strncpy(ourhostcanon,hent->h_name,sizeof(ourhostcanon)-1); + +#ifdef HAVE_SS + sci_idx = ss_create_invocation("zctl","",0,&zctl_cmds,&code); + if (code) { + ss_perror(sci_idx,code,"while creating invocation"); + exit(1); +#else + if (argc <= 1) { + printf("ZCTL $Revision$ (Protocol %s%d.%d)\nType '%s help' for a list of subcommands.\n\n", + ZVERSIONHDR, + ZVERSIONMAJOR,ZVERSIONMINOR, + argv[0]); + exit(0); +#endif + } + +#ifdef HAVE_SS + if (argc > 1) { + *ssline = '\0'; + for (i=1;i 2) { + fprintf(stderr,"Usage: %s filename\n",argv[0]); + return; + } + + if (argc == 1) + printf("Current file: %s\n",subsname); + else + (void) strcpy(subsname,argv[1]); +} + +void +flush_locations(int argc, + char *argv[]) +{ + int retval; + + if (argc > 2) { + fprintf(stderr,"Usage: %s [user]\n",argv[0]); + return; + } + + if (argc > 1) + retval = ZFlushUserLocations(argv[1]); + else + retval = ZFlushMyLocations(); + + if (retval != ZERR_NONE) + com_err(whoami, retval, "while flushing locations"); +} + +void +flush_subscr(int argc, + char *argv[]) +{ + int retval; + + if (argc > 2) { + fprintf(stderr,"Usage: %s [recipient]\n",argv[0]); + return; + } + + retval = ZFlushUserSubscriptions((argc > 1) ? argv[1] : NULL); + if (retval != ZERR_NONE) + com_err(whoami, retval, "while flushing subscriptions"); +} + +void +wgc_control(int argc, + char *argv[]) +{ + int retval; + short newport; + struct sockaddr_in newsin; + ZNotice_t notice; + + newsin = ZGetDestAddr(); + + if (argc > 1) { + fprintf(stderr,"Usage: %s\n",argv[0]); + return; + } + + if ((newport = ZGetWGPort()) == -1) { + com_err(whoami, errno, "while getting WindowGram port"); + return; + } + + newsin.sin_port = (u_short) newport; + if ((retval = ZSetDestAddr(&newsin)) != ZERR_NONE) { + com_err(whoami, retval, "while setting destination address"); + return; + } + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = UNSAFE; + notice.z_port = 0; + notice.z_class = WG_CTL_CLASS; + notice.z_class_inst = WG_CTL_USER; + + if (!strcmp(argv[0],"wg_read")) + notice.z_opcode = USER_REREAD; + if (!strcmp(argv[0],"wg_shutdown")) + notice.z_opcode = USER_SHUTDOWN; + if (!strcmp(argv[0],"wg_startup")) + notice.z_opcode = USER_STARTUP; + if (!strcmp(argv[0],"wg_exit")) + notice.z_opcode = USER_EXIT; + if (!notice.z_opcode) { + fprintf(stderr, + "unknown WindowGram client control command %s\n", + argv[0]); + return; + } + notice.z_sender = 0; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_message_len = 0; + + if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) + com_err(whoami, retval, "while sending notice"); + + if ((retval = ZInitialize()) != ZERR_NONE) + com_err(whoami, retval, + "while reinitializing"); +} + +void +hm_control(int argc, + char *argv[]) +{ + int retval; + ZNotice_t notice; + + if (argc > 1) { + fprintf(stderr,"Usage: %s\n",argv[0]); + return; + } + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = HMCTL; + notice.z_port = 0; + notice.z_class = HM_CTL_CLASS; + notice.z_class_inst = HM_CTL_CLIENT; + + if (!strcmp(argv[0],"hm_flush")) + notice.z_opcode = CLIENT_FLUSH; + if (!strcmp(argv[0],"new_server")) + notice.z_opcode = CLIENT_NEW_SERVER; + if (!notice.z_opcode) { + fprintf(stderr, "unknown HostManager control command %s\n", + argv[0]); + return; + } + notice.z_sender = 0; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_message_len = 0; + + if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) + com_err(whoami, retval, "while sending notice"); +} + +void +show_var(int argc, + char *argv[]) +{ + int i; + char *value; + + if (argc < 2) { + fprintf(stderr,"Usage: %s ...\n",argv[0]); + return; + } + + for (i=1;i [value]\n", + argv[0]); + return; + } + + setting_exp = 0; + + if (!strcasecmp(argv[1],"exposure")) { + setting_exp = 1; + if (argc != 3) { + fprintf(stderr,"An exposure setting must be specified.\n"); + return; + } + exp_level = (char *)0; + if (!strcasecmp(argv[2],EXPOSE_NONE)) + exp_level = EXPOSE_NONE; + if (!strcasecmp(argv[2],EXPOSE_OPSTAFF)) + exp_level = EXPOSE_OPSTAFF; + if (!strcasecmp(argv[2],EXPOSE_REALMVIS)) + exp_level = EXPOSE_REALMVIS; + if (!strcasecmp(argv[2],EXPOSE_REALMANN)) + exp_level = EXPOSE_REALMANN; + if (!strcasecmp(argv[2],EXPOSE_NETVIS)) + exp_level = EXPOSE_NETVIS; + if (!strcasecmp(argv[2],EXPOSE_NETANN)) + exp_level = EXPOSE_NETANN; + if (!exp_level) { + fprintf(stderr,"The exposure setting must be one of:\n"); + fprintf(stderr,"%s, %s, %s, %s, %s, %s.\n", + EXPOSE_NONE, + EXPOSE_OPSTAFF, + EXPOSE_REALMVIS, + EXPOSE_REALMANN, + EXPOSE_NETVIS, + EXPOSE_NETANN); + return; + } + } + if (argc == 2) + retval = ZSetVariable(argv[1],""); + else { + (void) strcpy(varcat,argv[2]); + for (i=3;i [ ... ]\n", + argv[0]); + return; + } + + for (i=1;i 4 || argc < 3) { + fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]); + return; + } + + sub.zsub_class = argv[1]; + sub.zsub_classinst = argv[2]; + sub.zsub_recipient = (argc == 3)?ZGetSender():argv[3]; + + fix_macros(&sub,&sub2,1); + + if ((wgport = ZGetWGPort()) == -1) { + com_err(whoami, errno, "while finding WindowGram port"); + return; + } + + retval = (*argv[0] == 's') ? + ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport) : + ZUnsubscribeTo(&sub2,1,(u_short)wgport); + + if (retval != ZERR_NONE) + com_err(whoami, retval, "while subscribing"); +} + +void +sub_file(int argc, + char *argv[]) +{ + ZSubscription_t sub; + short wgport; + + if (argc > 4 || argc < 3) { + fprintf(stderr,"Usage: %s class instance [*]\n",argv[0]); + return; + } + + if (argv[1][0] == '!') { + com_err(whoami, 0, + (!strcmp(argv[0],"add_unsubscription") || + !strcmp(argv[0],"add_un") || + !strcmp(argv[0],"delete_unsubscription") || + !strcmp(argv[0],"del_un")) ? + "Do not use `!' as the first character of a class.\n\tIt is automatically added before modifying the subscription file." : + "Do not use `!' as the first character of a class.\n\tIt is reserved for internal use with un-subscriptions."); + return; + } + sub.zsub_class = argv[1]; + sub.zsub_classinst = argv[2]; + sub.zsub_recipient = (argc == 3)?TOKEN_ME:argv[3]; + + if (make_exist(subsname)) + return; + if ((wgport = ZGetWGPort()) == -1) { + com_err(whoami, errno, "while finding WindowGram port"); + return; + } + + if (!strcmp(argv[0],"add")) + add_file(wgport,&sub,0); + else if (!strcmp(argv[0],"add_unsubscription") || + !strcmp(argv[0],"add_un")) + add_file(wgport,&sub,1); + else if (!strcmp(argv[0],"delete") || + !strcmp(argv[0],"del") || + !strcmp(argv[0],"dl")) + del_file(wgport,&sub,0); + else if (!strcmp(argv[0],"delete_unsubscription") || + !strcmp(argv[0],"del_un")) { + del_file(wgport,&sub,1); + } else + com_err(whoami, 0, "unknown command name"); + return; +} + +void +add_file(short wgport, + ZSubscription_t *subs, + int unsub) +{ + FILE *fp; + ZSubscription_t sub2; + Code_t retval; + + (void) purge_subs(subs,ALL); /* remove copies in the subs file */ + if (!(fp = fopen(subsname,"a"))) { + com_err(whoami, errno, "while opening %s for append", subsname); + return; + } + fprintf(fp,"%s%s,%s,%s\n", + unsub ? "!" : "", + subs->zsub_class, subs->zsub_classinst, subs->zsub_recipient); + if (fclose(fp) == EOF) { + com_err(whoami, errno, "while closing %s", subsname); + return; + } + fix_macros(subs,&sub2,1); + retval = (unsub + ? ZUnsubscribeTo(&sub2,1,(u_short)wgport) + : ZSubscribeToSansDefaults(&sub2,1,(u_short)wgport)); + if (retval) + com_err(whoami, retval, + unsub ? "while unsubscribing" : + "while subscribing"); + return; +} + +void +del_file(short wgport, + register ZSubscription_t *subs, + int unsub) +{ + ZSubscription_t sub2; + int retval; + + retval = purge_subs(subs, unsub ? UNSUBONLY : SUBONLY); + if (retval == ERR) + return; + if (retval == NOT_REMOVED) + fprintf(stderr, + "Couldn't find %sclass %s instance %s recipient %s in\n\tfile %s\n", + unsub ? "un-subscription " : "", + subs->zsub_class, subs->zsub_classinst, + subs->zsub_recipient, subsname); + fix_macros(subs,&sub2,1); + if ((retval = ZUnsubscribeTo(&sub2,1,(u_short)wgport)) != + ZERR_NONE) + com_err(whoami, retval, "while unsubscribing"); + return; +} + +int +purge_subs(register ZSubscription_t *subs, + int which) +{ + FILE *fp,*fpout; + char subline[BUFSIZ]; + char backup[BUFSIZ],ourline[BUFSIZ]; + int delflag = NOT_REMOVED; + int keep = 0; + + switch (which) { + case SUBONLY: + case UNSUBONLY: + case ALL: + break; + default: + com_err(whoami, 0, "internal error in purge_subs"); + return(ERR); + } + + (void) sprintf(ourline,"%s,%s,%s", + subs->zsub_class, + subs->zsub_classinst, + subs->zsub_recipient); + + if (!(fp = fopen(subsname,"r"))) { + com_err(whoami, errno, "while opening %s for read", subsname); + return(ERR); + } + (void) strcpy(backup, subsname); + (void) strcat(backup, ".temp"); + (void) unlink(backup); + if (!(fpout = fopen(backup,"w"))) { + com_err(whoami, errno, "while opening %s for writing", backup); + (void) fclose(fp); + return(ERR); + } + for (;;) { + if (!fgets(subline,sizeof subline,fp)) + break; + if (*subline) + subline[strlen(subline)-1] = '\0'; /* nuke newline */ + switch (which) { + case SUBONLY: + keep = strcmp(subline,ourline); + break; + case UNSUBONLY: + keep = (*subline != '!' || strcmp(subline+1,ourline)); + break; + case ALL: + keep = (strcmp(subline,ourline) && + (*subline != '!' || strcmp(subline+1, + ourline))); + break; + } + if (keep) { + fputs(subline, fpout); + if (ferror(fpout) || (fputc('\n', fpout) == EOF)) { + com_err(whoami, errno, "while writing to %s", + backup); + } + } else + delflag = REMOVED; + } + (void) fclose(fp); /* open read-only, ignore errs */ + if (fclose(fpout) == EOF) { + com_err(whoami, errno, "while closing %s", backup); + return(ERR); + } + if (rename(backup,subsname) == -1) { + com_err(whoami, errno, "while renaming %s to %s\n", + backup, subsname); + return(ERR); + } + return(delflag); +} + +void +load_subs(int argc, + char *argv[]) +{ + ZSubscription_t subs[SUBSATONCE],subs2[SUBSATONCE],unsubs[SUBSATONCE]; +#ifdef CMU_ZCTL_PUNT + ZSubscription_t punts[SUBSATONCE]; + int pind; +#endif + FILE *fp; + int ind,unind,lineno,i,retval,type; + short wgport = 0; + char *comma,*comma2,*file,subline[BUFSIZ]; + + if (argc > 2) { + fprintf(stderr,"Usage: %s [file]\n",argv[0]); + return; + } + + if (*argv[0] == 'u') + type = UNSUB; + else + if (!strcmp(argv[0],"list") || !strcmp(argv[0],"ls")) + type = LIST; + else + type = SUB; + + if (type != LIST) + if ((wgport = ZGetWGPort()) == -1) { + com_err(whoami, errno, + "while finding WindowGram port"); + return; + } + + file = (argc == 1) ? subsname : argv[1]; + + fp = fopen(file,"r"); + + if (fp == NULL) { + com_err(whoami, errno, + "while loading subscription file"); + return; + } + +#ifdef CMU_ZCTL_PUNT + pind = +#endif + ind = unind = 0; + lineno = 1; + + for (;;lineno++) { + if (!fgets(subline,sizeof subline,fp)) + break; + if (*subline == '#' || !*subline) + continue; + subline[strlen(subline)-1] = '\0'; /* nuke newline */ + comma = strchr(subline,','); + if (comma) + comma2 = strchr(comma+1,','); + else + comma2 = 0; + if (!comma || !comma2) { + fprintf(stderr, + "Malformed subscription at line %d of %s:\n%s\n", + lineno,file,subline); + continue; + } + *comma = '\0'; + *comma2 = '\0'; + if (type == LIST) { + if (*subline == '!') + printf("(Un-subscription) Class %s instance %s recipient %s\n", + subline+1, comma+1, comma2+1); +#ifdef CMU_ZCTL_PUNT + else if(*subline == '-') + printf("(Punted) Class %s instance %s recipient %s\n", + subline+1, comma+1, comma2+1); +#endif + else + printf("Class %s instance %s recipient %s\n", + subline, comma+1, comma2+1); + continue; + } + if (*subline == '!') { /* an un-subscription */ + /* if we are explicitly un-subscribing to + the contents of a subscription file, ignore + any un-subscriptions in that file */ + if (type == UNSUB) + continue; + unsubs[unind].zsub_class = + (char *)malloc((unsigned)(strlen(subline))); + /* XXX check malloc return */ + /* skip the leading '!' */ + (void) strcpy(unsubs[unind].zsub_class,subline+1); + unsubs[unind].zsub_classinst = + (char *)malloc((unsigned)(strlen(comma+1)+1)); + /* XXX check malloc return */ + (void) strcpy(unsubs[unind].zsub_classinst,comma+1); + unsubs[unind].zsub_recipient = + (char *)malloc((unsigned)(strlen(comma2+1)+1)); + /* XXX check malloc return */ + (void) strcpy(unsubs[unind].zsub_recipient,comma2+1); + unind++; + } else +#ifdef CMU_ZCTL_PUNT + if (*subline == '-') { /* a punt */ + if (type == UNSUB) + continue; + punts[pind].zsub_class = + (char *)malloc((unsigned)(strlen(subline)+1)); + /* XXX check malloc return */ + (void) strcpy(punts[pind].zsub_class,subline+1); + punts[pind].zsub_classinst = + (char *)malloc((unsigned)(strlen(comma+1)+1)); + /* XXX check malloc return */ + (void) strcpy(punts[pind].zsub_classinst,comma+1); + punts[pind].zsub_recipient = + (char *)malloc((unsigned)(strlen(comma2+1)+1)); + /* XXX check malloc return */ + (void) strcpy(punts[pind].zsub_recipient,comma2+1); + pind++; + } else +#endif + { + subs[ind].zsub_class = + (char *)malloc((unsigned)(strlen(subline)+1)); + /* XXX check malloc return */ + (void) strcpy(subs[ind].zsub_class,subline); + subs[ind].zsub_classinst = + (char *)malloc((unsigned)(strlen(comma+1)+1)); + /* XXX check malloc return */ + (void) strcpy(subs[ind].zsub_classinst,comma+1); + subs[ind].zsub_recipient = + (char *)malloc((unsigned)(strlen(comma2+1)+1)); + /* XXX check malloc return */ + (void) strcpy(subs[ind].zsub_recipient,comma2+1); + ind++; + } +#ifdef CMU_ZCTL_PUNT + if (pind == SUBSATONCE) { + fix_macros(punts,subs2,pind); + if ((retval = ZPunt(subs2,pind,(u_short)wgport) != + ZERR_NONE)) + { + com_err(whoami, retval, + "while punting"); + goto cleanup; + } + for (i=0;i\n", punt ? "Punting" : "Unpunting", + class, inst, *recip ? recip : "*"); + + memset((char *) ¬ice, 0, sizeof(ZNotice_t)); + notice.z_kind = UNSAFE; + notice.z_class = WG_CTL_CLASS; + notice.z_class_inst = WG_CTL_USER; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_opcode = (punt) ? "SUPPRESS" : "UNSUPPRESS"; + notice.z_port = 0; + notice.z_message = msg; + notice.z_message_len = strlen(class)+strlen(inst)+strlen(recip)+3; + + if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) + fprintf(stderr,"%s: while sending notice\n",whoami); + + free(msg); + + ZClosePort(); +#endif + return; +} + +void +list_punts(int argc, char *argv[]) +{ +#ifdef CMU_ZCTL_PUNT + ZNotice_t notice; + int retval; + struct sockaddr_in old, to, from; + u_short ourport, zwgcport; + char *msg; + + ourport=0; + retval = ZOpenPort(&ourport); + if(retval != ZERR_NONE) { + com_err("zctl", retval, "while opening Zephyr port."); + return; + } + + old = ZGetDestAddr(); + to = old; + if ((zwgcport = ZGetWGPort()) == (u_short)-1) { + fprintf(stderr, "zctl: Can't find windowgram port\n"); + return; + } + + to.sin_port = (u_short) zwgcport; + if ((retval = ZSetDestAddr(&to)) != ZERR_NONE) { + com_err("zctl",retval,"while setting destination address"); + return; + } + + memset((char *) ¬ice, 0, sizeof(ZNotice_t)); + notice.z_kind = UNSAFE; + notice.z_class = WG_CTL_CLASS; + notice.z_class_inst = WG_CTL_USER; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_opcode = "LIST-SUPPRESSED" /*USER_LIST_SUPPRESSED*/; + notice.z_port = ourport; + notice.z_message = NULL; + notice.z_message_len = 0; + + if ((retval = ZSendNotice(¬ice,ZNOAUTH)) != ZERR_NONE) + com_err("zctl",retval,"while sending notice"); + + if ((retval = ZReceiveNotice(¬ice,&from)) != ZERR_NONE) + com_err("zctl",retval,"while receiving ack"); + + (void) ZFreeNotice(¬ice); + + if ((retval = ZReceiveNotice(¬ice,&from)) != ZERR_NONE) + com_err("zctl",retval,"while receiving notice"); + + notice.z_auth = ZCheckAuthentication(¬ice, &from); + + if ((retval = ZSetDestAddr(&old)) != ZERR_NONE) { + com_err("zctl",retval,"while resetting destination address"); + return; + } + + msg = (char *) malloc((notice.z_message_len+1) * sizeof(char)); + (void) strncpy(msg,notice.z_message, notice.z_message_len); + msg[notice.z_message_len]=(char)0; + printf("%s", msg); + (void) free(msg); + (void) ZFreeNotice(¬ice); + (void) ZClosePort(); + +#endif /* CMU_ZCTL_PUNT */ + return; +} + +#ifndef HAVE_SS +#define MAXNAMES 3 +static const struct { + void (*fptr)(int, char *[]); + const char *doc; + const char *names[MAXNAMES]; +} commands[] = { +/* { set_file, "Set default subscriptions file.", "file" }, */ + { cancel_subs, "Cancel all subscriptions.", + { "cancel" } }, + { load_subs, "Subscribe to a subscriptions file.", + { "load", "ld" } }, + { load_subs, "Unsubscribe to a subscriptions file.", + { "unload", "unld" } }, + { load_subs, "List a subscriptions file.", + { "list", "ls" } }, + { subscribe, "Subscribe to a class/class instance.", + { "subscribe", "sub" } }, + { subscribe, "Unsubscribe to a class/class instance.", + { "unsubscribe", "unsub" } }, + { sub_file, "Subscribe and add to subscriptions file.", + { "add" } }, + { sub_file, "Unsubscribe and add to subscriptions file\nas un-subscription.", + { "add_unsubscription", "add_un" } }, + { sub_file, "Unsubscribe and delete subscription from\nsubscriptions file.", + { "delete", "del", "dl" } }, + { sub_file, "Delete un-subscription from subscriptions file.", + { "delete_unsubscription", "del_un" } }, + { current, "Retrieve current subscriptions.", + { "retrieve", "ret" } }, + { current, "Retrieve system-wide default subscriptions.", + { "defaults", "defs" } }, + { current, "Save current subscriptions (replacing existing file).", + { "save" } }, + { show_var, "Show a variable's value.", + { "show" } }, + { set_var, "Set a variable's value.", + { "set" } }, + { unset_var, "Delete a variable's value.", + { "unset" } }, + { wgc_control, "Get the WindowGram to reread its description file.", + { "wg_read" } }, + { wgc_control, "Tell the WindowGram not to react to incoming notices.", + { "wg_shutdown" } }, + { wgc_control, "Tell the WindowGram to react to incoming notices.", + { "wg_startup" } }, + { wgc_control, "Tell the WindowGram to exit completely.", + { "wg_exit" } }, + { hm_control, "Tell the server to flush information about this host.", + { "hm_flush" } }, + { hm_control, "Tell the HostManager to find a new server.", + { "new_server" } }, + { flush_locations, "Flush all location information.", + { "flush_locs" } }, + { flush_subscr, "Flush all subscription information.", + { "flush_subs" } }, + { do_hide, "Hide your location.", + { "hide" } }, + { do_hide, "Show (un-hide) your location.", + { "unhide" } }, + { show_commands, "List available commands.", + { "help", "?" } }, +#ifdef CMU_ZCTL_PUNT + { do_punt, "Ignore specified messages.", + { "punt" } }, + { do_punt, "Stop ignoring specified messages.", + { "unpunt" } }, + { list_punts, "List current messages to ignore.", + { "list_punts", "lp" } }, +#endif +}; +#define MAXCOMMAND (sizeof(commands)/sizeof(commands[0])) + +#define DOCCOL 25 + +static void +show_commands(int argc, char *argv[]) +{ + int i, j, col, len; + const char *str, *s; + printf("Available zctl requests:\n\n"); + for (i = 0; i < MAXCOMMAND; i++) { + col = 0; + printf("%s", commands[i].names[0]); + col += strlen(commands[i].names[0]); + for (j = 1; j < MAXNAMES && commands[i].names[j]; j++) { + printf(", %s", commands[i].names[j]); + col += 2 + strlen(commands[i].names[j]); + } + if (col > DOCCOL - 2) { + printf("\n"); + col = 0; + } + printf("%*s", DOCCOL - col, ""); + str = commands[i].doc; + while ((s = strchr(str, '\n')) != NULL) { + printf("%.*s\n%*s", (int)(s-str), str, DOCCOL, ""); + str = s+1; + } + printf("%s\n", str); + } +} + +static void +run_command(int argc, char *argv[]) +{ + int i, j; + for (i = 0; i < MAXCOMMAND; i++) + for (j = 0; j < MAXNAMES; j++) + if (commands[i].names[j] != NULL && + !strcmp(commands[i].names[j], argv[0])) { + commands[i].fptr(argc, argv); + return; + } + com_err(whoami, 0, + "Unknown command '%s'; use '%s help' for a list of commands.", + argv[0], whoami); + exit(1); +} +#endif diff --git a/clients/zctl/zctl_cmds.ct b/clients/zctl/zctl_cmds.ct new file mode 100644 index 0000000..00b799c --- /dev/null +++ b/clients/zctl/zctl_cmds.ct @@ -0,0 +1,101 @@ +# $Id$ +# + command_table zctl_cmds; + + request set_file, "Set default subscriptions file.", + file; + + request cancel_subs, "Cancel all subscriptions.", + cancel; + + request load_subs, "Subscribe to a subscriptions file.", + load, ld; + + request load_subs, "Unsubscribe to a subscriptions file.", + unload, unld; + + request load_subs, "List a subscriptions file.", + list, ls; + + request subscribe, "Subscribe to a class/class instance.", + subscribe, sub; + + request subscribe, "Unsubscribe to a class/class instance.", + unsubscribe, unsub; + + request sub_file, "Subscribe and add to subscriptions file.", + add; + + request sub_file, "Unsubscribe and add to subscriptions file\n as un-subscription.", + add_unsubscription, add_un; + + request sub_file, "Unsubscribe and delete subscription from\n subscriptions file.", + delete, del, dl; + request sub_file, "Delete un-subscription from subscriptions file.", + delete_unsubscription, del_un; + + request current, "Retrieve current subscriptions.", + retrieve, ret; + + request current, "Retrieve system-wide default subscriptions.", + defaults, defs; + + request current, "Save current subscriptions (replacing existing file).", + save; + + request show_var, "Show a variable's value.", + show; + + request set_var, "Set a variable's value.", + set; + + request unset_var, "Delete a variable's value.", + unset; + + request wgc_control, "Get the WindowGram to reread its description file.", + wg_read; + + request wgc_control, "Tell the WindowGram not to react to incoming notices.", + wg_shutdown; + + request wgc_control, "Tell the WindowGram to react to incoming notices.", + wg_startup; + + request wgc_control, "Tell the WindowGram to exit completely.", + wg_exit; + + request hm_control, "Tell the server to flush information about this host.", + hm_flush; + + request hm_control, "Tell the HostManager to find a new server.", + new_server; + + request flush_locations, "Flush all location information.", + flush_locs; + + request flush_subscr, "Flush all subscription information.", + flush_subs; + + request do_hide, "Hide your location.", + hide; + + request do_hide, "Show (un-hide) your location.", + unhide; + + request ss_list_requests, "List available commands.", + list_requests, lr, "?"; + + request ss_quit, "Quit.", + quit, exit, q; +#ifdef CMU_ZCTL_PUNT + request do_punt, "Ignore specified messages.", + punt; + + request do_punt, "Stop ignoring specified messages.", + unpunt; + + request list_punts, "List current messages to ignore.", + list_punts, lp; + +#endif + end; diff --git a/clients/zleave/Makefile.in b/clients/zleave/Makefile.in new file mode 100644 index 0000000..8892b5e --- /dev/null +++ b/clients/zleave/Makefile.in @@ -0,0 +1,56 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=../.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err + +OBJS= zleave.o + +all: zleave + +zleave: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: zleave + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zleave ${DESTDIR}${bindir} + ${INSTALL} -m 644 ${srcdir}/zleave.1 ${DESTDIR}${mandir}/man1 + +clean: + ${LIBTOOL} --mode=clean rm -f zleave + rm -f ${OBJS} + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/zleave/zleave.1 b/clients/zleave/zleave.1 new file mode 100644 index 0000000..0458e04 --- /dev/null +++ b/clients/zleave/zleave.1 @@ -0,0 +1,107 @@ +.\" $Id$ +.\" +.\" Copyright (c) 1980 Regents of the University of California. +.\" All rights reserved. The Berkeley software License Agreement +.\" specifies the terms and conditions for redistribution. +.\" +.\" +.TH ZLEAVE 1 "July 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zleave \- notify you via Zephyr when you have to leave +.SH SYNOPSIS +.B zleave +[ +.RI [+] hhmm +[ +.I -m "Reminder Message" +] ] +.br +.B zleave +.I can\fR[\fIcel\fR] +.SH DESCRIPTION +.I Zleave +waits until the specified time, then reminds you that you +have to leave, using the \fIZephyr(1)\fR Notification Service. +You are reminded 5 minutes and 1 minute before the actual +time, at the time, and every minute thereafter. +When you log off, +.I zleave +exits just before it would have sent the next message. +.PP +The time of day is in the form hhmm where hh is a time in +hours (on a 12 or 24 hour clock). +All times are converted to a 12 hour clock, and assumed to +be in the next 12 hours. +.PP +If the time is preceded by `+', the alarm will go off in hours and minutes +from the current time. +.PP +If no argument is given, +.I zleave +prompts with "When do you +have to leave?". A reply of newline causes +.I zleave +to exit, +otherwise the reply is assumed to be a time. +This form is suitable for inclusion in a +.I .login +or +.I .profile. +.PP +The +.I cancel +option cancels the currently running \fIzleave\fR. If another +.I zleave +is running, it is automatically killed when a new time to leave is +set. The process id is stored in the file /tmp/zleave.\fIuid\fR, where +\fIuid\fR is the user's UNIX uid. +.PP +If the +.I -m +argument is specified, the next argument +is appended to the standard message +(a sentence describing how much time remains until the appointed hour) +sent at appropriate times. +If you want to append a multiple-word message, you normally must quote it with +double quotes (") (This is necessary for users of +.IR csh (1) +and +.IR sh (1).) +.PP +.I Zleave +automatically subscribes you to Zephyr class "MESSAGE", +instance "LEAVE". You do not have to add anything to your +default subscriptions file (see +.IR zctl (1)). +The reminder message is displayed by the WindowGram client (usually +.IR zwgc (1)). +.PP +If Zephyr is unavailable, +.I zleave +acts essentially like +.IR leave (1). +.PP +Zleave ignores SIGINT, SIGQUIT, and SIGTERM. +To get rid of it you should either log off or use the +.I cancel +option. +.SH FILES +/tmp/zleave.\fIuid\fR +/tmp/wg.* +.SH SEE ALSO +calendar(1), zephyr(1), leave(1), zwgc(1), zctl(1), csh(1), sh(1) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH RESTRICTIONS +Copyright (c) 1980, Regents of the University of California. +All rights reserved. +Redistribution and use in source and binary forms are permitted +provided that this notice is preserved and that due credit is given +to the University of California at Berkeley. The name of the University +may not be used to endorse or promote products derived from this +software without specific written prior permission. This software +is provided ``as is'' without express or implied warranty. +.sp +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. diff --git a/clients/zleave/zleave.c b/clients/zleave/zleave.c new file mode 100644 index 0000000..7cb92ed --- /dev/null +++ b/clients/zleave/zleave.c @@ -0,0 +1,424 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for the "zleave" command. + * + * Created by: David Jedlinsky + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include + +#ifndef lint +static const char rcsid_zlocate_c[] = "$Id$"; +#endif /* lint */ + +/* + * Copyright (c) 1980 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that this notice is preserved and that due credit is given + * to the University of California at Berkeley. The name of the University + * may not be used to endorse or promote products derived from this + * software without specific written prior permission. This software + * is provided ``as is'' without express or implied warranty. + */ + +#ifndef lint +char copyright[] = +"@(#) Copyright (c) 1980 Regents of the University of California.\n\ + All rights reserved.\n"; +#endif /* not lint */ + +#define MESSAGE_CLASS "MESSAGE" +#define INSTANCE "LEAVE" +/* + * zleave [[+]hhmm [ -m "Reminder Message" ]] + * or + * zleave can[cel] + * + * Reminds you when you have to leave. + * Leave prompts for input and goes away if you hit return. + * Messages are sent through Zephyr. Subscriptions are handled automagically. + * It nags you like a mother hen. + */ +char origlogin[20]; +char tempfile[40]; +char *whenleave; +char *reminder_message = NULL; +char buff[100]; +int use_zephyr=1, oldpid; + +void usage(void); +void doalarm(long); +void bother(long, char *); +void delay(long); +int gethm(char *, int *, int*); + +int +main(int argc, + char **argv) +{ + time_t now; + long when, diff; + int hours, minutes; + char *cp; + FILE *fp; + struct tm *nv; + int port, c; + ZSubscription_t sub; + + if (ZInitialize() != ZERR_NONE) { + fprintf(stderr,"No Zephyr! Will write directly to terminal.\n"); + use_zephyr = 0; + } + (void) sprintf(tempfile, "/tmp/zleave.%d", (int) getuid()); + + if (use_zephyr) { + if ((port = ZGetWGPort()) == -1) { + fprintf(stderr, + "Can't find WindowGram subscription port.\n"); + fprintf(stderr,"Will write directly to terminal.\n"); + use_zephyr = 0; + } else { + sub.zsub_class = MESSAGE_CLASS; + sub.zsub_classinst = INSTANCE; + sub.zsub_recipient = ZGetSender(); + if (ZSubscribeToSansDefaults(&sub,1,(u_short)port) + != ZERR_NONE) { + fprintf(stderr, + "Subscription error! Writing to your terminal...\n"); + use_zephyr = 0; + } + } + } + if (!use_zephyr) { + if ((cp = getlogin()) == NULL) { + fputs("leave: You are not logged in.\n", stderr); + exit(1); + } + (void) strcpy(origlogin, cp); + } + + c = 1; + while ((c 59) + usage(); + diff = 60*hours+minutes; + doalarm(diff); + exit(0); + } + if (!strcmp(cp, "cancel") || !strcmp(cp, "can")) { + if (!(fp = fopen(tempfile,"r"))) { + printf("No zleave is currently running.\n"); + exit(0); + } + if (fscanf(fp, "%d", &oldpid) != 1) { + printf("The zleave pid file is corrupted.\n"); + (void) fclose(fp); + exit(0); + } + (void) fclose(fp); + if (kill(oldpid,9)) + printf("No zleave is currently running.\n"); + (void) unlink(tempfile); + exit(0); + } + if (!gethm(cp, &hours, &minutes)) + usage(); + if (hours > 12) + hours -= 12; + if (hours == 12) + hours = 0; + + if (hours < 0 || hours > 12 || minutes < 0 || minutes > 59) + usage(); + + (void) time(&now); + nv = localtime(&now); + when = 60*hours+minutes; + if (nv->tm_hour > 12) + nv->tm_hour -= 12; /* do am/pm bit */ + now = 60 * nv->tm_hour + nv->tm_min; + diff = when - now; + while (diff < 0) + diff += 12*60; + if (diff > 11*60) { + fprintf(stderr, "That time has already passed!\n"); + exit(1); + } + + doalarm(diff); + exit(0); +} + +void +usage(void) +{ + fprintf(stderr, "usage: zleave [[+]hhmm [-m \"Reminder Message\"]]\n\ +\tor: zleave can[cel]\n"); + exit(1); +} + +int +gethm(char *cp, + int *hp, + int *mp) +{ + char c; + int tod; + + tod = 0; + while ((c = *cp++) != '\0') { + if (!isdigit(c)) + return(0); + tod = tod * 10 + (c - '0'); + } + *hp = tod / 100; + *mp = tod % 100; + return(1); +} + +void +doalarm(long nmins) +{ + time_t daytime; + char *msg1, *msg2, *msg3, *msg4; + register int i; + long slp1, slp2, slp3, slp4; + long seconds, gseconds; + FILE *fp; +#ifdef _POSIX_VERSION + struct sigaction sa; +#endif + + seconds = 60 * nmins; + if (seconds <= 0) + seconds = 1; + gseconds = seconds; + + msg1 = "You have to leave in 5 minutes"; + if (seconds <= 60*5) { + slp1 = 0; + } else { + slp1 = seconds - 60*5; + seconds = 60*5; + } + + msg2 = "Just one more minute!"; + if (seconds <= 60) { + slp2 = 0; + } else { + slp2 = seconds - 60; + seconds = 60; + } + + msg3 = "Time to leave!"; + slp3 = seconds; + + msg4 = "You're going to be late!"; + slp4 = 60L; + + (void) time(&daytime); + daytime += gseconds; + whenleave = ctime(&daytime); + + fp = fopen(tempfile,"r"); + if (fp) { + if (fscanf(fp, "%d", &oldpid) == 1) + if (!kill(oldpid,9)) + printf("Old zleave process killed.\n"); + (void) fclose(fp); + } + printf("Alarm set for %s", whenleave); + +/* Subscribe to MESSAGE.LEAVE here */ + + switch(fork()) { + case -1: + perror("fork"); + exit(-1); + break; + case 0: + break; + default: + exit(0); + break; + } + if (!(fp = fopen(tempfile, "w"))) + fprintf(stderr, "Cannot open pid file.\n"); + else { + fprintf(fp, "%d\n", getpid()); + if (fclose(fp) == EOF) + (void) perror("fclose on pid file"); + } + +#ifdef _POSIX_VERSION + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &sa, (struct sigaction *)0); + sigaction(SIGQUIT, &sa, (struct sigaction *)0); + sigaction(SIGTERM, &sa, (struct sigaction *)0); + sigaction(SIGTTOU, &sa, (struct sigaction *)0); +#else + (void) signal(SIGINT, SIG_IGN); + (void) signal(SIGQUIT, SIG_IGN); + (void) signal(SIGTERM, SIG_IGN); + (void) signal(SIGTTOU, SIG_IGN); +#endif + + if (slp1) + bother(slp1, msg1); + if (slp2) + bother(slp2, msg2); + bother(slp3, msg3); + for (i = 0; i < 10; i++) + bother(slp4, msg4); + + bother(0L, "That was the last time I'll tell you. Bye."); + (void) unlink(tempfile); + exit(0); +} + +void +bother(long slp, + char *msg) +{ + ZNotice_t notice; + ZNotice_t retnotice; + int retval; + char *real_message; + + delay(slp); + + if (use_zephyr) { + real_message = (char *) malloc(strlen(msg) + + strlen(reminder_message) + 3); + if (real_message == NULL) { + fprintf (stderr, "zleave: out of memory\n"); + exit (1); + } + sprintf(real_message,"%c%s\n%s",'\0',msg,reminder_message); + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = ACKED; + notice.z_port = 0; + notice.z_charset = ZCHARSET_UNKNOWN; + notice.z_class = MESSAGE_CLASS; + notice.z_class_inst = INSTANCE; + notice.z_recipient = ZGetSender(); + notice.z_opcode = ""; + notice.z_sender = (char *) 0; + notice.z_default_format = "\n$2"; + notice.z_message = real_message; + /* +3: initial null, newline, final null */ + notice.z_message_len = strlen(msg)+strlen(reminder_message)+3; + + if (ZSendNotice(¬ice, ZAUTH) != ZERR_NONE) { + printf("\7\7\7%s\n%s", msg, reminder_message); + use_zephyr = 0; + } else + if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *) 0, + ZCompareUIDPred, + (char *)¬ice.z_uid)) != ZERR_NONE) { + fprintf(stderr, + "zleave: %s while waiting for acknowledgement\n", + error_message(retval)); + use_zephyr = 0; + } else + if (retnotice.z_kind == SERVNAK) { + fprintf(stderr, + "zleave: authorization failure while sending\n"); + use_zephyr = 0; + } else + if (retnotice.z_kind != SERVACK || !retnotice.z_message_len) { + fprintf(stderr, "zleave: Detected server failure while receiving acknowledgement\n"); + use_zephyr = 0; + } else + if (strcmp(retnotice.z_message, ZSRVACK_SENT)) { + /* it wasn't sent */ + exit(0); + } + if (!use_zephyr) + exit(1); + ZFreeNotice(&retnotice); + free(real_message); + } else +#ifdef __STDC__ + printf("\a\a\a%s\n%s", msg, reminder_message); +#else + printf("\7\7\7%s\n%s", msg, reminder_message); +#endif +} + +/* + * delay is like sleep but does it in 100 sec pieces and + * knows what zero means. + */ +void +delay(long secs) +{ + long n; + register char *l; + + while (secs > 0) { + n = 100; + if (secs < n) + n = secs; + secs -= n; + if (n > 0) + sleep((unsigned) n); + if (!use_zephyr) { + l = getlogin(); + if (l == NULL) + exit(0); + if (strcmp(origlogin, l) != 0) + exit(0); + } + } +} + +#ifndef HAVE_GETLOGIN +char *getlogin() { +#include + + static struct utmp ubuf; + int ufd; + + ufd = open("/etc/utmp",0); + seek(ufd, ttyn(0)*sizeof(ubuf), 0); + read(ufd, &ubuf, sizeof(ubuf)); + ubuf.ut_name[sizeof(ubuf.ut_name)] = 0; + return(&ubuf.ut_name); +} +#endif diff --git a/clients/zlocate/Makefile.in b/clients/zlocate/Makefile.in new file mode 100644 index 0000000..42efe52 --- /dev/null +++ b/clients/zlocate/Makefile.in @@ -0,0 +1,56 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=../.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err + +OBJS= zlocate.o + +all: zlocate + +zlocate: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: zlocate + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zlocate ${DESTDIR}${bindir} + ${INSTALL} -m 644 ${srcdir}/zlocate.1 ${DESTDIR}${mandir}/man1 + +clean: + ${LIBTOOL} --mode=clean rm -f zlocate + rm -f ${OBJS} + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/zlocate/zlocate.1 b/clients/zlocate/zlocate.1 new file mode 100644 index 0000000..0381966 --- /dev/null +++ b/clients/zlocate/zlocate.1 @@ -0,0 +1,76 @@ +.\" $Id$ +.\" +.\" Copyright 1987,1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" +.TH ZLOCATE 1 "April 17, 1990" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zlocate \- find a user using Zephyr +.SH SYNOPSIS +.B zlocate +[ +.B -a +| +.B -d +] [ +.B -1 +] [ +.B -p +] user ... +.SH DESCRIPTION +.I Zlocate +uses the +.I Zephyr(1) +Notification Service to find where a user is currently logged in. If +the user is not logged in, or has set his location information such that +you do not have access to see it, +.I zlocate +prints "Hidden or not logged-in". Otherwise, each machine that the +user is currently logged into is printed, along with the time of +login and location. The location is usually the X window system display +name of the user's display, but may be the terminal name if he is not +using X or for some other reason is only using the terminal interface to +.I zwgc(1). + +By default, all zlocate requests are authenticated using +.IR Kerberos . +If you do not have Kerberos tickets, or for some other reason do not +want to authenticate, the +.B -d +option will turn off authentication. The +.B -a +option is the default, authentication on. + +When locating multiple users, +.I zlocate +will display the user name on a line by itself, followed by the locations for that user. To display the user name on the same line as the output, use the +.B -1 +option (the numeral one). + +To look up multiple users in parallel asynchronously, use the +.B -p +option. + +.SH DIAGNOSTICS +.I zlocate +exits with status zero (0) if at least one user was found, and one (1) +if no users were found. +.SH SEE ALSO +zctl(1), zephyr(1), znol(1), zwgc(1), zhm(8), zephyrd(8), X(1) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH AUTHORS +.PP +Robert S. French (MIT-Project Athena) +.br +Marc Horowitz (MIT-Project Athena) +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/zlocate/zlocate.c b/clients/zlocate/zlocate.c new file mode 100644 index 0000000..0ade6a0 --- /dev/null +++ b/clients/zlocate/zlocate.c @@ -0,0 +1,182 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for the "zlocate" command. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include + +#if !defined(lint) && !defined(SABER) +static const char rcsid_zlocate_c[] = "$Id$"; +#endif + +int numusers=0, numleft=0, parallel=0, oneline=0; +char *whoami; + +static RETSIGTYPE +timeout(int sig) +{ + fprintf (stderr, "%s: no response from server\n", whoami); + exit(1); +} + +static void +usage(void) +{ + printf("Usage: %s [ -a | -d ] [ -p ] [ -1 ] user ... \n",whoami); + exit(1); +} + +static void +print_locs(char *user, + int nlocs) +{ + int one = 1, retval; + ZLocations_t locations; + + if ((!oneline) && (numusers>1)) + printf("\t%s:\n",user); + + if ((!oneline) && (nlocs == 0)) + printf("Hidden or not logged-in\n"); + + for (;nlocs;nlocs--) { + if ((retval = ZGetLocations(&locations,&one)) != ZERR_NONE) { + com_err(whoami,retval,"while getting location"); + exit(1); + } + + if (oneline) { + printf("%s:\t%s\t%s\t%s\n",user,locations.host,locations.tty, + locations.time); + } else { + printf("%-42s %-7s %s\n",locations.host, locations.tty, locations.time); + } + } + + if ((!oneline) && (numusers > 1) && (numleft > 0)) + printf("\n"); +} + +/*ARGSUSED*/ +int +main(int argc, + char *argv[]) +{ + char user[BUFSIZ],*whichuser; + ZAsyncLocateData_t ald; + int retval,i,numlocs,numfound,loc,auth,rlen; + ZNotice_t notice; +#ifdef _POSIX_VERSION + struct sigaction sa; +#endif + + whoami = argv[0]; + auth = -1; + + argv++; + argc--; + + for (i=0; i < argc; i++) + if (argv[i][0] == '-') + switch (argv[i][1]) { + case 'a': + if (auth != -1) usage(); + auth = 1; + break; + case 'd': + if (auth != -1) usage(); + auth = 0; + break; + case 'p': + parallel = 1; + break; + case '1': + oneline = 1; + break; + default: + usage(); + break; + } + else + numusers++; + + if (numusers == 0) + usage(); + + if (auth == -1) auth = 1; + + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err(whoami,retval,"while initializing"); + exit(1); + } + + numleft = numusers; + numfound = 0; + rlen = strlen(ZGetRealm()); + + i = 0; + for (loc = 0; loc < argc; loc++) { + if (argv[loc][0] == '-') continue; + + (void) strncpy(user,argv[loc],sizeof(user) - rlen - 2); + user[sizeof(user) - rlen - 2] = '\0'; + if (!strchr(user,'@')) { + (void) strcat(user,"@"); + (void) strcat(user,ZGetRealm()); + } + if (parallel) { + if ((retval = ZRequestLocations(user, &ald, i ? UNSAFE : UNACKED, + auth?ZAUTH:ZNOAUTH)) != ZERR_NONE) { + com_err(whoami,retval,"requesting location of %s",user); + exit(1); + } + i = 1; + } else { + if ((retval = ZLocateUser(user,&numlocs,auth?ZAUTH:ZNOAUTH)) != ZERR_NONE) { + com_err(whoami,retval,"while locating user %s",user); + exit(1); + } + print_locs(user,numlocs); + numfound += numlocs; + } + } + + if (parallel) { +#ifdef _POSIX_VERSION + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = timeout; + sigaction(SIGALRM, &sa, (struct sigaction *)0); +#else + signal (SIGALRM, timeout); +#endif + while (numleft-- > 0) { + alarm(SRV_TIMEOUT); + if ((retval = ZReceiveNotice(¬ice, NULL)) != ZERR_NONE) { + com_err(whoami,retval,"while searching notice queue"); + continue; + } + if ((retval = ZParseLocations(¬ice, (ZAsyncLocateData_t *)NULL, + &numlocs, &whichuser)) != ZERR_NONE) { + com_err(whoami,retval,"while parsing locations"); + continue; + } + if (numlocs >= 0) { + print_locs(whichuser,numlocs); + free(whichuser); + numfound += numlocs; + } + ZFreeNotice(¬ice); + } + } + return((numfound > 0) ? 0 : 1); +} diff --git a/clients/znol/Makefile.in b/clients/znol/Makefile.in new file mode 100644 index 0000000..8cf6851 --- /dev/null +++ b/clients/znol/Makefile.in @@ -0,0 +1,56 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=../.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err + +OBJS= znol.o + +all: znol + +znol: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: znol + ${LIBTOOL} --mode=install ${INSTALL} -m 755 znol ${DESTDIR}${bindir} + ${INSTALL} -m 644 ${srcdir}/znol.1 ${DESTDIR}${mandir}/man1 + +clean: + ${LIBTOOL} --mode=clean rm -f znol + rm -f ${OBJS} + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/znol/znol.1 b/clients/znol/znol.1 new file mode 100644 index 0000000..cbd6cbd --- /dev/null +++ b/clients/znol/znol.1 @@ -0,0 +1,109 @@ +.\" $Id$ +.\" +.\" Copyright 1987,1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" @(#)znol.1 6.1 (MIT) 7/9/87 +.\" +.TH ZNOL 1 "July 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +znol \- notify via Zephyr upon login or logout of interesting people +.SH SYNOPSIS +.B znol +[ +.BI on|off +] [ +.BI \-f \ file +] [ +.BI \-u \ username +] [ +.BI \-l +] [ +.BI \-q +] +.SH DESCRIPTION +.I Znol +provides a way for you to be notified when "interesting" people log in +or out. It uses the +.I Zephyr(1) +Notification Service, which causes a message to appear on your screen +for every person specified in a namelist (which defaults to +$HOME/.anyone). The namelist should have one login name per line. Any +line starting with `#' is considered a comment and ignored. +Anyone in the namelist who is logged in when +.I znol +is executed is printed to stdout. The control arguments are as +follows: +.TP 12 +.B on|off +Turns notification on or off. +.TP +.B \-f +The namelist file is taken to be +.I file. +If +.I file +is "-", then the standard input is used instead of a file. If +.I file +does not exist, an error message is printed, and +.I znol +exits. +This option may not be used in conjunction with the +.B \-u +option. +.TP +.B \-l +Causes +.I znol +to just list the people in the namelist who are currently logged in, +without subscribing to the login messages. This option may not be used +in conjunction with the +.BI \-q +option. +.TP +.B \-q +Disables printing who is currently logged in when subscribing. This +option may not be used in conjunction with the +.BI \-l +option. +.TP +.B \-u +Instead of reading a file to specify the "interesting" users, the next +argument is used as the only "interesting" user. This option may not be +used in conjunction with the +.B \-f +option. +.SH EXAMPLES +.nf +.in +.5in +znol +.in -.5in +.fi +reads the standard namelist file, prints the locations of any users +named therein which can be found on the system, and enters subscriptions +for notices about those users. +.nf +.in +.5in +znol \-l \-u foo +.in -.5in +.fi +prints the location (if visible) of the user 'foo'. +.SH FILES +$HOME/.anyone +.SH SEE ALSO +anyone(SIPB), nol(SIPB), zctl(1), zephyr(1), zwgc(1), zhm(8), zephyrd(8) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH AUTHOR +.PP +Robert S. French (MIT-Project Athena) +.sp +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/znol/znol.c b/clients/znol/znol.c new file mode 100644 index 0000000..4d03914 --- /dev/null +++ b/clients/znol/znol.c @@ -0,0 +1,256 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for the "znol" command. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include + +#include + +#ifndef lint +static const char rcsid_znol_c[] = "$Id$"; +#endif + +#define SUBSATONCE 7 +#define ON 1 +#define OFF 0 + +int +main(int argc, char *argv[]) +{ + register char *cp; + char *realm; + ZSubscription_t subs[SUBSATONCE]; + ZLocations_t locations; + FILE *fp = NULL; + struct passwd *pwd; + char anyonename[BUFSIZ],name[BUFSIZ],cleanname[BUFSIZ],*envptr; + char *comment_ptr; + int onoff = ON,quiet = 0,justlist = 0,useronly = 0, filenamed = 0; + int retval,arg,ind,one,numlocs,i; + int wgport = 0; + + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err(argv[0],retval,"initializing"); + exit (1); + } + + for (arg=1;argpw_dir); + } + (void) strcat(anyonename,"/.anyone"); + } + + /* if the filename is "-", read stdin */ + if (strcmp(anyonename,"-") == 0) { + fp = stdin; + } else if (!(fp = fopen(anyonename,"r"))) { + fprintf(stderr,"Can't open %s for input\n",anyonename); + exit (1); + } + } + + ind = 0; + + for (;;) { + if (!useronly) { + if (!fgets(cleanname,sizeof cleanname,fp)) + break; + if (cleanname[0] == '#' || cleanname[0] == '\0' || + cleanname[0] == '\n') + continue; /* ignore comment and empty lines */ + comment_ptr = strchr(cleanname, '#'); + if (comment_ptr) + *comment_ptr = '\0'; /* Ignore from # onwards */ + /* Get rid of old-style nol entries, just in case */ + cp = cleanname + strlen(cleanname) - 1; + *cp = '\0'; + while(*--cp == ' ') + *cp = '\0'; + if (*cleanname == '@' || !*cleanname) + continue; + } else if (ind) + break; /* only do the one name */ + + subs[ind].zsub_class = LOGIN_CLASS; + (void) strcpy(name,cleanname); + if (!strchr(name,'@')) { + cp = name + strlen(name); + *cp++ = '@'; + (void) strcpy(cp,ZGetRealm()); + } + cp = strchr(name,'@'); + if (cp[0] && strcmp(cp+1,ZGetRealm())) { + realm = cp + 1; + *cp = '\0'; + if ((subs[ind].zsub_classinst = + malloc((unsigned)(strlen(name) + strlen(realm) + 2))) + == NULL) + { + fprintf (stderr, "znol: out of memory"); + exit (1); + } + (void) sprintf(subs[ind].zsub_classinst, "%s@%s", name, + realm); + (void) strcpy(name, subs[ind].zsub_classinst); + if ((subs[ind].zsub_recipient = + malloc((unsigned)(strlen(realm)+2))) == NULL) { + fprintf (stderr, "znol: out of memory"); + exit (1); + } + (void) sprintf(subs[ind++].zsub_recipient, "@%s", realm); + } else { + if ((subs[ind].zsub_classinst = + malloc((unsigned)(strlen(name)+1))) == NULL) + { + fprintf (stderr, "znol: out of memory"); + exit (1); + } + (void) strcpy(subs[ind].zsub_classinst, name); + subs[ind++].zsub_recipient = ""; + } + + if (!quiet && onoff == ON) { + if ((retval = ZLocateUser(name,&numlocs,ZAUTH)) + != ZERR_NONE) { + com_err(argv[0],retval,"locating user"); + exit(1); + } + one = 1; + if (numlocs) { + for (i=0;i, +recipient "*", where is the official hostname of the sending host. +.PP +Any users who are using resources on the sending host are expected to +subscribe to these messages so they will be warned of any impending +shutdowns. +.PP +.I zshutdown_notify +is usually invoked from within +.I /etc/shutdown. +.SH SEE ALSO +attach(1), zephyr(1), zwgc(1), shutdown(8), zhm(8), zephyrd(8) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH AUTHOR +.PP +C. Anthony Della Fera (Digital Equipment Corporation-Project Athena) +.sp +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/zshutdown_notify/zshutdown_notify.c b/clients/zshutdown_notify/zshutdown_notify.c new file mode 100644 index 0000000..2f51cc0 --- /dev/null +++ b/clients/zshutdown_notify/zshutdown_notify.c @@ -0,0 +1,143 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for "zshutdown_notify", a utility called by + * shutdown(8) to do Zephyr notification on shutdown. + * + * Created by: C. Anthony Della Fera + * + * $Id$ + * + * Copyright (c) 1987, 1993 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include + +#include +#include +#include + +#ifndef lint +static const char rcsid_zshutdown_notify_c[] = + "$Id$"; +#endif + +#define N_KIND UNSAFE +#define N_CLASS "FILSRV" +#define N_OPCODE "SHUTDOWN" +#define N_DEF_FORMAT "From $sender:\n@bold(Shutdown message from $1 at $time)\n@center(System going down, message is:)\n\n$2\n\n@center(@bold($3))" +#define N_FIELD_CNT 3 + +#ifdef HAVE_KRB4 +#define SVC_NAME "rcmd" +#endif + +/* + * Standard warning strings appended as extra fields to + * the message body. + */ + +static char warning[] = "Please detach any filesystems you may have\nattached from this host by typing detach -host %s"; + +/*ARGSUSED*/ +int +main(int argc, + char *argv[]) +{ + ZNotice_t notice; + struct hostent *hp; + int retval; + char hostname[NS_MAXDNAME]; + char msgbuff[BUFSIZ], message[Z_MAXPKTLEN], *ptr; + char scratch[BUFSIZ]; + char *msg[N_FIELD_CNT]; +#ifdef HAVE_KRB4 + char tkt_filename[MAXPATHLEN]; + char rlm[REALM_SZ]; + char hn2[NS_MAXDNAME]; + char *cp; +#endif + + if (gethostname(hostname, sizeof(hostname)) < 0) { + com_err(argv[0], errno, "while finding hostname"); + exit(1); + } + + if ((hp = gethostbyname(hostname)) != NULL) + (void) strcpy(hostname, hp->h_name); + + msg[0] = hostname; + msg[1] = message; + sprintf(scratch, warning, hostname); + msg[2] = scratch; + +#ifdef HAVE_KRB4 + (void) sprintf(tkt_filename, "/tmp/tkt_zshut_%d", getpid()); + krb_set_tkt_string(tkt_filename); + + cp = krb_get_phost(hostname); + if (cp) + (void) strcpy(hn2, cp); + else { + fprintf(stderr, "%s: can't figure out canonical hostname\n",argv[0]); + exit(1); + } + retval = krb_get_lrealm(rlm, 1); + if (retval) { + fprintf(stderr, "%s: can't get local realm: %s\n", + argv[0], krb_get_err_text(retval)); + exit(1); + } + retval = krb_get_svc_in_tkt(SVC_NAME, hn2, rlm, + SERVER_SERVICE, SERVER_INSTANCE, 1, + (char *)KEYFILE); + if (retval) { + fprintf(stderr, "%s: can't get tickets: %s\n", + argv[0], krb_get_err_text(retval)); + exit(1); + } +#endif + + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err(argv[0], retval, "while initializing"); + exit(1); + } + + ptr = message; + + for (;;) { + if (!fgets(msgbuff, sizeof(msgbuff), stdin)) + break; + if ((strlen(msgbuff) + (ptr - message)) > Z_MAXPKTLEN){ + break; + } + (void) strcpy(ptr, msgbuff); + ptr += strlen(ptr); + } + + (void) memset((char *)¬ice, 0, sizeof(notice)); + + notice.z_kind = N_KIND; + notice.z_port = 0; + notice.z_charset = ZCHARSET_UNKNOWN; + notice.z_class = N_CLASS; + notice.z_class_inst = hostname; + notice.z_opcode = N_OPCODE; + notice.z_sender = 0; + notice.z_message_len = 0; + notice.z_recipient = ""; + notice.z_default_format = N_DEF_FORMAT; + + retval = ZSendList(¬ice, msg, N_FIELD_CNT, ZAUTH); +#ifdef HAVE_KRB4 + (void) dest_tkt(); +#endif + + if (retval != ZERR_NONE) { + com_err(argv[0], retval, "while sending notice"); + exit(1); + } + return 0; +} diff --git a/clients/zstat/Makefile.in b/clients/zstat/Makefile.in new file mode 100644 index 0000000..a7d9e70 --- /dev/null +++ b/clients/zstat/Makefile.in @@ -0,0 +1,56 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=../.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err + +OBJS= zstat.o + +all: zstat + +zstat: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: zstat + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zstat ${DESTDIR}${bindir} + ${INSTALL} -m 644 ${srcdir}/zstat.8 ${DESTDIR}${mandir}/man8 + +clean: + ${LIBTOOL} --mode=clean rm -f zstat + rm -f ${OBJS} + +${OBJS}: zserver.h ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/zstat/zserver.h b/clients/zstat/zserver.h new file mode 100644 index 0000000..91e6026 --- /dev/null +++ b/clients/zstat/zserver.h @@ -0,0 +1,26 @@ +#ifndef __ZSERVER_H__ +#define __ZSERVER_H__ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains declarations for use in the server. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#define ADMIN_HELLO "HELLO" /* Opcode: hello, are you there */ +#define ADMIN_IMHERE "IHEARDYOU" /* Opcode: yes, I am here */ +#define ADMIN_SHUTDOWN "GOODBYE" /* Opcode: I am shutting down */ +#define ADMIN_BDUMP "DUMP_AVAIL" /* Opcode: I will give you a dump */ +#define ADMIN_DONE "DUMP_DONE" /* Opcode: brain dump for this server + is complete */ +#define ADMIN_NEWCLT "NEXT_CLIENT" /* Opcode: this is a new client */ +#define ADMIN_LOST_CLT "LOST_CLIENT" /* Opcode: client not ack'ing */ +#define ADMIN_KILL_CLT "KILL_CLIENT" /* Opcode: client is dead, remove */ +#define ADMIN_STATUS "STATUS" /* Opcode: please send status */ + +#endif /* !__ZSERVER_H__ */ diff --git a/clients/zstat/zstat.8 b/clients/zstat/zstat.8 new file mode 100644 index 0000000..e3cfbce --- /dev/null +++ b/clients/zstat/zstat.8 @@ -0,0 +1,51 @@ +.\" $Id$ +.\" +.\" Copyright 1987,1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" +.TH ZSTAT 8 "July 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zstat \- display Zephyr statistics +.SH SYNOPSIS +.B zstat +[ +.BI -h +] [ +.BI -s +] [ +.BI host \ ... +] +.SH DESCRIPTION +.I Zstat +is used to display statistics reported by a HostManager, +.I zhm(8), +or a Zephyr Server +.I zephyrd(8), +or both. +.TP 12 +.B \-h +is used to indicate that only HostManager statistics should be displayed. +.TP +.B \-s +is used to indicate that only server statistics should be displayed. +.TP +If no hosts are specified, the current host is assumed. +When both HostManager and server statistics are displayed, +statistics from the current server for each host are displayed. +.SH SEE ALSO +zephyr(1), zhm(8), zephyrd(8) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH AUTHOR +.PP +David C. Jedlinsky (MIT-Project Athena) +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/zstat/zstat.c b/clients/zstat/zstat.c new file mode 100644 index 0000000..6856893 --- /dev/null +++ b/clients/zstat/zstat.c @@ -0,0 +1,312 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the zstat program. + * + * Created by: David C. Jedlinsky + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +/* There should be library interfaces for the operations in zstat; for now, + * however, zstat is more or less internal to the Zephyr system. */ +#include + +#include +#include +#include +#include +#include "zserver.h" + +#if !defined(lint) && !defined(SABER) +static const char rcsid_zstat_c[] = "$Id$"; +#endif + +const char *hm_head[] = { + "Current server =", + "Items in queue:", + "Client packets received:", + "Server packets received:", + "Server changes:", + "Version:", + "Looking for a new server:", + "Time running:", + "Size:", + "Machine type:" +}; +#define HM_SIZE (sizeof(hm_head) / sizeof (char *)) +const char *srv_head[] = { + "Current server version =", + "Packets handled:", + "Uptime:", + "Server states:", +}; +#define SRV_SIZE (sizeof(srv_head) / sizeof (char *)) + +int outoftime = 0; + +int serveronly = 0,hmonly = 0; +u_short srv_port; + +void usage(char *); +void do_stat(char *); +int srv_stat(char *); +int hm_stat(char *, char *); + +static RETSIGTYPE +timeout(int ignored) +{ + outoftime = 1; +} + +int +main(int argc, + char *argv[]) +{ + Code_t ret; + char hostname[NS_MAXDNAME]; + int optchar; + struct servent *sp; + + if ((ret = ZInitialize()) != ZERR_NONE) { + com_err("zstat", ret, "initializing"); + exit(-1); + } + + if ((ret = ZOpenPort((u_short *)0)) != ZERR_NONE) { + com_err("zstat", ret, "opening port"); + exit(-1); + } + + while ((optchar = getopt(argc, argv, "sh")) != EOF) { + switch(optchar) { + case 's': + serveronly++; + break; + case 'h': + hmonly++; + break; + case '?': + default: + usage(argv[0]); + exit(1); + } + } + + if (serveronly && hmonly) { + fprintf(stderr,"Only one of -s and -h may be specified\n"); + exit(1); + } + + sp = getservbyname(SERVER_SVCNAME,"udp"); + srv_port = (sp) ? sp->s_port : SERVER_SVC_FALLBACK; + + if (optind == argc) { + do_stat("127.0.0.1"); + exit(0); + } + + for (;optindh_addr, hp->h_length); + + printf("Hostmanager stats: %s\n", hp->h_name); + } else { + printf("Hostmanager stats: %s\n", host); + } + + if ((code = ZhmStat(&inaddr, ¬ice)) != ZERR_NONE) { + com_err("zstat", code, "getting hostmanager status"); + exit(-1); + } + + mp = notice.z_message; + for (nf=0;mptm_yday, + tim->tm_hour, + tim->tm_min, + tim->tm_sec); + } + else + printf("%s %s\n",hm_head[i],line[i]); + } + + printf("\n"); + + ZFreeNotice(¬ice); + return(0); +} + +int +srv_stat(char *host) +{ + char *line[20],*mp; + int sock,i,nf,ret; + struct hostent *hp; + struct sockaddr_in sin; + ZNotice_t notice; + time_t runtime; + struct tm *tim; +#ifdef _POSIX_VERSION + struct sigaction sa; +#endif + + (void) memset((char *) &sin, 0, sizeof(struct sockaddr_in)); + + sin.sin_port = srv_port; + + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + perror("socket:"); + exit(-1); + } + + sin.sin_family = AF_INET; + + if ((sin.sin_addr.s_addr = inet_addr(host)) == (unsigned)(-1)) { + if ((hp = gethostbyname(host)) == NULL) { + fprintf(stderr,"Unknown host: %s\n",host); + exit(-1); + } + (void) memcpy((char *) &sin.sin_addr, hp->h_addr, hp->h_length); + + printf("Server stats: %s\n", hp->h_name); + } else { + printf("Server stats: %s\n", host); + } + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = UNSAFE; + notice.z_port = 0; + notice.z_charset = ZCHARSET_UNKNOWN; + notice.z_class = ZEPHYR_ADMIN_CLASS; + notice.z_class_inst = ""; + notice.z_opcode = ADMIN_STATUS; + notice.z_sender = ""; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_message_len = 0; + + if ((ret = ZSetDestAddr(&sin)) != ZERR_NONE) { + com_err("zstat", ret, "setting destination"); + exit(-1); + } + if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) { + com_err("zstat", ret, "sending notice"); + exit(-1); + } + +#ifdef _POSIX_VERSION + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = timeout; + (void) sigaction(SIGALRM, &sa, (struct sigaction *)0); +#else + (void) signal(SIGALRM,timeout); +#endif + outoftime = 0; + (void) alarm(10); + if (((ret = ZReceiveNotice(¬ice, (struct sockaddr_in *) 0)) + != ZERR_NONE) && + ret != EINTR) { + com_err("zstat", ret, "receiving notice"); + return (1); + } + (void) alarm(0); + if (outoftime) { + fprintf(stderr,"No response after 10 seconds.\n"); + return (1); + } + + mp = notice.z_message; + for (nf=0;mptm_yday, + tim->tm_hour, + tim->tm_min, + tim->tm_sec); + } else if (i == 3) { + printf("%s\n",srv_head[i]); + printf("%s\n",line[i]); + } else printf("%s\n",line[i]); + } + printf("\n"); + + (void) close(sock); + ZFreeNotice(¬ice); + return(0); +} + +void +usage(char *s) +{ + fprintf(stderr,"usage: %s [-s] [-h] [host ...]\n",s); + exit(1); +} diff --git a/clients/zwrite/Makefile.in b/clients/zwrite/Makefile.in new file mode 100644 index 0000000..eaf5ac5 --- /dev/null +++ b/clients/zwrite/Makefile.in @@ -0,0 +1,56 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=../.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=../.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err + +OBJS= zwrite.o + +all: zwrite + +zwrite: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: zwrite + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zwrite ${DESTDIR}${bindir} + ${INSTALL} -m 644 ${srcdir}/zwrite.1 ${DESTDIR}${mandir}/man1 + +clean: + ${LIBTOOL} --mode=clean rm -f zwrite + rm -f ${OBJS} + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/clients/zwrite/zwrite.1 b/clients/zwrite/zwrite.1 new file mode 100644 index 0000000..86472fa --- /dev/null +++ b/clients/zwrite/zwrite.1 @@ -0,0 +1,290 @@ +.\" $Id$ +.\" +.\" Copyright 1987,1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" +.TH ZWRITE 1 "October 26, 1989" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zwrite \- write to another user via Zephyr +.SH SYNOPSIS +.B zwrite +[ +.BI \-a +] [ +.BI \-d +] [ +.BI \-v +] [ +.BI \-q +] [ +.BI \-t +] [ +.BI \-u +] [ +.BI \-o +] [ +.BI \-n +] [ +.BI \-l +] [ +.BI \-C +] [ +.BI \-U +] [ +.BI \-O +opcode ] [ +.BI \-s +signature ] [ +.BI \-c +class ] [ +.BI \-i +instance ] [ +.BI \-r +realm ] [ +.BI \-f +arg ] [ +.BI \-S +sender ] [ +.BI user \ ... +] [ +.BI \-m +.BI message +] +.SH DESCRIPTION +.I Zwrite +sends a message from you to another user through the +.I zephyr(1) +notification service. The user must have subscribed to messages of +the appropriate class and instance using the +.I zctl(1) +program. +.PP +.I Zwrite +understands the following options. +.TP 12 +.B \-a +Causes +.I zwrite +to send the message authenticated, using +.I Kerberos +to perform the authentication. This is the default. +.TP +.B \-d +Causes +.I zwrite +to send the message unauthenticated. +.TP +.B \-v +Causes +.I zwrite +to print what type of message it is sending, and whether or not it was +successful. +.TP +.B \-q +Forces +.I zwrite +to suppress information about whether or not the message was sent. +.TP +.B \-t +Prevents +.I zwrite +from expanding tabs in the message into appropriate spaces. Normally +.I zwrite +will expand any tabs it finds into the appropriate number of spaces to +maintain separation based on 8-character tab stops. +.TP +.B \-l +Causes +.I zwrite +to ignore `.' on a line by itself in the input and only end a typed +message when the user types the end-of-file character (usually +control-D). When the input is not a terminal, this is the default action. +.TP +.B \-u +Sends an urgent message. This changes the +.I zephyr +instance of the message to ``URGENT''. +.TP +.B \-o +Causes +.I zwrite +to ignore the Zephyr variables +.IR zwrite-class , +.IR zwrite-inst , +and +.I zwrite-opcode +when picking a default class, instance, and opcode. +.TP +.B \-n +prevents +.I zwrite +from sending a PING message to verify the recipient is subscribing to +messages. By default, +.I zwrite +will send a notice to the destination class, instance, and recipient, +with opcode ``PING'' before sending the message. If the PING is sent, +and the server response indicates there are no recipients subscribed to +your message, +.I zwrite +exits without sending a message. +When the +.B \-n +option is used, no PING is sent. +.TP +.B \-C +prepends a "CC:" line to the body of the message indicating the +recipients of the message. This is strictly a convenience: the +presence of a "CC:" line at the top of a zephyr body does not +necessarily indicate that this option was used, or that the message +really was sent to the listed users, and its lack doesn't indicate +that the message was not sent to multiple users. +.TP +.B \-U +Send an unacked message. +.I zwrite +will not wait for acknowledgement that the message was sent, nor will +it issue a PING before sending. +.TP +.B \-s \fIsignature\fR +sets the signature to be included in the message. This overrides both +the user's name (as found in the password file) and any +setting of the Zephyr variable +.IR zwrite-signature . +.I signature +must +be a single argument, hence when using a shell it should be quoted with +double quotes. A +.I signature +argument of "" leaves the signature in +the message empty. +.TP +.B \-c \fIclass\fR +Allows a user to specify a different class for the message. This allows +a message to be sent to a large group of people with some degree of +security. See +.I zephyr(1) +and +.I zephyrd(8) +for a description of how to restrict access to classes. When this option +is specified, the message is sent to recipient "*" unless an additional +list of recipients is specified. +.br +This argument may not be used in conjunction with the \-f option. +.TP +.B \-i \fIinstance\fR +Allows a user to specify a different instance than the default. +When this option is used, the message is sent to recipient "*" unless an +additional list of recipients is specified. This allows a message to be +sent to a large group of people (e.g. a development group) just by having +the members subscribe to messages of class "MESSAGE", the specified instance, +and recipient "*". +.br +This argument may not be used in conjunction with the \-f option. +.TP +.B \-r \fIrealm\fR +Allows a user to specify a different realm for the message, if the +server supports interrealm Zephyr. +.TP +.B \-S \fIsender\fR +Specify a sender. The message will be sent unauthenticated. +.TP +.B \-F \fIformat\fR +Allows a user to specify a different default format for the message. +.TP +.B \-O \fIopcode\fR +Allows a user to specify a different opcode for the message. +Some Zephyr notice display programs may use the opcode to decide how +to display a notice. +.TP +.B \-f \fIarg\fR +Allows a user to specify an argument to be interpreted as a filesystem +specification. The class is set to +.BR FILSRV . +he instance is set +to +.I arg +as modified: +If +.I arg +contains no colons (`:'), it is assumed to +be a host name, and it is converted into an official host name via +.I gethostbyname(3). +If +.I arg +contains a colon, the portion preceding the colon is +treated as a host name, and the colon and any trailing characters are +appended to the offical host name returned by +.I gethostbyname. +If the name fails to resolve into an official host name, the instance is +set to +.I arg +unmodified. +.br +This option may not be used in conjunction with the \-c or \-i option. +.TP +.B \-m +.I Zwrite +sends the remaining arguments on the command line as the message. +.PP +If the +.I \-m +option is not specified, the user is prompted for the message to be +sent. The message may be terminated by typing ^D or ``.'' on a line +by itself. +.PP +The default class for messages is ``MESSAGE'', the default instance +is ``PERSONAL'', andthe default opcode is ``'' (an empty string). +These defaults can be overridden by setting the Zephyr +variables +.IR zwrite-class , +.IR zwrite-inst , +and +.IR zwrite-opcode , +respectively. +Command-line options can override the defaults. +.PP +If the class is ``MESSAGE'' and the instance is either ``PERSONAL'' or +``URGENT'', a recipient must be specified. These comparisons are +case-sensitive. +.PP +Unless the +.B \-s +option is used, the contents of the Zephyr variable +.I zwrite-signature +are used to augment the user's username in the +message. If +.I zwrite-signature +is not set and the +.B \-s +option is not specified, the user's full name (as specified in the +password file) is used instead. +.SH BUGS +Tab expansion should really be done by the receiver of the message. +.br +The \-u option is provided for compatibility with old versions of +.I zwrite +and is not necessarily useful for sending messages to users who do not +have old subscription files. +.SH SEE ALSO +kerberosintro(1), zctl(1), zephyr(1), zwgc(1), zhm(8), zephyrd(8), +gethostbyname(3) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH FILES +/etc/passwd +.br +$ZEPHYR_VARS or $HOME/.zephyr.vars +.SH AUTHOR +.PP +.br +Robert S. French (MIT-Project Athena) +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/clients/zwrite/zwrite.c b/clients/zwrite/zwrite.c new file mode 100644 index 0000000..aae3101 --- /dev/null +++ b/clients/zwrite/zwrite.c @@ -0,0 +1,568 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains code for the "zwrite" command. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include +#include +#include + +#ifndef lint +static const char rcsid_zwrite_c[] = "$Id$"; +#endif /* lint */ + +#define DEFAULT_CLASS "MESSAGE" +#define DEFAULT_INSTANCE "PERSONAL" +#define URGENT_INSTANCE "URGENT" +#define DEFAULT_OPCODE "" +#define FILSRV_CLASS "FILSRV" + +#define MAXRECIPS 100 + +int nrecips, msgarg, verbose, quiet, nodot, cc; +char *whoami, *inst, *class, *opcode, *realm, *recips[MAXRECIPS], *sender = 0; +Z_AuthProc auth; +ZNotice_Kind_t kind = ACKED; +void un_tabify(char **, int *); + +char *fix_filsrv_inst(char *); +void usage(char *); +void send_off(ZNotice_t *, int); + +int +main(int argc, char *argv[]) +{ + int retval, arg, nocheck, nchars, msgsize, filsys, tabexpand; + char *message, *signature = NULL, *format = NULL; + static char bfr[BUFSIZ], classbfr[BUFSIZ], instbfr[BUFSIZ], sigbfr[BUFSIZ]; + static char opbfr[BUFSIZ]; + static ZNotice_t notice; + char *charset = NULL; + + whoami = argv[0]; + + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err(whoami, retval, "while initializing"); + exit(1); + } + + if (argc < 2) + usage(whoami); + + auth = ZAUTH; + verbose = quiet = msgarg = nrecips = nocheck = filsys = nodot = 0; + tabexpand = 1; + + class = ZGetVariable("zwrite-class"); + if (class) { + (void) strcpy(classbfr, class); + class = classbfr; + } + else + class = DEFAULT_CLASS; + inst = ZGetVariable("zwrite-inst"); + if (inst) { + (void) strcpy(instbfr, inst); + inst = instbfr; + } + else + inst = DEFAULT_INSTANCE; + + opcode = ZGetVariable("zwrite-opcode"); + if (opcode) + opcode = strcpy(opbfr, opcode); + else + opcode = DEFAULT_OPCODE; + + signature = ZGetVariable("zwrite-signature"); + if (signature) { + (void) strcpy(sigbfr, signature); + signature = sigbfr; + } + + arg = 1; + + for (;arg 2) + usage(whoami); + switch (argv[arg][1]) { + case 'a': /* Backwards compatibility */ + auth = ZAUTH; + break; + case 'o': + class = DEFAULT_CLASS; + inst = DEFAULT_INSTANCE; + opcode = DEFAULT_OPCODE; + break; + case 'd': + auth = ZNOAUTH; + break; + case 'v': + verbose = 1; + break; + case 'q': + quiet = 1; + break; + case 'n': + nocheck = 1; + break; + case 't': + tabexpand = 0; + break; + case 'u': + inst = URGENT_INSTANCE; + break; + case 'O': + if (arg == argc-1) + usage(whoami); + arg++; + opcode = argv[arg]; + break; + case 'i': + if (arg == argc-1 || filsys == 1) + usage(whoami); + arg++; + inst = argv[arg]; + filsys = -1; + break; + case 'c': + if (arg == argc-1 || filsys == 1) + usage(whoami); + arg++; + class = argv[arg]; + filsys = -1; + break; + case 'f': + if (arg == argc-1 || filsys == -1) + usage(whoami); + arg++; + class = FILSRV_CLASS; + inst = fix_filsrv_inst(argv[arg]); + filsys = 1; + nocheck = 1; /* implied -n (no ping) */ + break; + case 's': + if (arg == argc-1) + usage(whoami); + arg++; + signature = argv[arg]; + break; + case 'm': + if (arg == argc-1) + usage(whoami); + nocheck = 1; /* implied -n (no ping) */ + msgarg = arg+1; + break; + case 'l': /* literal */ + nodot = 1; + break; + case 'F': + if (arg == argc-1) + usage(whoami); + arg++; + format = argv[arg]; + break; + case 'r': + if (arg == argc-1) + usage(whoami); + arg++; + realm = argv[arg]; + break; + case 'C': + cc = 1; + break; + case 'x': + if (arg == argc-1) + usage(whoami); + arg++; + charset = argv[arg]; + break; + case 'S': + if (arg == argc-1) + usage(whoami); + arg++; + sender = argv[arg]; + auth = ZNOAUTH; + break; + case 'U': + kind = UNACKED; + nocheck = 1; /* implied -n (no ping) */ + break; + default: + usage(whoami); + } + } + + if (!nrecips && !(strcmp(class, DEFAULT_CLASS) || + (strcmp(inst, DEFAULT_INSTANCE) && + strcmp(inst, URGENT_INSTANCE)))) { + /* must specify recipient if using default class and + (default instance or urgent instance) */ + fprintf(stderr, "No recipients specified.\n"); + usage(whoami); + } + + if (!signature) { + /* try to find name in the password file */ + register struct passwd *pwd; + register char *cp = sigbfr; + register char *cp2, *pp; + + pwd = getpwuid(getuid()); + if (pwd) { + cp2 = pwd->pw_gecos; + for (; *cp2 && *cp2 != ',' ; cp2++) { + if (*cp2 == '&') { + pp = pwd->pw_name; + *cp++ = islower(*pp) ? toupper(*pp) : *pp; + pp++; + while (*pp) + *cp++ = *pp++; + } else + *cp++ = *cp2; + } + signature = sigbfr; + } + } + + memset(¬ice, 0, sizeof(ZNotice_t)); + notice.z_kind = kind; + notice.z_port = 0; + notice.z_class = class; + notice.z_class_inst = inst; + notice.z_opcode = "PING"; + notice.z_sender = sender; + notice.z_message_len = 0; + notice.z_recipient = ""; + notice.z_charset = ZGetCharset(charset); + if (format) + notice.z_default_format = format; + else + notice.z_default_format = "http://zephyr.1ts.org/wiki/df"; + if (!nocheck && nrecips) + send_off(¬ice, 0); + + if (!msgarg && isatty(0)) { + if (nodot) + printf("Type your message now. End with the end-of-file character.\n"); + else + printf("Type your message now. End with control-D or a dot on a line by itself.\n"); + } + + message = NULL; + msgsize = 0; + if (signature) { + message = malloc((unsigned)(strlen(signature)+2)); + (void) strcpy(message, signature); + msgsize = strlen(message); + message[msgsize++] = '\0'; + } else { + message = malloc(1); + message[msgsize++] = '\0'; + } + + if (cc && nrecips > 1) { + int size = msgsize; + for (arg=0;argz_recipient = realm_recip; + } else { + notice->z_recipient = (nrecips) ? recips[i] : ""; + } + if (nrecips) + strcpy(dest, recips[i]); + else if (!strcmp(class, DEFAULT_CLASS)) + sprintf(dest, "instance \"%s\"", inst); + else if (!strcmp(inst, DEFAULT_INSTANCE)) + sprintf(dest, "class \"%s\"", class); + else + sprintf(dest, "class \"%s\", instance \"%s\"", class, inst); + if (verbose && real) + printf("Sending %smessage, class %s, instance %s, to %s\n", + auth?"authenticated ":"", + class, inst, + nrecips?notice->z_recipient:"everyone"); + if ((retval = ZSendNotice(notice, auth)) != ZERR_NONE) { + com_err(whoami, retval, "while sending notice to %s", dest); + break; + } + if (kind == UNACKED) + continue; + if (real && !quiet) { + if (verbose) + printf("Queued... "); + else + printf("Message queued for %s... ", dest); + fflush(stdout); + } + if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *) 0, + ZCompareUIDPred, + (char *)¬ice->z_uid)) != ZERR_NONE) { + com_err(whoami, retval, "while waiting for acknowledgement for %s", + dest); + continue; + } + if (retnotice.z_kind == SERVNAK) { + if (!quiet) { + printf("Received authorization failure while sending to %s\n", + dest); + } + ZFreeNotice(&retnotice); + break; /* if auth fails, punt */ + } + if (retnotice.z_kind != SERVACK || !retnotice.z_message_len) { + if (!quiet) { + printf("Detected server failure while receiving acknowledgement for %s\n", + dest); + } + ZFreeNotice(&retnotice); + continue; + } + if (!strcmp(retnotice.z_message, ZSRVACK_SENT)) { + success = 1; + if (real && !quiet) + printf("sent\n"); + } else if (!strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) { + if (verbose && real && !quiet) { + if (strcmp(class, DEFAULT_CLASS)) { + fprintf(stderr, "Not logged in or not subscribing to class %s, instance %s\n", + class, inst); + } else { + fprintf(stderr, + "Not logged in or not subscribing to messages\n"); + } + } + else if (!quiet) { + if (!nrecips) { + fprintf(stderr, + "No one subscribing to class %s, instance %s\n", + class, inst); + } else { + if (strcmp(class, DEFAULT_CLASS)) { + fprintf(stderr, "%s: Not logged in or not subscribing to class %s, instance %s\n", + notice->z_recipient, class, inst); + } else { + fprintf(stderr, "%s: Not logged in or not subscribing to messages\n", + notice->z_recipient); + } + } + } + } + else + printf("Internal failure - illegal message field in server response\n"); + ZFreeNotice(&retnotice); + } + if (!success) + exit(1); +} + +void +usage(char *s) +{ + fprintf(stderr, + "Usage: %s [-a] [-o] [-d] [-v] [-q] [-n] [-t] [-u] [-l]\n\ +\t[-c class] [-i inst] [-O opcode] [-f fsname] [-s signature] [-C]\n\ +\t[user ...] [-F format] [-r realm] [-x charset] [-m message]\n", s); + fprintf(stderr,"\t-f and -c are mutually exclusive\n\ +\t-f and -i are mutually exclusive\n\ +\trecipients must be specified unless -c or -f specifies a class\n\ +\tother than the default class or -i or -f specifies an instance\n\ +\tother than the default or urgent instance\n"); + exit(1); +} + +/* + if the -f option is specified, this routine is called to canonicalize + an instance of the form hostname[:pack]. It turns the hostname into the + name returned by gethostbyname(hostname) + */ + +char * +fix_filsrv_inst(char *str) +{ + static char fsinst[BUFSIZ]; + char *ptr; + struct hostent *hp; + + ptr = strchr(str,':'); + if (ptr) + *ptr = '\0'; + + hp = gethostbyname(str); + if (!hp) { + if (ptr) + *ptr = ':'; + return(str); + } + (void) strcpy(fsinst, hp->h_name); + if (ptr) { + (void) strcat(fsinst, ":"); + ptr++; + (void) strcat(fsinst, ptr); + } + return(fsinst); +} + +/* convert tabs in the buffer into appropriate # of spaces. + slightly tricky since the buffer can have NUL's in it. */ + +#ifndef TABSTOP +#define TABSTOP 8 /* #chars between tabstops */ +#endif /* ! TABSTOP */ + +void +un_tabify(char **bufp, + int *sizep) +{ + register char *cp, *cp2; + char *cp3; + register int i; + register int column; /* column of next character */ + register int size = *sizep; + + for (cp = *bufp, i = 0; size; size--, cp++) + if (*cp == '\t') + i++; /* count tabs in buffer */ + + if (!i) + return; /* no tabs == no work */ + + /* To avoid allocation churning, allocate enough extra space to convert + every tab into TABSTOP spaces */ + /* only add (TABSTOP-1)x because we re-use the cell holding the + tab itself */ + cp = malloc((unsigned)(*sizep + (i * (TABSTOP-1)))); + if (!cp) /* XXX */ + return; /* punt expanding if memory fails */ + cp3 = cp; + /* Copy buffer, converting tabs to spaces as we go */ + for (cp2 = *bufp, column = 1, size = *sizep; size; cp2++, size--) { + switch (*cp2) { + case '\n': + case '\0': + /* newline or null: reset column */ + column = 1; + *cp++ = *cp2; /* copy the newline */ + break; + default: + /* copy the character */ + *cp = *cp2; + cp++; + column++; + break; + case '\t': + /* it's a tab, compute how many spaces to expand into. */ + i = TABSTOP - ((column - 1) % TABSTOP); + for (; i > 0; i--) { + *cp++ = ' '; /* fill in the spaces */ + column++; + (*sizep)++; /* increment the size */ + } + (*sizep)--; /* remove one (we replaced the tab) */ + break; + } + } + free(*bufp); /* free the old buf */ + *bufp = cp3; + return; +} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..4b776d7 --- /dev/null +++ b/configure.ac @@ -0,0 +1,414 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT([zephyr],[__DEV__]) +AC_CONFIG_MACRO_DIR([m4]) + +test -d h || mkdir h +test -d h/zephyr || mkdir h/zephyr + +test -z "$lbindir" && lbindir='${bindir}' +test -z "$lsbindir" && lsbindir='${sbindir}' +AC_SUBST(lbindir) +AC_SUBST(lsbindir) + +AC_CANONICAL_SYSTEM +AC_CANONICAL_TARGET +AC_DEFINE_UNQUOTED(MACHINE_TYPE, "$host", [Define to the type of the host system.]) + +dnl Checks for programs. +AC_PROG_CC +AC_PROG_YACC +AC_PROG_LEX +AC_PROG_INSTALL +AC_PROG_LIBTOOL + +AC_MSG_CHECKING(location of temporary directory) +if test -d /var/tmp; then + found_tmp=/var/tmp/ +elif test -d /usr/tmp; then + found_tmp=/usr/tmp/ +else + found_tmp=/tmp/ +fi +AC_DEFINE_UNQUOTED(FOUND_TMP, "${found_tmp}", [Define to a temporary directory on your system.]) +AC_MSG_RESULT(${found_tmp}) + +dnl Checks for header files. +AC_PATH_XTRA +AC_HEADER_STDC +AC_HEADER_SYS_WAIT +AC_CHECK_HEADERS(fcntl.h paths.h sgtty.h unistd.h malloc.h) +AC_CHECK_HEADERS(sys/filio.h sys/ioctl.h sys/time.h sys/file.h sys/utsname.h) +AC_CHECK_HEADERS(sys/select.h sys/msgbuf.h sys/cdefs.h krb5_err.h termcap.h) +AC_CHECK_HEADERS(arpa/nameser_compat.h stdbool.h termio.h curses.h) +AC_CHECK_HEADERS([term.h], [], [], +[#ifdef HAVE_CURSES_H +#include +#endif +]) + +if test "$no_x" != "yes"; then + ZWGC_LIBX11=-lX11 +fi +AC_SUBST(XCLIENTS) +AC_SUBST(ZWGC_LIBX11) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_SIGNAL +AC_TYPE_UID_T +AC_CHECK_SIZEOF(short) +AC_CHECK_SIZEOF(int) +AC_CHECK_SIZEOF(long) +AC_MSG_CHECKING(for 32-bit integer type) +if test "$ac_cv_sizeof_long" = 4; then + int32=long +elif test "$ac_cv_sizeof_int" = 4; then + int32=int +elif test "$ac_cv_sizeof_short" = 4; then + int32=short +else + AC_WARN([Can't find 32-bit type, using long]) + int32=long +fi +AC_DEFINE_UNQUOTED(ZEPHYR_INT32, ${int32}, [Define to a signed 32-bit integral type.]) +AC_MSG_RESULT(${int32}) + +AC_CHECK_LIB(w, wslen) +# XXX? AC_CHECK_LIB(dl, dlopen) + +AC_CHECK_MEMBER([struct sockaddr_in.sin_len], + [AC_DEFINE(HAVE_SOCKADDR_IN_SIN_LEN, 1, + [sockaddr_in has sin_len member])], + [], [ +#include +#include +#include +]) + +AC_CHECK_MEMBER([struct sockaddr_in6.sin6_len], + [AC_DEFINE(HAVE_SOCKADDR_IN6_SIN6_LEN, 1, + [sockaddr_in6 has sin6_len member])], + [], [ +#include +#include +#include +]) + +AC_SEARCH_LIBS(gethostbyname, nsl) +AC_SEARCH_LIBS(socket, socket) + +AC_CHECK_LIB(44bsd, strerror) + +AC_ARG_WITH(libiconv, + [ --with-libiconv=PREFIX Location for libiconv], + [libiconv="$withval"], [libiconv=no]) +if test "$libiconv" != no; then + CPPFLAGS="$CPPFLAGS -I$libiconv/include" + LDFLAGS="$LDFLAGS -L$libiconv/lib" + AC_CHECK_LIB(iconv, iconv_open, [LIBICONV=-liconv; AC_SUBST(LIBICONV)]) +else + AC_CHECK_FUNC(iconv_open, :, + AC_CHECK_LIB(iconv, iconv_open, [LIBICONV=-liconv; AC_SUBST(LIBICONV)])) +fi +AC_SUBST(LIBICONV) + +AC_CHECK_LIB(curses, tgetstr, [TLIB=-lcurses], [TLIB=-ltermcap]) +AC_SUBST(TLIB) + +AC_ARG_WITH(krb4, + [ --with-krb4=PREFIX Use Kerberos 4], + [krb4="$withval"], [krb4=no]) +if test "$krb4" != no; then + AC_CHECK_FUNC(gethostbyname, :, AC_CHECK_LIB(nsl, gethostbyname)) + AC_CHECK_FUNC(socket, :, AC_CHECK_LIB(socket, socket)) + AC_CHECK_LIB(gen, compile) + if test "$krb4" != yes; then + CPPFLAGS="$CPPFLAGS -I$krb4/include" + if test -d "$krb4/include/kerberosIV"; then + CPPFLAGS="$CPPFLAGS -I$krb4/include/kerberosIV" + fi + LDFLAGS="$LDFLAGS -L$krb4/lib" + fi + AC_CHECK_LIB(krb4, krb_rd_req, + [KRB4_LIBS="-lkrb4 -ldes425 -lkrb5 -lk5crypto -lcom_err"], + [AC_CHECK_LIB(des, des_quad_cksum, + [KRB4_DES_LIBS="-ldes"],,,) + AC_CHECK_LIB(krb, krb_rd_req, + [KRB4_LIBS="-lkrb $KRB4_DES_LIBS"], + [AC_MSG_ERROR(Kerberos 4 libraries not found)], + $KRB4_DES_LIBS)], + -ldes425 -lkrb5 -lk5crypto -lcom_err) + AC_DEFINE(HAVE_KRB4, 1, [Define to compile with Kerberos support.]) + LIBZEPHYR_LIBS="$LIBZEPHYR_LIBS $KRB4_LIBS" +fi +AC_SUBST(KRB4_LIBS) + +AC_ARG_WITH(krb5, + [ --with-krb5=PREFIX Use Kerberos 5], + [krb5="$withval"], [krb5=no]) +if test "$krb5" != no; then + AC_SEARCH_LIBS(gethostbyname, nsl) + AC_SEARCH_LIBS(socket, socket) + AC_CHECK_LIB(gen, compile) + if test "$krb5" != yes; then + PATH="$krb5/bin:$PATH" + fi + AC_CHECK_PROG(krb5config, krb5-config,yes) + if test "$krb5config" = yes; then + CPPFLAGS="$CPPFLAGS $(krb5-config --cflags krb5)" + KRB5_LIBS="$(krb5-config --libs krb5)" + else + if test "$krb5" != yes; then + CPPFLAGS="$CPPFLAGS -I$krb5/include" + LDFLAGS="$LDFLAGS -L$krb5/lib" + fi + KRB5_LIBS="-lkrb5 -lk5crypto -lcom_err" + fi + AC_CHECK_HEADER(krb5.h, :, [AC_MSG_ERROR(Kerberos 5 headers not found)]) + local_save_LIBS=$LIBS + LIBS="$libs $KRB5_LIBS" + AC_CHECK_FUNC(krb5_init_context, :, + [AC_MSG_ERROR(Kerberos 5 libraries not found)]) + LIBS="$local_save_LIBS" + AC_DEFINE(HAVE_KRB5, 1, [Define to compile with Kerberos 5 support.]) + LIBZEPHYR_LIBS="$LIBZEPHYR_LIBS $KRB5_LIBS" + case "$target_os" in + darwin*) KRB5_LIBS="$KRB5_LIBS -framework Kerberos" ;; + esac +fi + +AC_ARG_WITH(hesiod, + [ --with-hesiod=PREFIX Use Hesiod], + [hesiod="$withval"], [hesiod=no]) + +if test "$krb5" != no || test "$hesiod" != no; then + # the zephyr library needs -lresolv if it's built with krb5 or hesiod + AC_CHECK_LIB([resolv], [res_mkquery], [], [ + AC_MSG_CHECKING([if res_mkquery is provided by libresolv with mangled symbols]) + save_LIBS="$LIBS" + LIBS="-lresolv $LIBS" + AC_TRY_LINK([#include ], + [res_mkquery(0,NULL,0,0,NULL,0,NULL,NULL,0);], [ + AC_DEFINE(HAVE_LIBRESOLV, [1], [Define if your libresolv provides res_mkquery.]) + LIBZEPHYR_LIBS="-lresolv $LIBZEPHYR_LIBS" + AC_MSG_RESULT(yes)], [ + LIBS="$save_LIBS" + AC_MSG_RESULT(no) + AC_MSG_ERROR(Zephyr requires libresolv along with Kerberos V or Hesiod.) + ])]) +fi + +AC_SUBST(KRB5_LIBS) + +AC_SUBST(LIBZEPHYR_LIBS) +if test "$hesiod" != no; then + if test "$hesiod" != yes; then + CPPFLAGS="$CPPFLAGS -I$hesiod/include" + LDFLAGS="$LDFLAGS -L$hesiod/lib" + fi + AC_CHECK_FUNC(hes_resolve, :, + AC_CHECK_LIB(hesiod, hes_resolve, HESIOD_LIBS="-lhesiod", + [AC_MSG_ERROR(Hesiod library not found)],$LIBS)) + AC_DEFINE(HAVE_HESIOD, 1, [Define to compile with Hesiod support.]) +fi + +AC_SUBST(HESIOD_LIBS) + +AC_ARG_WITH(regex, + [ --with-regex=PREFIX Use installed regex library], + [regex="$withval"], [regex=no]) +if test "$regex" != no; then + if test "$regex" != yes; then + CPPFLAGS="$CPPFLAGS -I$regex/include" + LDFLAGS="$LDFLAGS -L$regex/lib" + fi + AC_CHECK_LIB(regex, regcomp, REGEX_LIBS=-lregex, + [AC_MSG_ERROR(regex library not found)]) +else + AC_CHECK_FUNC(regcomp, :, + [AC_MSG_ERROR(can't find POSIX regexp support)]) +fi +AC_SUBST(REGEX_LIBS) + +AC_ARG_WITH(com_err, + [ --with-com_err=PREFIX Specify location of com_err], + [com_err="$withval"], [com_err=yes]) +if test "$com_err" != no; then + if test "$com_err" != yes; then + CPPFLAGS="$CPPFLAGS -I$com_err/include" + LDFLAGS="$LDFLAGS -L$com_err/lib" + fi + AC_CHECK_LIB(com_err, com_err, :, + [AC_MSG_ERROR(com_err library not found)]) +else + AC_MSG_ERROR(This package requires com_err.) +fi + +AC_ARG_WITH(ss, + [ --with-ss=PREFIX Specify location of ss (requires com_err)], + [ss="$withval"], [ss=maybe]) +if test "$ss" != no; then + if test "$ss" != yes -a "$ss" != maybe; then + CPPFLAGS="$CPPFLAGS -I$ss/include" + LDFLAGS="$LDFLAGS -L$ss/lib" + fi + AC_CHECK_LIB(ss, ss_perror, + [SS_LIBS="-lss" + AC_DEFINE(HAVE_SS, 1, [Define if we are building with the ss library])], + AS_IF([test "x$ss" != "xmaybe"], AC_MSG_ERROR(ss library not found)), + -lcom_err) + SS_OBJS='${SS_OBJS}' +fi +AC_SUBST(SS_LIBS) +AC_SUBST(SS_OBJS) + +LIBS="$KRB5_LIBS $KRB4_LIBS $LIBS" + +dnl Checks for library functions. +#XXX more looking for res_send +#AC_CHECK_FUNC(res_send, :, AC_CHECK_LIB(resolv, res_send)) + +AC_ARG_WITH([cares], AS_HELP_STRING([--with-cares], [Use libcares])) +if test "x$with_ares" != "xno"; then + AC_CHECK_LIB(cares, ares_getnameinfo, + [ARES_LIBS="-lcares" + AC_DEFINE(HAVE_ARES, 1, [Define to compile with c-ares support.])], + AS_IF([test "x$with_ares" = "xyes"], + AC_MSG_ERROR(libcares not found))) +fi +AC_SUBST(ARES_LIBS) + +AC_PROG_GCC_TRADITIONAL +AC_FUNC_VPRINTF +AC_FUNC_GETPGRP +AC_FUNC_SETPGRP +AC_CHECK_FUNCS(putenv strchr memcpy memmove waitpid getlogin strerror random) +AC_CHECK_FUNCS(lrand48 gethostid getsid getpgid etext) +AC_CHECK_FUNCS(krb_get_err_text krb_log) +AC_CHECK_FUNCS(krb5_free_data krb5_c_make_checksum krb5_cc_set_default_name) +AC_CHECK_FUNCS(krb5_crypto_init krb5_c_decrypt krb5_free_unparsed_name) + +AC_MSG_CHECKING(krb5_auth_con_getauthenticator out argument type) +AC_CACHE_VAL(ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer, [ +local_save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}" +AC_TRY_COMPILE( +[#include +krb5_error_code +krb5_auth_con_getauthenticator(krb5_context context, + krb5_auth_context auth_context, + krb5_authenticator *authenticator);], +[krb5_error_code foo = krb5_auth_con_getauthenticator(0, 0, 0);], +ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer=no, +[AC_TRY_COMPILE( +[#include +krb5_error_code +krb5_auth_con_getauthenticator(krb5_context context, + krb5_auth_context auth_context, + krb5_authenticator **authenticator);], +[krb5_error_code foo = krb5_auth_con_getauthenticator(0, 0, 0);], +ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer=yes, +[AC_MSG_ERROR([Cannot identify krb5_auth_con_getauthenticator function signature])] +)]) +CPPFLAGS="${local_save_CPPFLAGS}" +]) +krb5_authent_type='krb5_authenticator *' +if test "$ac_cv_krb5_auth_con_getauthenticator_takes_double_pointer" = yes; then + AC_DEFINE(KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER, 1, + [Define if `krb5_auth_con_getauthenticator' takes a double pointer third arg.])dnl + krb5_authent_type='krb5_authenticator **' +fi +AC_MSG_RESULT($krb5_authent_type) + +AC_CACHE_CHECK([krb5_auth_con_getflags out argument type], + [ac_cv_krb5_auth_con_flags_type], [ +local_save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}" +for t in krb5_flags int32_t ; do + AC_TRY_COMPILE( + [#include + extern krb5_error_code + krb5_auth_con_getflags(krb5_context, krb5_auth_context, $t *);], + [krb5_error_code foo = krb5_auth_con_getflags(0, 0, 0);], + [ac_cv_krb5_auth_con_flags_type=$t; break]) +done +CPPFLAGS="${local_save_CPPFLAGS}" +if test "x$ac_cv_krb5_auth_con_flags_type" = x ; then + AC_MSG_ERROR([Cannot identify krb5_auth_con_getflags function signature]) +fi +]) +AC_DEFINE_UNQUOTED([KRB5_AUTH_CON_FLAGS_TYPE], + [$ac_cv_krb5_auth_con_flags_type], + [krb5_auth_con_getflags() output arg type]) + +AC_MSG_CHECKING(for enc_part2 in struct krb5_ticket) +AC_CACHE_VAL(ac_cv_have_krb5_ticket_enc_part2, [ +local_save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}" +AC_TRY_COMPILE( +[#include ], [krb5_ticket _tkt; _tkt.enc_part2;], +ac_cv_have_krb5_ticket_enc_part2=yes, +ac_cv_have_krb5_ticket_enc_part2=no) +]) +CPPFLAGS="${local_save_CPPFLAGS}" +if test "$ac_cv_have_krb5_ticket_enc_part2" = yes; then + AC_DEFINE(HAVE_KRB5_TICKET_ENC_PART2, 1, + [Define to 1 if `enc_part2' is member of `krb5_ticket'.])dnl +fi +AC_MSG_RESULT($ac_cv_have_krb5_ticket_enc_part2) + +AC_MSG_CHECKING(for enctype in struct krb5_keyblock) +AC_CACHE_VAL(ac_cv_have_krb5_creds_keyblock_enctype, [ +local_save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="${CPPFLAGS} ${KRB5_INC_FLAGS}" +AC_TRY_COMPILE( +[#include ], [krb5_creds _creds; _creds.keyblock.enctype;], +ac_cv_have_krb5_creds_keyblock_enctype=yes, +ac_cv_have_krb5_creds_keyblock_enctype=no) +]) +CPPFLAGS="${local_save_CPPFLAGS}" +if test "$ac_cv_have_krb5_creds_keyblock_enctype" = yes; then + AC_DEFINE(HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE, 1, + [Define if `keyblock.enctype' is member of `krb5_creds'.])dnl +fi +AC_MSG_RESULT($ac_cv_have_krb5_creds_keyblock_enctype) + +AC_ARG_ENABLE(cmu-zwgcplus, +[ --enable-cmu-zwgcplus enable CMU zwgcplus extensions],[ +if test "$enableval" = "yes"; then + AC_DEFINE(CMU_ZWGCPLUS, 1, [Define to enable zwgcplus support]) +fi +]) + +AC_ARG_ENABLE(cmu-zctl-punt, +[ --enable-cmu-zctl-punt enable CMU zctl punt extensions],[ +if test "$enableval" = "yes"; then + AC_DEFINE(CMU_ZCTL_PUNT, 1, + [Define to pull in CMU zctl punt backward compat foo]) +fi +]) + +AC_ARG_ENABLE(cmu-hm-flush-restrict, +[ --enable-cmu-hm-flush-restrict enable CMU zctl hm flush restriction],[ +if test "$enableval" = "yes"; then + AC_DEFINE(HM_FLUSH_RESTRICT, 1, + [Define to get hm_flush restrictions in zctl]) +fi +]) + +AC_ARG_ENABLE(cmu-opstaff-locate-self, +[ --enable-cmu-opstaff-locate-self enable CMU opstaff locate-self ability],[ +if test "$enableval" = "yes"; then + AC_DEFINE(OPSTAFF_LOCATE_SELF, 1, + [Define to allow users to locate themselves if they are opstaff]) +fi +]) + +AC_CONFIG_HEADER(h/config.h) +AC_OUTPUT(Makefile clients/Makefile clients/zaway/Makefile + clients/zctl/Makefile clients/zleave/Makefile + clients/zlocate/Makefile clients/znol/Makefile + clients/zshutdown_notify/Makefile clients/zstat/Makefile + clients/zwrite/Makefile lib/Makefile + server/Makefile zhm/Makefile zwgc/Makefile + zephyr.pc + ) diff --git a/contrib/zephyr-dissector.lua b/contrib/zephyr-dissector.lua new file mode 100644 index 0000000..13ea6c9 --- /dev/null +++ b/contrib/zephyr-dissector.lua @@ -0,0 +1,233 @@ +-- Wireshark dissector for Zephyr +-- Place in ~/.local/lib/wireshark/plugins/2.6/ + +zephyr_protocol = Proto("Zephyr", "Zephyr IM Protocol") + +local kind_names = { + [0] = "UNSAFE", + [1] = "UNACKED", + [2] = "ACKED", + [3] = "HMACK", + [4] = "HMCTL", + [5] = "SERVACK", + [6] = "SERVNAK", + [7] = "CLIENTACK", + [8] = "STAT" +} +zephyr_protocol.fields.version = ProtoField.stringz("zephyr.version", "Version") +zephyr_protocol.fields.numfields = ProtoField.uint32("zephyr.fields", "Field Count") +zephyr_protocol.fields.z_kind = ProtoField.uint32("zephyr.z_kind", "Kind", base.DEC, kind_names) +zephyr_protocol.fields.z_uid = ProtoField.stringz("zephyr.z_uid", "UID") +zephyr_protocol.fields.z_uid_addr = ProtoField.ipv4("zephyr.z_uid.zuid_addr", "Address") +zephyr_protocol.fields.z_uid_tv = ProtoField.absolute_time("zephyr.z_uid.tv", "Time") +zephyr_protocol.fields.z_port = ProtoField.uint16("zephyr.z_port", "Port") +zephyr_protocol.fields.z_auth = ProtoField.uint32("zephyr.z_auth", "Auth") +zephyr_protocol.fields.z_authent_len = ProtoField.uint32("zephyr.z_authent_len", "Authenticator Length") +zephyr_protocol.fields.z_ascii_authent = ProtoField.stringz("zephyr.z_ascii_authent", "Authenticator") +zephyr_protocol.fields.z_class = ProtoField.stringz("zephyr.z_class", "Class") +zephyr_protocol.fields.z_class_inst = ProtoField.stringz("zephyr.z_class_inst", "Instance") +zephyr_protocol.fields.z_opcode = ProtoField.stringz("zephyr.z_opcode", "Opcode") +zephyr_protocol.fields.z_sender = ProtoField.stringz("zephyr.z_sender", "Sender") +zephyr_protocol.fields.z_recipient = ProtoField.stringz("zephyr.z_recipient", "Recipient") +zephyr_protocol.fields.z_default_format = ProtoField.stringz("zephyr.z_default_format", "Default Format") +zephyr_protocol.fields.z_ascii_checksum = ProtoField.stringz("zephyr.z_ascii_checksum", "ASCII Checksum") +zephyr_protocol.fields.z_checksum = ProtoField.uint32("zephyr.z_checksum", "Checksum") +zephyr_protocol.fields.z_multinotice = ProtoField.stringz("zephyr.z_multinotice", "Multinotice") +zephyr_protocol.fields.z_multiuid = ProtoField.stringz("zephyr.z_multiuid", "MultiUID") +zephyr_protocol.fields.z_multiuid_addr = ProtoField.ipv4("zephyr.z_multiuid.zuid_addr", "Address") +zephyr_protocol.fields.z_multiuid_tv = ProtoField.absolute_time("zephyr.z_multiuid.tv", "Time") +zephyr_protocol.fields.z_sender_sockaddr = ProtoField.ipv4("zephyr.z_sender_sockaddr", "Sender sockaddr") +zephyr_protocol.fields.z_charset = ProtoField.uint16("zephyr.z_charset", "Character Set") +zephyr_protocol.fields.z_message = ProtoField.string("zephyr.z_message", "Message") +zephyr_protocol.fields.z_message_len = ProtoField.uint32("zephyr.z_message_len", "Message Length") + +function parse_ascii(range) + local v = range(2):string() + return tonumber(string.match(v, "[0-9A-F]+"), 16) +end + +function parse_ascii_ip(range) + local ip = "" .. tonumber(range(2, 2):string(), 16) .. "." .. tonumber(range(4, 2):string(), 16) .. "." .. tonumber(range(6, 2):string(), 16) .. "." .. tonumber(range(8, 2):string(), 16) + return Address.ip(ip) +end + +function parse_zcode_ip(range) + local bytes = {} + local str = range(1,range:len()-2):bytes() + local i = 0 + while i < str:len() do + local byte = str:get_index(i) + info(i .. ": " .. byte) + if (byte == 0xFF) then + if (str:get_index(i+1) == 0xF0) then + table.insert(bytes, 0) + elseif (str:get_index(i+1) == 0xF1) then + table.insert(bytes, 0xFF) + end + i = i + 2 + else + table.insert(bytes, byte) + i = i + 1 + end + end + info(bytes[1]) + info(table.concat(bytes, ".")) + return Address.ip(table.concat(bytes, ".")) +end + +function parse_ascii_tv(range) + info(range:string()) + local seconds = parse_ascii(range) + local microseconds = parse_ascii(range(11)) + return NSTime.new(seconds, microseconds*1000) +end + +function zephyr_protocol.dissector(buffer, pinfo, tree) + length = buffer:len() + if length == 0 then return end + + pinfo.cols.protocol = zephyr_protocol.name + + local subtree = tree:add(zephyr_protocol, buffer(), "Zephyr") + + local range = buffer() + local length = range:strsize() + local v = range:stringz() + subtree:add(zephyr_protocol.fields.version, range) + + if v == "ZEPH0.2" then + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + local numfields = parse_ascii(range) + subtree:add(zephyr_protocol.fields.numfields, range, numfields) + numfields = numfields - 2 + + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + local kind = parse_ascii(range) + subtree:add(zephyr_protocol.fields.z_kind, range, kind) + numfields = numfields - 1 + + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + local z_uid = subtree:add(zephyr_protocol.fields.z_uid, range) + + local addr = parse_ascii_ip(range) + local tv = parse_ascii_tv(range(11)) + z_uid:add(zephyr_protocol.fields.z_uid_addr, range(0, 11), addr) + z_uid:add(zephyr_protocol.fields.z_uid_tv, range(11), tv) + z_uid:set_text("UID: " .. tostring(addr) .. " " .. tostring(tv)) + + numfields = numfields - 1 + + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + subtree:add(zephyr_protocol.fields.z_port, range, parse_ascii(range)) + numfields = numfields - 1 + + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + subtree:add(zephyr_protocol.fields.z_auth, range, parse_ascii(range)) + numfields = numfields - 1 + + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + local authent_length = parse_ascii(range) + subtree:add(zephyr_protocol.fields.z_authent_len, range, authent_length) + numfields = numfields - 1 + + function add(field) + range = buffer(range:offset()+range:len()) + subtree:add(field, range) + numfields = numfields - 1 + end + + add(zephyr_protocol.fields.z_ascii_authent) + add(zephyr_protocol.fields.z_class) + local class = range:stringz() + add(zephyr_protocol.fields.z_class_inst) + local instance = range:stringz() + add(zephyr_protocol.fields.z_opcode) + local opcode = range:stringz() + add(zephyr_protocol.fields.z_sender) + add(zephyr_protocol.fields.z_recipient) + add(zephyr_protocol.fields.z_default_format) + + if (numfields > 0) then + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + subtree:add(zephyr_protocol.fields.z_ascii_checksum, range) + local status, value = pcall(function() return parse_ascii(range) end) + if status then + subtree:add(zephyr_protocol.fields.z_checksum, range, value) + end + numfields = numfields - 1 + -- TODO: validate checksum and flag if wrong + end + + if (numfields > 0) then + range = buffer(range:offset()+range:len()) + subtree:add(zephyr_protocol.fields.z_multinotice, range) + numfields = numfields - 1 + end + + if (numfields > 0) then + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + local z_multiuid = subtree:add(zephyr_protocol.fields.z_multiuid, range) + + local addr = parse_ascii_ip(range) + local tv = parse_ascii_tv(range(11)) + z_multiuid:add(zephyr_protocol.fields.z_multiuid_addr, range(0, 11), addr) + z_multiuid:add(zephyr_protocol.fields.z_multiuid_tv, range(11), tv) + z_multiuid:set_text("MultiUID: " .. tostring(addr) .. " " .. tostring(tv)) + numfields = numfields - 1 + -- else z_multiuid = z_uid + end + + if (numfields > 0) then + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + if (range:string():byte(1) == 90) then + -- TODO: parse Zcode address for real + subtree:add(zephyr_protocol.fields.z_sender_sockaddr, range, parse_zcode_ip(range)):append_text(" (Zcode)") + else + subtree:add(zephyr_protocol.fields.z_sender_sockaddr, range, parse_ascii_ip(range)):append_text(" (NetASCII)") + end + numfields = numfields - 1 + end + + if (numfields > 0) then + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + subtree:add(zephyr_protocol.fields.z_charset, range, parse_ascii(range)) + numfields = numfields - 1 + end + + if (numfields > 0) then + local otherfields = subtree:add("Other Fields") + for i = 1,numfields do + range = buffer(range:offset()+range:len()) + range = range(0, range:strsize()) + otherfields:add(range) + numfields = numfields - 1 + end + end + + range = buffer(range:offset()+range:len()) + if (range:len() > 0) then + subtree:add(zephyr_protocol.fields.z_message_len, range:len()) + subtree:add(zephyr_protocol.fields.z_message, range) + end + local info = kind_names[kind] .. " " .. class .. " " .. instance .. " " .. opcode + pinfo.columns.info = info + subtree.text = "Zephyr, " .. info + end +end + + + +local udp_port = DissectorTable.get("udp.port") +udp_port:add(2102, zephyr_protocol) +udp_port:add(2103, zephyr_protocol) +udp_port:add(2104, zephyr_protocol) diff --git a/debian/.gitattributes b/debian/.gitattributes new file mode 100644 index 0000000..9a0df39 --- /dev/null +++ b/debian/.gitattributes @@ -0,0 +1 @@ +zephyr.vars ident diff --git a/debian/README.krb4-5 b/debian/README.krb4-5 new file mode 100644 index 0000000..3278453 --- /dev/null +++ b/debian/README.krb4-5 @@ -0,0 +1 @@ +Placehold that will explain how to build an agile server goes here. diff --git a/debian/acl/class-registry.acl b/debian/acl/class-registry.acl new file mode 100644 index 0000000..272e138 --- /dev/null +++ b/debian/acl/class-registry.acl @@ -0,0 +1,9 @@ +wg_ctl: +hm_ctl: +hm_stat: +locate: +login: +zephyr_admin: +zephyr_ctl: +zmatch_all: +operations: diff --git a/debian/acl/iui-hm_ctl.acl b/debian/acl/iui-hm_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-hm_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iui-hm_stat.acl b/debian/acl/iui-hm_stat.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-hm_stat.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iui-login.acl b/debian/acl/iui-login.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-login.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iui-operations.acl b/debian/acl/iui-operations.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/iui-operations.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/iui-user_locate.acl b/debian/acl/iui-user_locate.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-user_locate.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iui-wg_ctl.acl b/debian/acl/iui-wg_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-wg_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iui-zephyr_admin.acl b/debian/acl/iui-zephyr_admin.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-zephyr_admin.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iui-zephyr_ctl.acl b/debian/acl/iui-zephyr_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iui-zephyr_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-hm_ctl.acl b/debian/acl/iws-hm_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-hm_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-hm_stat.acl b/debian/acl/iws-hm_stat.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-hm_stat.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-login.acl b/debian/acl/iws-login.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-login.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-operations.acl b/debian/acl/iws-operations.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/iws-operations.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/iws-user_locate.acl b/debian/acl/iws-user_locate.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-user_locate.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-wg_ctl.acl b/debian/acl/iws-wg_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-wg_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-zephyr_admin.acl b/debian/acl/iws-zephyr_admin.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-zephyr_admin.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/iws-zephyr_ctl.acl b/debian/acl/iws-zephyr_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/iws-zephyr_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/sub-hm_ctl.acl b/debian/acl/sub-hm_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/sub-hm_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/sub-hm_stat.acl b/debian/acl/sub-hm_stat.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/sub-hm_stat.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/sub-login.acl b/debian/acl/sub-login.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/sub-login.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/sub-operations.acl b/debian/acl/sub-operations.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/sub-operations.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/sub-user_locate.acl b/debian/acl/sub-user_locate.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/sub-user_locate.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/sub-wg_ctl.acl b/debian/acl/sub-wg_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/sub-wg_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/sub-zephyr_admin.acl b/debian/acl/sub-zephyr_admin.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/sub-zephyr_admin.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/sub-zephyr_ctl.acl b/debian/acl/sub-zephyr_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/sub-zephyr_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/xmt-hm_ctl.acl b/debian/acl/xmt-hm_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/xmt-hm_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/xmt-hm_stat.acl b/debian/acl/xmt-hm_stat.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/xmt-hm_stat.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/xmt-login.acl b/debian/acl/xmt-login.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/xmt-login.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/xmt-operations.acl b/debian/acl/xmt-operations.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/xmt-operations.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/xmt-user_locate.acl b/debian/acl/xmt-user_locate.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/xmt-user_locate.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/acl/xmt-wg_ctl.acl b/debian/acl/xmt-wg_ctl.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/xmt-wg_ctl.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/xmt-zephyr_admin.acl b/debian/acl/xmt-zephyr_admin.acl new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/debian/acl/xmt-zephyr_admin.acl @@ -0,0 +1 @@ + diff --git a/debian/acl/xmt-zephyr_ctl.acl b/debian/acl/xmt-zephyr_ctl.acl new file mode 100644 index 0000000..74c91fb --- /dev/null +++ b/debian/acl/xmt-zephyr_ctl.acl @@ -0,0 +1 @@ +*.*@* diff --git a/debian/changelog b/debian/changelog new file mode 100644 index 0000000..966a126 --- /dev/null +++ b/debian/changelog @@ -0,0 +1,89 @@ +zephyr (1:3.1.999-trunk) unstable; urgency=low + + * The next actual release on this branch will be 3.2... someday + + -- Karl Ramm Mon, 28 Oct 2013 00:32:21 -0400 + +zephyr (1:3.1.1-trunk) unstable; urgency=low + + * release 3.1.1 + + -- Karl Ramm Fri, 25 Oct 2013 01:15:29 -0400 + +zephyr (1:3.1-trunk) unstable; urgency=low + + * release 3.1 + + -- Karl Ramm Sat, 12 Oct 2013 13:15:58 -0400 + +zephyr (1:3.1~rc2-trunk) unstable; urgency=low + + * release 3.1~rc2 + + -- Karl Ramm Sun, 06 Oct 2013 20:53:42 -0400 + +zephyr (1:3.1~rc1-trunk) unstable; urgency=low + + * release 3.1~rc1 + + -- Karl Ramm Sat, 28 Sep 2013 19:45:21 -0400 + +zephyr (1:3.1~rc0-trunk) unstable; urgency=low + + * release 3.1~rc0 + + -- Karl Ramm Sat, 28 Sep 2013 15:18:25 -0400 + +zephyr (1:3.1~beta1-trunk) unstable; urgency=low + + * release 3.1~beta1 + + -- Karl Ramm Thu, 08 Aug 2013 02:23:32 -0400 + +zephyr (1:3.1-beta0-trunk) unstable; urgency=low + + * release 3.1-beta0 + + -- Karl Ramm Sun, 07 Jul 2013 22:08:01 -0400 + +zephyr (1:3.0.999-trunk) UNRELEASED; urgency=low + + * Any further revisions to 3.0.x go on the 3.0.x branch; the mainline is for 3.1 stuff + + -- Karl Ramm Sat, 11 Feb 2012 10:53:49 -0500 + +zephyr (1:3.0.2-trunk) unstable; urgency=low + + * release 3.0.2 + + -- Karl Ramm Sun, 22 Jan 2012 02:12:41 -0500 + +zephyr (1:3.0.1) unstable; urgency=low + + * 80% more nelhage proof + + -- Karl Ramm Sun, 06 Mar 2011 10:54:46 -0500 + +zephyr (1:3.0.1~rc.HEAD) unstable; urgency=low + + * bugfixes ahoy. + + -- Karl Ramm Wed, 07 Jul 2010 16:26:49 -0400 + +zephyr (1:3.0) unstable; urgency=low + + * Might as well let it escape. + + -- Karl Ramm Mon, 05 Oct 2009 19:56:17 -0400 + +zephyr (1:3.0~rc.HEAD) unstable; urgency=low + + * It's Release Candidate Time! + + -- Karl Ramm Mon, 03 Aug 2009 01:27:46 -0400 + +zephyr (1:3.0~beta.HEAD) inconceivable; urgency=low + + * Mark version for upstream trunk + + -- Karl Ramm Sat, 28 Mar 2009 12:59:14 -0400 diff --git a/debian/compat b/debian/compat new file mode 100644 index 0000000..7ed6ff8 --- /dev/null +++ b/debian/compat @@ -0,0 +1 @@ +5 diff --git a/debian/control b/debian/control new file mode 100644 index 0000000..bf03797 --- /dev/null +++ b/debian/control @@ -0,0 +1,191 @@ +Source: zephyr +Section: net +Priority: optional +Maintainer: Karl Ramm +Build-Depends: debhelper (>= 5), libc-ares-dev, libkrb5-dev (>= 1.2.2-4), + comerr-dev, ss-dev, libreadline-dev | libreadline5-dev, + libx11-dev, libxt-dev, x11proto-core-dev, libncurses5-dev, + bison, libhesiod-dev, autotools-dev, python (>= 2.5), python-central, + autoconf, libtool, automake, git-core | git, devscripts +Build-Conflicts: autoconf2.13 +Standards-Version: 3.9.2.0 +Homepage: http://zephyr.1ts.org/ +Vcs-Svn: git://zephyr.1ts.org/zephyr.git +Vcs-Browser: http://zephyr.1ts.org/browser/zephyr +XS-Python-Version: 2.5 + +Package: libzephyr4 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends} +Conflicts: libzephyr4-krb, libzephyr4-krb5, libzephyr4-krb45 +Description: Project Athena's notification service - non-Kerberos libraries + Zephyr is derived from the original Project Athena 'Instant Message' system + and allows users to send messages to other users or to groups of users. + Users can view incoming Zephyr messages as windowgrams (transient X + windows) or as text on a terminal. + . + This package provides the libraries without Kerberos support. + +Package: libzephyr4-krb +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, krb4-config +Conflicts: libzephyr4, libzephyr4-krb5, libzephyr4-krb45 +Replaces: libzephyr4, libzephyr4-krb5, libzephyr4-krb45 +Provides: libzephyr4 +Description: Project Athena's notification service - libraries with Kerberos + Zephyr is derived from the original Project Athena 'Instant Message' system + and allows users to send messages to other users or to groups of users. + Users can view incoming Zephyr messages as windowgrams (transient X + windows) or as text on a terminal. + . + This package provides libraries that use Kerberos. + +Package: libzephyr4-krb5 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, krb5-config +Conflicts: libzephyr4, libzephyr4-krb, libzephyr4-krb45 +Replaces: libzephyr4, libzephyr4-krb, libzephyr4-krb45 +Provides: libzephyr4 +Description: The original "Instant Message" system libraries with Kerberos 5 + This version of the library uses Kerberos for message authentication. + . + This is the Project Athena Zephyr notification system. + Zephyr allows users to send messages to other users or to groups of + users. Users can view incoming Zephyr messages as windowgrams + (transient X windows) or as text on a terminal. + +Package: libzephyr4-krb45 +Section: libs +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, krb5-config +Conflicts: libzephyr4, libzephyr4-krb, libzephyr4-krb5 +Replaces: libzephyr4, libzephyr4-krb, libzephyr4-krb5 +Provides: libzephyr4 +Description: The original "Instant Message" system libraries with Kerberos 4+5 + This version of the library uses Kerberos for message authentication. + . + This is the Project Athena Zephyr notification system. + Zephyr allows users to send messages to other users or to groups of + users. Users can view incoming Zephyr messages as windowgrams + (transient X windows) or as text on a terminal. + +Package: libzephyr-python +Section: python +Architecture: any +Depends: ${python:Depends}, ${misc:Depends}, libzephyr4 +Provides: ${python:Provides} +XB-Python-Version: ${python:Verions} +Description: Python bindings for zephyr library + Get at the zephyr library from python. + +Package: zephyr-clients +Section: net +Replaces: zephyr-client +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, debianutils (>= 1.6), debconf | debconf-2.0 +Description: Project Athena's notification service - client programs + Zephyr is derived from the original Project Athena 'Instant Message' system + and allows users to send messages to other users or to groups of users. + Users can view incoming Zephyr messages as windowgrams (transient X + windows) or as text on a terminal. + . + This package provides client programs for the messaging service. + +Package: zephyr-server +Section: net +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, debconf | debconf-2.0 +Conflicts: zephyr-server-krb, zephyr-server-krb5, zephyr-server-krb45 +Description: Project Athena's notification service - non-Kerberos server + Zephyr is derived from the original Project Athena 'Instant Message' system + and allows users to send messages to other users or to groups of users. + Users can view incoming Zephyr messages as windowgrams (transient X + windows) or as text on a terminal. + . + This package provides the server for the messaging service, which + maintains a location and subscription database for all the receiving + clients. All zephyrgrams are sent to the server to be routed to the + intended recipient. Only one server is required for a group of clients. + +Package: zephyr-server-krb +Section: net +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, debconf | debconf-2.0, libzephyr4-krb +Conflicts: zephyr-server, zephyr-server-krb5, zephyr-server-krb45 +Replaces: zephyr-server, zephyr-server-krb5, zephyr-server-krb45 +Provides: zephyr-server +Description: Project Athena's notification service - server with Kerberos + Zephyr is derived from the original Project Athena 'Instant Message' system + and allows users to send messages to other users or to groups of users. + Users can view incoming Zephyr messages as windowgrams (transient X + windows) or as text on a terminal. + . + This package provides the server for the messaging service. Only one + server is needed for a group of client. The program consumes much memory, + especially for very large sites. + . + The server maintains a location and subscription database for all the + receiving clients. All zephyrgrams are sent to the server to be routed + to the intended recipient. + . + This version of the server uses Kerberos. + +Package: zephyr-server-krb5 +Section: net +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, debconf | debconf-2.0, libzephyr4-krb5 +Conflicts: zephyr-server, zephyr-server-krb, zephyr-server-krb45 +Replaces: zephyr-server, zephyr-server-krb, zephyr-server-krb45 +Provides: zephyr-server +Description: The original "Instant Message" system-server with Kerberos 5 + You probably only need one server for a group of clients. + This can be a memory-intensive server, especially for very large sites. + . + The server maintains a location and subscription database for all the + receiving clients. All zephyrgrams are sent to the server to be routed + to the intended recipient. + . + This version of the server uses Kerberos for message authentication. + . + This is the Project Athena Zephyr notification system. + Zephyr allows users to send messages to other users or to groups of + users. Users can view incoming Zephyr messages as windowgrams + (transient X windows) or as text on a terminal. + +Package: zephyr-server-krb45 +Section: net +Architecture: any +Depends: ${shlibs:Depends}, ${misc:Depends}, debconf | debconf-2.0, libzephyr4-krb45 +Conflicts: zephyr-server, zephyr-server-krb, zephyr-server-krb5 +Replaces: zephyr-server, zephyr-server-krb, zephyr-server-krb5 +Provides: zephyr-server +Description: The original "Instant Message" system-server with Kerberos 4+5 + You probably only need one server for a group of clients. + This can be a memory-intensive server, especially for very large sites. + . + The server maintains a location and subscription database for all the + receiving clients. All zephyrgrams are sent to the server to be routed + to the intended recipient. + . + This version of the server uses Kerberos for message authentication. + . + This is the Project Athena Zephyr notification system. + Zephyr allows users to send messages to other users or to groups of + users. Users can view incoming Zephyr messages as windowgrams + (transient X windows) or as text on a terminal. + +Package: libzephyr-dev +Section: libdevel +Architecture: any +Depends: libzephyr4 (= ${binary:Version}) | libzephyr4-krb (= ${binary:Version}) | libzephyr4-krb5 (= ${binary:Version}) | libzephyr4-krb45 (= ${binary:Version}), ${misc:Depends}, libc6-dev +Description: Project Athena's notification service - development files + Zephyr is derived from the original Project Athena 'Instant Message' system + and allows users to send messages to other users or to groups of users. + Users can view incoming Zephyr messages as windowgrams (transient X + windows) or as text on a terminal. + . + This package provides development libraries and files, which are + needed to compile alternative Zephyr clients. diff --git a/debian/copyright b/debian/copyright new file mode 100644 index 0000000..245b261 --- /dev/null +++ b/debian/copyright @@ -0,0 +1,125 @@ +This package was debianized by Karl Ramm on +Mon, 4 Dec 2000 05:28:22 -0500. + +It was downloaded from ftp://athena-dist.mit.edu/pub/ATHENA/zephyr + +Copyright: + +/* + +Copyright 1987,1988,1995 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ +/* + * lib/quad_cksum.c + * + * Copyright 1985, 1986, 1987, 1988,1990 by the Massachusetts Institute + * of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + */ + +server/utf8proc.[ch]: +/* + * Copyright (c) 2006-2007 Jan Behrens, FlexiGuided GmbH, Berlin + * + * 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. + */ + +server/utf8proc_data.c: +/* + * This file contains derived data from a modified version of the + * Unicode data files. + * + * The original data files are available at + * http://www.unicode.org/Public/UNIDATA/ + * + * + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (c) 1991-2007 Unicode, Inc. All rights reserved. Distributed + * under the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do + * so, provided that (a) the above copyright notice(s) and this permission + * notice appear with all copies of the Data Files or Software, (b) both the + * above copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE 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 OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written + * authorization of the copyright holder. + */ + diff --git a/debian/default.subscriptions b/debian/default.subscriptions new file mode 100644 index 0000000..2ef3863 --- /dev/null +++ b/debian/default.subscriptions @@ -0,0 +1,3 @@ +operations,message,* +message,personal,%me% +message,urgent,%me% diff --git a/debian/dirs b/debian/dirs new file mode 100644 index 0000000..ca882bb --- /dev/null +++ b/debian/dirs @@ -0,0 +1,2 @@ +usr/bin +usr/sbin diff --git a/debian/libzephyr-dev.files b/debian/libzephyr-dev.files new file mode 100644 index 0000000..d5513c1 --- /dev/null +++ b/debian/libzephyr-dev.files @@ -0,0 +1,6 @@ +usr/lib/libzephyr.a +usr/lib/libzephyr.so +usr/lib/pkgconfig/zephyr.pc +usr/include/zephyr/mit-copyright.h +usr/include/zephyr/zephyr.h +usr/include/zephyr/zephyr_err.h diff --git a/debian/libzephyr-python.files b/debian/libzephyr-python.files new file mode 100644 index 0000000..4188d73 --- /dev/null +++ b/debian/libzephyr-python.files @@ -0,0 +1 @@ +usr/lib/python2.5/site-packages/zephyr_ctypes.py diff --git a/debian/libzephyr4-krb5.templates b/debian/libzephyr4-krb5.templates new file mode 100644 index 0000000..cf97f10 --- /dev/null +++ b/debian/libzephyr4-krb5.templates @@ -0,0 +1,15 @@ +Template: libzephyr4-krb5/no-more-krb4 +Type: boolean +Default: true +Description: Potentially incompatible upgrade + You appear to be upgrading from a version of zephyr that uses + Kerberos version 4 to authenticate. Kerberos version 4 support has + been removed from Debian, and accordingly from zephyr. This version + of zephyr uses Kerberos 5 to authenticate, and thus your servers must + have been upgraded for it to be useful. + . + A server that authenticates both ways can be built for lenny from the + zephyr source package, see: + /usr/share/doc/libzephyr4-krb5/README.krb4-5 + . + Continue with the upgrade? diff --git a/debian/libzephyr4.files b/debian/libzephyr4.files new file mode 100644 index 0000000..a837249 --- /dev/null +++ b/debian/libzephyr4.files @@ -0,0 +1 @@ +usr/lib/libzephyr.so.* diff --git a/debian/po/POTFILES.in b/debian/po/POTFILES.in new file mode 100644 index 0000000..8713a70 --- /dev/null +++ b/debian/po/POTFILES.in @@ -0,0 +1,2 @@ +[type: gettext/rfc822deb] zephyr-clients.templates +[type: gettext/rfc822deb] zephyr-server.templates diff --git a/debian/po/cs.po b/debian/po/cs.po new file mode 100644 index 0000000..56ad2b1 --- /dev/null +++ b/debian/po/cs.po @@ -0,0 +1,91 @@ +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-08 17:00+0100\n" +"Last-Translator: Miroslav Kure \n" +"Language-Team: Czech \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Zephyr servery:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Zadejte prosím plná jména Zephyr serverů; jednotlivá jména oddÄ›lte mezerami." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"Seznam definovaný na klientech může být podmnožinou seznamu definovaného na " +"serverech." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Pokud pro oznamování Zephyr serverů používáte Hesiod, můžete ponechat " +"prázdné." + +#~ msgid "" +#~ "We want to try and capture user changes when they edit a config file " +#~ "manually. To do this we look at the file in the config script. However, " +#~ "in the case of preconfigure, the config script is run twice before the " +#~ "postinst is run. Thus we may read the wrong value before the edited " +#~ "value is written out in postinst. If this is false we skip reading config " +#~ "files until postinst runs." +#~ msgstr "" +#~ "Snažíme se rozpoznat a zachytit uživatelovy ruÄní zmÄ›ny v konfiguraÄním " +#~ "souboru, což se dÄ›je v konfiguraÄním skriptu. OvÅ¡em v případÄ› " +#~ "pÅ™edkonfigurace je konfiguraÄní skript spuÅ¡tÄ›n dvakrát pÅ™ed spuÅ¡tÄ›ním " +#~ "poinstalaÄního skriptu a tudíž můžeme pÅ™eÄíst chybnou hodnotu pÅ™ed tím, " +#~ "než je upravená hodnota zapsána v poinstalaÄním kroku. Pokud je to " +#~ "chybnÄ›, pÅ™eskoÄíme Ätení kofiguraÄních souborů až do poinstalaÄní fáze." + +#~ msgid "You have no zephyr servers specified for the client" +#~ msgstr "Pro klienta jste nezadali žádné zephyr servery" + +#~ msgid "" +#~ "The zephyr-clients package for whatever reason does not have any zephyr " +#~ "servers configured. Please edit the file /etc/default/zephyr-clients and " +#~ "add the names of your zephyr servers, separated by spaces to the zhm_args " +#~ "variable." +#~ msgstr "" +#~ "BalíÄek zephyr-clients nemá z nÄ›jakého důvodu nakonfigurován žádný zephyr " +#~ "server. Upravte prosím soubor /etc/default/zephyr-clients a pÅ™idejte do " +#~ "nÄ›j do promÄ›nné zhm_args mezerami oddÄ›lená jména zephyr serverů." + +#~ msgid "What are your zephyr servers?" +#~ msgstr "Jaké jsou vaÅ¡e zephyr servery?" + +#~ msgid "You should never see this" +#~ msgstr "Toto jste nikdy nemÄ›li vidÄ›t" diff --git a/debian/po/es.po b/debian/po/es.po new file mode 100644 index 0000000..2a22e1e --- /dev/null +++ b/debian/po/es.po @@ -0,0 +1,65 @@ +# zephyr debconf translation to spanish +# Copyright (C) 2001, 2006, 2007 Software in the Public Interest +# This file is distributed under the same license as the zephyr package. +# +# Changes: +# - Initial translation +# Carlos Valdivia Yagüe , 2001, 2006, 2007 +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr 2.1.20070719.SNAPSHOT-4\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-05 15:50+0100\n" +"Last-Translator: Carlos Valdivia Yagüe \n" +"Language-Team: Debian L10n Spanish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Servidores Zephyr:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Por favor, introduzca el nombre completo de los servidores Zephyr como una " +"lista separada por espacios." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"La lista configurada en los clientes puede ser un subconjunto de la lista " +"configurada en los servidores." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Puede dejarlo en blanco si se utiliza Hesiod para anunciar los servidores " +"Zephyr." diff --git a/debian/po/fr.po b/debian/po/fr.po new file mode 100644 index 0000000..e54aa6d --- /dev/null +++ b/debian/po/fr.po @@ -0,0 +1,56 @@ +# translation of fr.po to French +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans# +# Developers do not need to manually edit POT or PO files. +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr_2.1.20070913.SNAPSHOT-3\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-23 15:01+0100\n" +"Last-Translator: Michel Grentzinger \n" +"Language-Team: French \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Serveurs Zephyr :" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Veuillez indiquer le nom complet des serveurs Zephyr, séparés par un espace." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"La liste configurée sur les clients peut être un sous-ensemble de la liste " +"configurée sur les serveurs." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Ce champ peut être laissé vide si Hesiod est employé pour annoncer les " +"serveurs Zephyr." diff --git a/debian/po/gl.po b/debian/po/gl.po new file mode 100644 index 0000000..92d393f --- /dev/null +++ b/debian/po/gl.po @@ -0,0 +1,100 @@ +# Galician translation of zephyr's debconf templates +# This file is distributed under the same license as the zephyr package. +# Jacobo Tarrio , 2007. +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-05 20:45+0000\n" +"Last-Translator: Jacobo Tarrio \n" +"Language-Team: Galician \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Servidores zephyr:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Indique os nomes completos dos servidores Zephyr, nunha lista de nomes " +"separados por comas." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"A lista configurada nos clientes pode ser un subconxunto da lista " +"configurada nos servidores." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Pódese deixar baleiro se se emprega Hesiod para anunciar os servidores " +"Zephyr." + +#, fuzzy +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(note that this can be a subset of what you're telling the servers) If " +#~ "you are using hesiod to advertise your zephyr servers, leave this blank." +#~ msgstr "" +#~ "Escriba os nomes completos dos seus servidores zephyr, separados por " +#~ "espazos. (Teña en conta que isto pode ser un subconxunto do que lles " +#~ "conta aos servidores)" + +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(Note that this can be a superset of that you're telling the clients.)" +#~ msgstr "" +#~ "Escriba os nomes completos dos seus servidores zephyr, separados por " +#~ "espazos. (Teña en conta que pode ser un superconxunto do que lles di aos " +#~ "clientes)." + +#~ msgid "for internal use" +#~ msgstr "para uso interno" + +#~ msgid "" +#~ "We want to try and capture user changes when they edit a config file " +#~ "manually. To do this we look at the file in the config script. However, " +#~ "in the case of preconfigure, the config script is run twice before the " +#~ "postinst is run. Thus we may read the wrong value before the edited " +#~ "value is written out in postinst. If this is false we skip reading config " +#~ "files until postinst runs." +#~ msgstr "" +#~ "Preténdes capturar os cambios que fan os usuarios cando modifican " +#~ "manualmente un ficheiro de configuración. Para facelo consúltase o " +#~ "ficheiro no script de configuración. Nembargantes, no caso da " +#~ "preconfiguración, o script de configuración execútase dúas veces antes de " +#~ "executar o script de post-instalación. Polo tanto, pódese ler o valor " +#~ "incorrecto antes de que se grave o valor editado na post-instalación. Se " +#~ "isto é falso omítese a lectura de ficheiros de configuración ata que se " +#~ "execute o script de post-instalación." + +#~ msgid "You have no zephyr servers specified for the client" +#~ msgstr "Non especificou servidores zephyr para o cliente" + +#~ msgid "" +#~ "The zephyr-clients package for whatever reason does not have any zephyr " +#~ "servers configured. Please edit the file /etc/default/zephyr-clients and " +#~ "add the names of your zephyr servers, separated by spaces to the zhm_args " +#~ "variable." +#~ msgstr "" +#~ "Por algún motivo, o paquete zephyr-clients non ten configurado ningún " +#~ "servidor zephyr. Edite o ficheiro /etc/default/zephyr-clients e engada os " +#~ "nomes dos servidores zephyr, separados por espazos, á variable zhm_args." diff --git a/debian/po/ja.po b/debian/po/ja.po new file mode 100644 index 0000000..3ddbf45 --- /dev/null +++ b/debian/po/ja.po @@ -0,0 +1,45 @@ +# Copyright (C) 2008 Karl Ramm +# This file is distributed under the same license as the zephyr package. +# Hideki Yamane (Debian-JP) , 2008. +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr 2.1.20070719.SNAPSHOT-1.2\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2008-12-28 22:26+0900\n" +"Last-Translator: Hideki Yamane (Debian-JP) \n" +"Language-Team: Japanese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Zephyr サーãƒ:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Zephyr サーãƒã®åå‰ã‚’å…¨ã¦ã€ã‚¹ãƒšãƒ¼ã‚¹ã§åŒºåˆ‡ã£ãŸãƒªã‚¹ãƒˆã§æŒ‡å®šã—ã¦ãã ã•ã„。" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"クライアント上ã§è¨­å®šã•れãŸãƒªã‚¹ãƒˆã¯ã€ã‚µãƒ¼ãƒä¸Šã§è¨­å®šã•れãŸãƒªã‚¹ãƒˆã®ã‚µãƒ–セットã«ãªã‚Šã¾ã™ã€‚" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "Hesiod ã‚’ Zephyr サーãƒã®åºƒå ±ã«åˆ©ç”¨ã—ã¦ã„ã‚‹å ´åˆã¯ã€ã“ã“ã¯ç©ºã®ã¾ã¾ã§æ§‹ã„ã¾ã›ã‚“。" diff --git a/debian/po/nl.po b/debian/po/nl.po new file mode 100644 index 0000000..cadb04c --- /dev/null +++ b/debian/po/nl.po @@ -0,0 +1,112 @@ +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-09 14:00+0100\n" +"Last-Translator: Bart Cornelis \n" +"Language-Team: debian-l10n-dutch \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=utf-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Poedit-Language: Dutch\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Zephyr-servers:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Gelieve hier een (met spaties gescheiden) lijst van de de volledige namen " +"van de Zephyr-servers op te geven." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"De op de clients ingestelde lijst mag een subset zijn van de op de servers " +"ingestelde lijst." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Als u Hesiod gebruikt om Zephyr-servers te adverteren kunt u dit veld " +"leeglaten." + +#, fuzzy +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(note that this can be a subset of what you're telling the servers) If " +#~ "you are using hesiod to advertise your zephyr servers, leave this blank." +#~ msgstr "" +#~ "Gelieve de volledige naam van uw zephyr-servers op te geven gescheiden " +#~ "door spaties (merk op dat dit een subset kan zijn van wat u aan de " +#~ "servers vertelt)." + +#, fuzzy +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(Note that this can be a superset of that you're telling the clients.)" +#~ msgstr "" +#~ "Gelieve de volledige namen van uw zephyr-servers op te geven, gescheiden " +#~ "door spaties (merk op dat dit een superset kan zijn van wat u de clients " +#~ "verteld)." + +#~ msgid "for internal use" +#~ msgstr "voor intern gebruik" + +#~ msgid "" +#~ "We want to try and capture user changes when they edit a config file " +#~ "manually. To do this we look at the file in the config script. However, " +#~ "in the case of preconfigure, the config script is run twice before the " +#~ "postinst is run. Thus we may read the wrong value before the edited " +#~ "value is written out in postinst. If this is false we skip reading config " +#~ "files until postinst runs." +#~ msgstr "" +#~ "Er wordt geprobeerd om gebruikersaanpassingen op te vangen wanneer een " +#~ "configuratiebestand handmatig aangepast wordt. Hiertoe kijkt het " +#~ "'config'-script in het configuratiebestand, maar in het geval van " +#~ "preconfigure wordt dit script tweemaal uitgevoerd voordat het 'postinst'-" +#~ "script gedraaid wordt. Dit kan er toe leiden dat de verkeerde waarde " +#~ "wordt uitgeschreven voordat de aangepaste waarde uitgeschreven wordt in " +#~ "het 'postinst'-script. Als dit onwaar is slaan we het lezen van " +#~ "configuratiebestanden over totdat het 'postinst'-script uitgevoerd is." + +#~ msgid "You have no zephyr servers specified for the client" +#~ msgstr "U heeft geen zephyr-servers opgegeven voor de client." + +#~ msgid "" +#~ "The zephyr-clients package for whatever reason does not have any zephyr " +#~ "servers configured. Please edit the file /etc/default/zephyr-clients and " +#~ "add the names of your zephyr servers, separated by spaces to the zhm_args " +#~ "variable." +#~ msgstr "" +#~ "Het 'zephyr-clients'-pakket heeft om wat voor reden dan ook geen zephyr-" +#~ "servers ingesteld. Gelieve het bestand /etc/default/zephyr-clients aan te " +#~ "passen en de namen van uw zephyr-servers gescheiden door spaties toe te " +#~ "voegen aan de 'zhm_args'-variabele." diff --git a/debian/po/pt.po b/debian/po/pt.po new file mode 100644 index 0000000..70aba7e --- /dev/null +++ b/debian/po/pt.po @@ -0,0 +1,98 @@ +# Portuguese translation for zephyr's debconf messages +# Ricardo Silva , 2007 +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr 2.1.20070719.SNAPSHOT-3\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-19 22:05+0000\n" +"Last-Translator: Ricardo Silva \n" +"Language-Team: Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Servidores Zephyr:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Por favor especifique o nome completo dos servidores Zephyr, numa lista " +"separada por espaços." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"A lista configurada nos clientes pode ser um sub-conjunto da lista " +"configurada nos servidores." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Esta opção pode ser deixada vazia se o Hesiod for utilizado para anunciar os " +"servidores Zephyr." + +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(note that this can be a subset of what you're telling the servers) If " +#~ "you are using hesiod to advertise your zephyr servers, leave this blank." +#~ msgstr "" +#~ "Por favor escreva os nomes completos dos seus servidores zephyr, " +#~ "separados por espaços. (note que esta lista pode ser um subconjunto do " +#~ "que diz aos servidores)" + +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(Note that this can be a superset of that you're telling the clients.)" +#~ msgstr "" +#~ "Por favor escreva os nomes completos dos seus servidores zephyr, " +#~ "separados por espaços. (Note que esta lista pode ser um super-conjunto " +#~ "do que diz aos clientes.)" + +#~ msgid "for internal use" +#~ msgstr "para uso interno" + +#~ msgid "" +#~ "We want to try and capture user changes when they edit a config file " +#~ "manually. To do this we look at the file in the config script. However, " +#~ "in the case of preconfigure, the config script is run twice before the " +#~ "postinst is run. Thus we may read the wrong value before the edited " +#~ "value is written out in postinst. If this is false we skip reading config " +#~ "files until postinst runs." +#~ msgstr "" +#~ "Tentamos determinar que alterações os utilizadores fazem quando editam " +#~ "um ficheiro de configuração manualmente. Para tal analisamos o ficheiro " +#~ "no script de configuração. No entanto quando há pré-configuração, o " +#~ "script de configuração é corrido duas vezes antes do pós-instalaçÃ" +#~ "£o. Assim podemos ler os valores errados antes que o valor editado seja " +#~ "escrito no pós-instalação. Se esta opção for falsa não analisamos " +#~ "os ficheiros de configuração até que o pós-instalação corra." + +#~ msgid "You have no zephyr servers specified for the client" +#~ msgstr "Não tem nenhum servidor zephyr especificado para o cliente" + +#~ msgid "" +#~ "The zephyr-clients package for whatever reason does not have any zephyr " +#~ "servers configured. Please edit the file /etc/default/zephyr-clients and " +#~ "add the names of your zephyr servers, separated by spaces to the zhm_args " +#~ "variable." +#~ msgstr "" +#~ "O pacote zephyr-clients por alguma razão não tem nenhum servidor zephyr " +#~ "configurado. Por favor edite o ficheiro /etc/default/zephyr-clients e " +#~ "adicione os nomes dos seus servidores zephyr, separados por espaços à " +#~ "variável zhm_args." diff --git a/debian/po/pt_BR.po b/debian/po/pt_BR.po new file mode 100644 index 0000000..915ba1d --- /dev/null +++ b/debian/po/pt_BR.po @@ -0,0 +1,111 @@ +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# Developers do not need to manually edit POT or PO files. +# +# +# +msgid "" +msgstr "" +"Project-Id-Version: zephyr 2.1\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2008-10-06 02:33-0300\n" +"Last-Translator: Felipe Augusto van de Wiel (faw) \n" +"Language-Team: Brazilian Portuguese \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"pt_BR\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Servidores Zephyr:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" +"Por favor, especifique os nomes completos dos servidores Zephyr, use uma " +"lista separada por espaços." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"A lista configurada nos clientes pode ser um subconjunto da lista " +"configurada nos servidores." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"É possível deixar este campo vazio se o Hesiod for usado para anunciar os " +"servidores Zephyr." + +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(note that this can be a subset of what you're telling the servers) If " +#~ "you are using hesiod to advertise your zephyr servers, leave this blank." +#~ msgstr "" +#~ "Por favor digite o nome completo dos seus servidores zephyr, separado por " +#~ "espaços. (note que isso pode ser um subconjunto daquilo que você está " +#~ "dizendo aos servidores)" + +#~ msgid "" +#~ "Please type the full names of your zephyr servers, separated by spaces. " +#~ "(Note that this can be a superset of that you're telling the clients.)" +#~ msgstr "" +#~ "Por favor digite os nomes completos de seus servidores zephyr, separado " +#~ "por espaços. (Note que isso pode ser um subconjunto daquilo que você está " +#~ "dizendo aos clientes.)" + +#~ msgid "" +#~ "We want to try and capture user changes when they edit a config file " +#~ "manually. To do this we look at the file in the config script. However, " +#~ "in the case of preconfigure, the config script is run twice before the " +#~ "postinst is run. Thus we may read the wrong value before the edited " +#~ "value is written out in postinst. If this is false we skip reading config " +#~ "files until postinst runs." +#~ msgstr "" +#~ "Nós queremos tentar e capturar mudanças de usuários quando eles editam um " +#~ "arquivo de configuração manualmente. Para fazer isso nós olhamos no " +#~ "arquivo do script de configuração. De qualquer forma, no caso de pré-" +#~ "configuração, o script de configuração é executado duas vezes antes do " +#~ "\"postinst\" ser executado. Se isso for falso nós continuamos lendo os " +#~ "arquivos de configuração até que o \"postinst\" seja executado." + +#~ msgid "You have no zephyr servers specified for the client" +#~ msgstr "Você não tem servidores zephyr especificados para o cliente" + +#~ msgid "" +#~ "The zephyr-clients package for whatever reason does not have any zephyr " +#~ "servers configured. Please edit the file /etc/default/zephyr-clients and " +#~ "add the names of your zephyr servers, separated by spaces to the zhm_args " +#~ "variable." +#~ msgstr "" +#~ "Por uma razão qualquer o pacote zephyr-clients não possui qualquer " +#~ "servidor zephyr configurado. Por favor edite o arquivo /etc/default/" +#~ "zephyr-clients e adicione os nomes dos seus servidores zephyr, separado " +#~ "por espaços na variável zhm_args." + +#~ msgid "What are your zephyr servers?" +#~ msgstr "Quais são os seus servidores zephyr?" + +#~ msgid "You should never see this" +#~ msgstr "Você nunca deveria ter visto isso" diff --git a/debian/po/ru.po b/debian/po/ru.po new file mode 100644 index 0000000..03a1bf7 --- /dev/null +++ b/debian/po/ru.po @@ -0,0 +1,61 @@ +# translation of ru.po to Russian +# +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# +# Developers do not need to manually edit POT or PO files. +# +# Unknown, 2003,. +# Yuri Kozlov , 2006, 2007. +msgid "" +msgstr "" +"Project-Id-Version: 2.1.20070719.SNAPSHOT-3\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2007-12-19 20:35+0300\n" +"Last-Translator: Yuri Kozlov \n" +"Language-Team: Russian \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%" +"10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Серверы Zephyr:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "Введите ÑпиÑок полных имён Ñерверов Zephyr через пробел." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"Ðа клиентах можно указывать подмножеÑтво ÑпиÑка, наÑтроенного на Ñерверах." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Можно ничего не вводить, еÑли Ð´Ð»Ñ Ð¾Ð±ÑŠÑÐ²Ð»ÐµÐ½Ð¸Ñ Ñерверов Zephyr иÑпользуетÑÑ " +"Hesiod." diff --git a/debian/po/sv.po b/debian/po/sv.po new file mode 100644 index 0000000..4631f5c --- /dev/null +++ b/debian/po/sv.po @@ -0,0 +1,57 @@ +# translation of zephyr_2.1.20070719.SNAPSHOT-1.1_sv.po to Swedish +# Translators, if you are not familiar with the PO format, gettext +# documentation is worth reading, especially sections dedicated to +# this format, e.g. by running: +# info -n '(gettext)PO Files' +# info -n '(gettext)Header Entry' +# Some information specific to po-debconf are available at +# /usr/share/doc/po-debconf/README-trans +# or http://www.debian.org/intl/l10n/po-debconf/README-trans +# Developers do not need to manually edit POT or PO files. +# +# Martin Ågren , 2008. +msgid "" +msgstr "" +"Project-Id-Version: zephyr_2.1.20070719.SNAPSHOT-1.1_sv\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: 2008-07-20 10:41+0200\n" +"Last-Translator: Martin Ågren \n" +"Language-Team: Swedish \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Generator: KBabel 1.11.4\n" +"Plural-Forms: nplurals=2; plural=(n != 1);\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "Zephyr-servrar:" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "Ange hela namnen på Zephyr-servrarna som en blankstegsseparerad lista." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" +"Den lista som konfigureras på klienter kan vara en delmängd av listan som " +"konfigureras på servrar." + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" +"Detta fält kan lämnas tomt om Hesiod används för att tillkännage Zephyr-" +"servrar." diff --git a/debian/po/templates.pot b/debian/po/templates.pot new file mode 100644 index 0000000..90619b2 --- /dev/null +++ b/debian/po/templates.pot @@ -0,0 +1,45 @@ +# SOME DESCRIPTIVE TITLE. +# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER +# This file is distributed under the same license as the PACKAGE package. +# FIRST AUTHOR , YEAR. +# +#, fuzzy +msgid "" +msgstr "" +"Project-Id-Version: PACKAGE VERSION\n" +"Report-Msgid-Bugs-To: Source: zephyr@packages.debian.org\n" +"POT-Creation-Date: 2007-12-05 09:47+0530\n" +"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" +"Last-Translator: FULL NAME \n" +"Language-Team: LANGUAGE \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=CHARSET\n" +"Content-Transfer-Encoding: 8bit\n" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "Zephyr servers:" +msgstr "" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"Please specify the full names of the Zephyr servers, as a space-separated " +"list." +msgstr "" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 ../zephyr-server.templates:2001 +msgid "" +"The list configured on clients can be a subset of the list configured on " +"servers." +msgstr "" + +#. Type: string +#. Description +#: ../zephyr-clients.templates:2001 +msgid "This can be left empty if Hesiod is used to advertise Zephyr servers." +msgstr "" diff --git a/debian/rules b/debian/rules new file mode 100755 index 0000000..8f575bb --- /dev/null +++ b/debian/rules @@ -0,0 +1,177 @@ +#!/usr/bin/make -f +# Sample debian/rules that uses debhelper. +# GNU copyright 1997 by Joey Hess. +# +# This version is for a hypothetical package that builds an +# architecture-dependant package, as well as an architecture-independent +# package. + +# Uncomment this to turn on verbose mode. +#export DH_VERBOSE=1 +VARIETALS=krb5 +#VARIETALS=krb krb45 krb5 + +PACKAGES:=-plibzephyr4 -pzephyr-clients -pzephyr-server -plibzephyr-dev -plibzephyr-python $(foreach i,$(VARIETALS),-plibzephyr4-$(i) -pzephyr-server-$(i)) + +# This has to be exported to make some magic below work. +export DH_OPTIONS +CONFIGURE_ROOT=--prefix=/usr --mandir=\$${prefix}/share/man \ + --infodir=\$${prefix}/share/info --sysconfdir=/etc --datadir=/etc \ + --with-cares=/usr --with-hesiod=/usr --enable-cmu-zwgcplus +CONFIGURE_krb5=--with-krb5=/usr +CONFIGURE_krb45=--with-krb4=/usr --with-krb5=/usr +CONFIGURE_krb=--with-krb4=/usr +CONFIGURE_no-krb= +CFLAGS=-g -O +CHECK= + +# see /usr/share/doc/autotools-dev/README.Debian.gz +export DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE) +export DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE) + +# FOR AUTOCONF 2.52 AND NEWER ONLY +ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE)) + CONFIGURE_ROOT += --build $(DEB_HOST_GNU_TYPE) +else + CONFIGURE_ROOT += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE) +endif + +BUILD_VARIETALS=$(VARIETALS) no-krb + +configure: configure-stamp +configure-stamp: + dh_testdir + # Add here commands to configure the package. + libtoolize + aclocal + automake -a || true # we only want this for install-sh + autoreconf + mkdir -p $(BUILD_VARIETALS) + $(foreach VARIETY,$(BUILD_VARIETALS),(cd $(VARIETY) && CFLAGS="$(CFLAGS)" ../configure $(CONFIGURE_$(VARIETY)) $(CONFIGURE_ROOT));) + touch configure-stamp + +build-arch: build-stamp +build-indep: build-stamp +build: build-stamp +build-stamp: configure-stamp + dh_testdir + + # Add here commands to compile the package. + set -e; \ + for dir in $(VARIETALS) ; do \ + $(MAKE) -C $$dir h/zephyr_version.h; $(MAKE) -C $$dir/lib all $(CHECK); $(MAKE) -C $$dir/server; \ + done + $(MAKE) -C no-krb all $(CHECK) + + touch build-stamp + +clean: + dh_testdir + dh_testroot + -rm -f build-stamp configure-stamp + + # Add here commands to clean up after the build process. + -rm -rf autom4te.cache m4 + -rm aclocal.m4 config.guess config.sub configure h/config.h.in \ + install-sh ltmain.sh + -rm -rf $(VARIETALS) no-krb debian/tmp-krb* + -rm debian/zephyr-server-krb.files + -rm debian/zephyr-server-krb.templates + -rm debian/zephyr-server-krb.config + -rm debian/zephyr-server-krb.postinst + -rm debian/zephyr-server-krb5.README.Debian \ + debian/zephyr-server-krb5.docs debian/zephyr-server-krb5.files \ + debian/zephyr-server-krb5.postinst debian/zephyr-server-krb5.postrm \ + debian/zephyr-server-krb5.templates + -rm debian/zephyr-server-krb45.* + -rm debian/libzephyr4-krb.files debian/libzephyr4-krb5.files \ + debian/libzephyr4-krb45.files + + dh_clean -XTAGS + +install: DH_OPTIONS= +install: build + dh_testdir + dh_testroot + dh_prep -XTAGS + -rm -rf debian/tmp-krb* + dh_installdirs + + # Add here commands to install the package into debian/tmp. + $(MAKE) -C no-krb DESTDIR=$(CURDIR)/debian/tmp install + for dir in $(VARIETALS); do \ + $(MAKE) -C $$dir SUBDIRS="lib server" DESTDIR=$(CURDIR)/debian/tmp-$$dir install; \ + done + mkdir -p debian/tmp/etc/zephyr/acl + set -x; for i in debian/acl/*; do install -c -m 644 -o root $$i debian/tmp/etc/zephyr/acl; done; set +x + install -c -m 644 debian/zephyr.vars debian/tmp/etc/zephyr + install -c -m 644 debian/default.subscriptions debian/tmp/etc/zephyr + for dir in $(VARIETALS); do \ + cp -rp debian/tmp/etc/zephyr/acl debian/tmp-$$dir/etc/zephyr; \ + done + mkdir -p debian/tmp/usr/lib/python2.5/site-packages + install -c -m 644 python/zephyr_ctypes.py debian/tmp/usr/lib/python2.5/site-packages + +# Build architecture-independent files here. +# Pass -i to all debhelper commands in this target to reduce clutter. +binary-indep: build install + +# Build architecture-dependent files here. +# Pass -a to all debhelper commands in this target to reduce clutter. +binary-arch: build install + dh_testdir + dh_testroot + set -e; \ + for file in files templates postinst docs; do \ + for dir in $(VARIETALS); do \ + cp debian/zephyr-server.$$file debian/zephyr-server-$$dir.$$file; \ + done; \ + done + for file in config init; do \ + for dir in $(filter-out krb5,$(VARIETALS)); do \ + cp debian/zephyr-server.$$file debian/zephyr-server-$$dir.$$file; \ + done; \ + done + for file in README.Debian docs postrm; do \ + for dir in $(filter-out krb,$(VARIETALS)); do \ + cp debian/zephyr-server-krb.$$file debian/zephyr-server-$$dir.$$file; \ + done; \ + done + for dir in $(VARIETALS); do \ + cp debian/libzephyr4.files debian/libzephyr4-$$dir.files; \ + done + dh_movefiles -plibzephyr4 -pzephyr-clients -pzephyr-server -plibzephyr-dev -plibzephyr-python + for dir in $(VARIETALS); do \ + dh_movefiles --sourcedir=debian/tmp-$$dir -plibzephyr4-$$dir -pzephyr-server-$$dir; \ + done + dh_installdebconf + dh_installdocs + dh_installinit -pzephyr-clients --init-script=zhm --no-start + dh_installinit -pzephyr-server --init-script=zephyrd + for dir in $(VARIETALS); do \ + dh_installinit -pzephyr-server-$$dir --init-script=zephyrd; \ + done + dh_installchangelogs + dh_pycentral -plibzephyr-python + dh_python -plibzephyr-python + dh_strip + dh_compress + dh_fixperms + dh_makeshlibs + # sigh + for dir in $(VARIETALS); do \ + cp debian/libzephyr4/DEBIAN/shlibs debian/libzephyr4-$$dir/DEBIAN/shlibs; \ + done + dh_shlibdeps $(PACKAGES) + dh_installdeb $(PACKAGES) + dh_gencontrol $(PACKAGES) + dh_md5sums $(PACKAGES) + dh_builddeb $(PACKAGES) + for dir in $(VARIETALS); do \ + dh_builddeb --sourcedir=debian/tmp-$$dir -plibzephyr4-$$dir -pzephyr-server-$$dir; \ + done + + +binary: binary-indep binary-arch + +.PHONY: build clean binary-indep binary-arch binary install diff --git a/debian/zephyr-clients.config b/debian/zephyr-clients.config new file mode 100644 index 0000000..9c2c62f --- /dev/null +++ b/debian/zephyr-clients.config @@ -0,0 +1,42 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule +db_version 2.0 + +db_get zephyr-clients/servers || true +if test -z "$RET" +then + # If there's an /etc/zephyr/server.list file lying around, read it + if test -f /etc/zephyr/server.list + then + z="`cat /etc/zephyr/server.list`" + + if test -n "$z" + then + db_set zephyr-clients/servers "`echo $z`" + fi + else + # if there happens to be zephyr server decconf on this machine, + # see what its debconf knows about zephyr servers... + if db_get zephyr-server/servers && test -n "$RET" + then + db_set zephyr-clients/servers $RET + fi + fi +fi + +db_get zephyr-clients/read_conf +if test -f /etc/default/zephyr-clients -a \( "$RET" = true \) +then + zhm_args="" + . /etc/default/zephyr-clients + if test -n "$zhm_args" + then + db_set zephyr-clients/read_conf false + db_set zephyr-clients/servers "$zhm_args" + fi +fi + +db_input high zephyr-clients/servers || true + +db_go || true diff --git a/debian/zephyr-clients.docs b/debian/zephyr-clients.docs new file mode 100644 index 0000000..a70b3c8 --- /dev/null +++ b/debian/zephyr-clients.docs @@ -0,0 +1 @@ +USING diff --git a/debian/zephyr-clients.files b/debian/zephyr-clients.files new file mode 100644 index 0000000..238bb10 --- /dev/null +++ b/debian/zephyr-clients.files @@ -0,0 +1,24 @@ +usr/bin/zaway +usr/bin/zctl +usr/bin/zleave +usr/bin/zlocate +usr/bin/znol +usr/bin/zstat +usr/bin/zwrite +usr/bin/zwgc +usr/sbin/zshutdown_notify +usr/sbin/zhm +usr/share/man/man1/zephyr.1 +usr/share/man/man1/zaway.1 +usr/share/man/man1/zctl.1 +usr/share/man/man1/zleave.1 +usr/share/man/man1/zlocate.1 +usr/share/man/man1/znol.1 +usr/share/man/man1/zwrite.1 +usr/share/man/man1/zwgc.1 +usr/share/man/man8/zshutdown_notify.8 +usr/share/man/man8/zstat.8 +usr/share/man/man8/zhm.8 +etc/zephyr/zwgc.desc +etc/zephyr/zwgc_resources +etc/zephyr/zephyr.vars diff --git a/debian/zephyr-clients.init b/debian/zephyr-clients.init new file mode 100644 index 0000000..1665e1a --- /dev/null +++ b/debian/zephyr-clients.init @@ -0,0 +1,74 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# +# Version: @(#)skeleton 1.8 03-Mar-1998 miquels@cistron.nl +# +# This file was automatically customized by dh-make on Mon, 4 Dec 2000 05:28:22 -0500 + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/zhm +NAME=zhm +DESC="zephyr host manager" + +test -f $DAEMON || exit 0 + +set -e + +if test -f /etc/default/zephyr-clients +then + . /etc/default/zephyr-clients +fi + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --pidfile /var/run/$NAME.pid \ + --exec $DAEMON -- $zhm_args + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --oknodo --stop --quiet --pidfile /var/run/$NAME.pid \ + --name $NAME + echo "$NAME."- + ;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + start-stop-daemon --oknodo --stop --retry 5 --quiet --pidfile \ + /var/run/$NAME.pid --name $NAME + start-stop-daemon --start --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON -- -N $zhm_args + echo "$NAME." + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 + +### BEGIN INIT INFO +# Provides: zhm +# Required-Start: $syslog $network $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the zephyr host manager daemon. +# Description: Start the zephyr host manager daemon. +### END INIT INFO + diff --git a/debian/zephyr-clients.postinst b/debian/zephyr-clients.postinst new file mode 100644 index 0000000..e358728 --- /dev/null +++ b/debian/zephyr-clients.postinst @@ -0,0 +1,84 @@ +#! /bin/sh +# postinst script for zephyr +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see /usr/share/doc/packaging-manual/ +# +# quoting from the policy: +# Any necessary prompting should almost always be confined to the +# post-installation script, and should be protected with a conditional +# so that unnecessary prompting doesn't happen if a package's +# installation fails and the `postinst' is called with `abort-upgrade', +# `abort-remove' or `abort-deconfigure'. + +case "$1" in + configure) + + . /usr/share/debconf/confmodule + db_version 2.0 + + db_set zephyr-clients/read_conf true + + if test -f /etc/zephyr/zephyr.conf + then + if test ! -f /etc/default/zephyr-clients + then + mv /etc/zephyr/zephyr.conf /etc/default/zephyr-clients + fi + fi + + # if /etc/default/zephyr-clients already exists and has a zhm_args + # line, the config script should have sucked it into debconf + db_get zephyr-clients/servers || true + + tmpfile=/etc/default/zephyr-client.dpkg-new + if test -f /etc/default/zephyr-clients + then + grep -v ^zhm_args /etc/default/zephyr-clients > $tmpfile || true + else + cat > $tmpfile << EOF +# This file is automatically rewritten by the zephyr-clients post-install +# script. So treat it right. +EOF + fi + echo zhm_args=\"${RET}\" >> $tmpfile + cat $tmpfile > /etc/default/zephyr-clients + rm $tmpfile + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +if [ -x "/etc/init.d/zhm" ]; then + # this script does not necessarily fail if these do + if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then + invoke-rc.d zhm restart + else + /etc/init.d/zhm restart + fi +fi + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 diff --git a/debian/zephyr-clients.prerm b/debian/zephyr-clients.prerm new file mode 100644 index 0000000..69beaac --- /dev/null +++ b/debian/zephyr-clients.prerm @@ -0,0 +1,49 @@ +#! /bin/sh +# prerm script for zephyr-client +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `remove' +# * `upgrade' +# * `failed-upgrade' +# * `remove' `in-favour' +# * `deconfigure' `in-favour' +# `removing' +# +# for details, see /usr/share/doc/packaging-manual/ + +case "$1" in + deconfigure|remove) + rm /etc/default/zephyr-clients || true + ;; + upgrade) +# remove|upgrade|deconfigure) +# install-info --quiet --remove /usr/info/zephyr.info.gz + ;; + failed-upgrade) + ;; + *) + echo "prerm called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +if [ -x "/etc/init.d/zhm" ] && [ "$1" = remove ]; then + if [ -x "`which invoke-rc.d 2>/dev/null`" ]; then + invoke-rc.d zhm stop || exit $? + else + /etc/init.d/zhm stop || exit $? + fi +fi + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/zephyr-clients.templates b/debian/zephyr-clients.templates new file mode 100644 index 0000000..2d0d025 --- /dev/null +++ b/debian/zephyr-clients.templates @@ -0,0 +1,30 @@ +# These templates have been reviewed by the debian-l10n-english +# team +# +# If modifications/additions/rewording are needed, please ask +# debian-l10n-english@lists.debian.org for advice. +# +# Even minor modifications require translation updates and such +# changes should be coordinated with translators and reviewers. + +Template: zephyr-clients/servers +Type: string +_Description: Zephyr servers: + Please specify the full names of the Zephyr servers, as a + space-separated list. + . + The list configured on clients can be a subset of the list configured + on servers. + . + This can be left empty if Hesiod is used to advertise Zephyr servers. + +Template: zephyr-clients/read_conf +Type: boolean +Default: true +Description: for internal use + We want to try and capture user changes when they edit a config file + manually. To do this we look at the file in the config script. However, + in the case of preconfigure, the config script is run twice before the + postinst is run. Thus we may read the wrong value before the edited value + is written out in postinst. If this is false we skip reading config files + until postinst runs. diff --git a/debian/zephyr-server-krb.README.Debian b/debian/zephyr-server-krb.README.Debian new file mode 100644 index 0000000..4b03c1d --- /dev/null +++ b/debian/zephyr-server-krb.README.Debian @@ -0,0 +1,30 @@ +To run a zephyr server with MIT Kerberos support, you need to generate a +Kerberos IV srvtab for the principal zephyr.zephyr@YOUR.REALM.NAME. + +Doing this with the MIT Kerberos V server is a somewhat convoluted process, +but here we go: + +[Note that this presumes that you have Kerberos administrator privileges, if +you don't, find someone who does.] + +At the kadmin prompt, type + +ank -randkey zephyr/zephyr + +this creates the Kerberos principal, with whatever key types and cryptosystems +your realm defaults to. Next, also at the kadmin prompt, type the following +substituting appropriately for your realm name and various file locations: + +xst -k /tmp/keytab -e des-cbc-crc:v4 zephyr/zephyr@YOUR.REALM.NAME + +The key type is necessary because zephyr uses an older version of Kerberos +that used only single-DES. Now run ktutil: + +rkt /tmp/keytab +wst /etc/zephyr/srvtab +q + +You now want to make sure that the /tmp/keytab file is written-over and +removed. Fortunately, you have Kerberos, you have kdestroy. + +env KRB5CCNAME=/tmp/keytab kdestroy diff --git a/debian/zephyr-server-krb.docs b/debian/zephyr-server-krb.docs new file mode 100644 index 0000000..a3a5154 --- /dev/null +++ b/debian/zephyr-server-krb.docs @@ -0,0 +1 @@ +OPERATING diff --git a/debian/zephyr-server-krb.init b/debian/zephyr-server-krb.init new file mode 100644 index 0000000..f83ca92 --- /dev/null +++ b/debian/zephyr-server-krb.init @@ -0,0 +1,77 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# +# Version: @(#)skeleton 1.8 03-Mar-1998 miquels@cistron.nl +# +# This file was automatically customized by dh-make on Mon, 4 Dec 2000 05:28:22 -0500 + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/zephyrd +NAME=zephyrd +DESC="zephyr server" + +test -f $DAEMON || exit 0 + +set -e + +case "$1" in + start) + if test ! -f /etc/zephyr/srvtab + then + echo 'You need to get a srvtab before the kerberized zephyr server will function' + echo 'correctly. Get a srvtab for zephyr/zephyr and put it in /etc/zephyr/srvtab.' + exit 0 + fi + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --exec $DAEMON + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --oknodo --stop --quiet --exec $DAEMON + echo "$NAME." + ;; + restart) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + start-stop-daemon --oknodo --stop --quiet --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON -- $zhm_args + echo "$NAME." + ;; + reload|force-reload) + echo -n "Telling $NAME to reload..." + start-stop-daemon --stop --signal HUP --exec $DAEMON + echo done. + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + # echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 + +### BEGIN INIT INFO +# Provides: zephyrd +# Required-Start: $syslog $network $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the zephyr server. +# Description: Start the zephyr server. +### END INIT INFO diff --git a/debian/zephyr-server-krb.postrm b/debian/zephyr-server-krb.postrm new file mode 100644 index 0000000..95aa504 --- /dev/null +++ b/debian/zephyr-server-krb.postrm @@ -0,0 +1,9 @@ +#!/bin/sh -e + +if test "$1" = purge; then + rm -f /etc/zephyr/server.list +fi + +#DEBHELPER# + +exit 0 diff --git a/debian/zephyr-server-krb5.init b/debian/zephyr-server-krb5.init new file mode 100644 index 0000000..d48d01d --- /dev/null +++ b/debian/zephyr-server-krb5.init @@ -0,0 +1,78 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# +# Version: @(#)skeleton 1.8 03-Mar-1998 miquels@cistron.nl +# +# This file was automatically customized by dh-make on Mon, 4 Dec 2000 05:28:22 -0500 + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/zephyrd +NAME=zephyrd +DESC="zephyr server" + +test -f $DAEMON || exit 0 + +set -e + +case "$1" in + start) + if test ! -f /etc/zephyr/krb5.keytab + then + echo 'You need to get a keytab before the kerberized zephyr server will' + echo 'function correctly. Get a keytab for zephyr/zephyr and put it in' + echo 'the file "/etc/zephyr/krb5.keytab".' + exit 0 + fi + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --exec $DAEMON + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --oknodo --stop --quiet --exec $DAEMON + echo "$NAME." + ;; + restart) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + start-stop-daemon --oknodo --stop --quiet --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON -- $zhm_args + echo "$NAME." + ;; + reload|force-reload) + echo -n "Telling $NAME to reload..." + start-stop-daemon --stop --signal HUP --exec $DAEMON + echo done. + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + # echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 + +### BEGIN INIT INFO +# Provides: zephyrd +# Required-Start: $syslog $network $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the zephyr server. +# Description: Start the zephyr server. +### END INIT INFO diff --git a/debian/zephyr-server.config b/debian/zephyr-server.config new file mode 100644 index 0000000..f7a27b2 --- /dev/null +++ b/debian/zephyr-server.config @@ -0,0 +1,33 @@ +#!/bin/sh -e + +. /usr/share/debconf/confmodule +db_version 2.0 + +db_get zephyr-server/read_conf +if test -f /etc/zephyr/server.list -a \( "$RET" = true \) +then + z="`cat /etc/zephyr/server.list`" + + if test -n "$z" + then + db_set zephyr-server/read_conf false + db_set zephyr-server/servers "`echo $z`" + fi +fi + +db_get zephyr-server/servers || true +if test -z "$RET" +then + # if there happens to be zephyr-clients running on this machine + # it might know something about servers. + # else default to just the current host + z="`hostname --fqdn`" + if db_get zephyr-clients/servers && test -n "$RET" && ! echo "$RET" | grep -q "$z" + then + z="$RET $z" + fi + db_set zephyr-server/servers "$z" +fi + +db_input high zephyr-server/servers || true +db_go || true diff --git a/debian/zephyr-server.docs b/debian/zephyr-server.docs new file mode 100644 index 0000000..a3a5154 --- /dev/null +++ b/debian/zephyr-server.docs @@ -0,0 +1 @@ +OPERATING diff --git a/debian/zephyr-server.files b/debian/zephyr-server.files new file mode 100644 index 0000000..f0f9687 --- /dev/null +++ b/debian/zephyr-server.files @@ -0,0 +1,36 @@ +usr/sbin/zephyrd +usr/share/man/man8/zephyrd.8 +etc/zephyr/acl/class-registry.acl +etc/zephyr/acl/iui-hm_ctl.acl +etc/zephyr/acl/iui-hm_stat.acl +etc/zephyr/acl/iui-login.acl +etc/zephyr/acl/iui-operations.acl +etc/zephyr/acl/iui-user_locate.acl +etc/zephyr/acl/iui-wg_ctl.acl +etc/zephyr/acl/iui-zephyr_admin.acl +etc/zephyr/acl/iui-zephyr_ctl.acl +etc/zephyr/acl/iws-hm_ctl.acl +etc/zephyr/acl/iws-hm_stat.acl +etc/zephyr/acl/iws-login.acl +etc/zephyr/acl/iws-operations.acl +etc/zephyr/acl/iws-user_locate.acl +etc/zephyr/acl/iws-wg_ctl.acl +etc/zephyr/acl/iws-zephyr_admin.acl +etc/zephyr/acl/iws-zephyr_ctl.acl +etc/zephyr/acl/sub-hm_ctl.acl +etc/zephyr/acl/sub-hm_stat.acl +etc/zephyr/acl/sub-login.acl +etc/zephyr/acl/sub-operations.acl +etc/zephyr/acl/sub-user_locate.acl +etc/zephyr/acl/sub-wg_ctl.acl +etc/zephyr/acl/sub-zephyr_admin.acl +etc/zephyr/acl/sub-zephyr_ctl.acl +etc/zephyr/acl/xmt-hm_ctl.acl +etc/zephyr/acl/xmt-hm_stat.acl +etc/zephyr/acl/xmt-login.acl +etc/zephyr/acl/xmt-operations.acl +etc/zephyr/acl/xmt-user_locate.acl +etc/zephyr/acl/xmt-wg_ctl.acl +etc/zephyr/acl/xmt-zephyr_admin.acl +etc/zephyr/acl/xmt-zephyr_ctl.acl +etc/zephyr/default.subscriptions diff --git a/debian/zephyr-server.init b/debian/zephyr-server.init new file mode 100644 index 0000000..39b5e76 --- /dev/null +++ b/debian/zephyr-server.init @@ -0,0 +1,72 @@ +#! /bin/sh +# +# skeleton example file to build /etc/init.d/ scripts. +# This file should be used to construct scripts for /etc/init.d. +# +# Written by Miquel van Smoorenburg . +# Modified for Debian GNU/Linux +# by Ian Murdock . +# +# Version: @(#)skeleton 1.8 03-Mar-1998 miquels@cistron.nl +# +# This file was automatically customized by dh-make on Mon, 4 Dec 2000 05:28:22 -0500 + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/sbin/zephyrd +NAME=zephyrd +DESC="zephyr server" + +test -f $DAEMON || exit 0 + +set -e + +case "$1" in + start) + echo -n "Starting $DESC: " + start-stop-daemon --start --quiet --exec $DAEMON + echo "$NAME." + ;; + stop) + echo -n "Stopping $DESC: " + start-stop-daemon --oknodo --stop --quiet --exec $DAEMON + echo "$NAME." + ;; + restart) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + echo -n "Restarting $DESC: " + start-stop-daemon --oknodo --stop --quiet --exec $DAEMON + sleep 1 + start-stop-daemon --start --quiet --pidfile \ + /var/run/$NAME.pid --exec $DAEMON + echo "$NAME." + ;; + reload|force-reload) + echo -n "Telling $NAME to reload..." + start-stop-daemon --stop --signal HUP --exec $DAEMON + echo done. + ;; + *) + N=/etc/init.d/$NAME + echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + # echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit 0 + +### BEGIN INIT INFO +# Provides: zephyrd +# Required-Start: $syslog $network $remote_fs +# Required-Stop: $syslog $remote_fs +# Should-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: Start the zephyr server. +# Description: Start the zephyr server. +### END INIT INFO + diff --git a/debian/zephyr-server.postinst b/debian/zephyr-server.postinst new file mode 100644 index 0000000..014ab5e --- /dev/null +++ b/debian/zephyr-server.postinst @@ -0,0 +1,61 @@ +#! /bin/sh +# postinst script for zephyr +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see /usr/share/doc/packaging-manual/ +# +# quoting from the policy: +# Any necessary prompting should almost always be confined to the +# post-installation script, and should be protected with a conditional +# so that unnecessary prompting doesn't happen if a package's +# installation fails and the `postinst' is called with `abort-upgrade', +# `abort-remove' or `abort-deconfigure'. + +case "$1" in + configure) + if test ! -f /etc/zephyr/server.list; then + # if there's a server.list file, don't mess with it + . /usr/share/debconf/confmodule + + db_version 2.0 + + db_set zephyr-server/read_conf true + + db_get zephyr-server/servers || true + : > /etc/zephyr/server.list + for i in $RET + do + echo $i >> /etc/zephyr/server.list + done + fi + ;; + + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 0 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + diff --git a/debian/zephyr-server.postrm b/debian/zephyr-server.postrm new file mode 100644 index 0000000..95aa504 --- /dev/null +++ b/debian/zephyr-server.postrm @@ -0,0 +1,9 @@ +#!/bin/sh -e + +if test "$1" = purge; then + rm -f /etc/zephyr/server.list +fi + +#DEBHELPER# + +exit 0 diff --git a/debian/zephyr-server.templates b/debian/zephyr-server.templates new file mode 100644 index 0000000..efca03b --- /dev/null +++ b/debian/zephyr-server.templates @@ -0,0 +1,45 @@ +# These templates have been reviewed by the debian-l10n-english +# team +# +# If modifications/additions/rewording are needed, please ask +# debian-l10n-english@lists.debian.org for advice. +# +# Even minor modifications require translation updates and such +# changes should be coordinated with translators and reviewers. + +Template: zephyr-server/servers +Type: string +_Description: Zephyr servers: + Please specify the full names of the Zephyr servers, as a + space-separated list. + . + The list configured on clients can be a subset of the list configured + on servers. + +Template: zephyr-server/no-more-krb4 +Type: boolean +Default: true +Description: Incompatible Upgrade + You appear to be upgrading from a version of the zephyr server that + uses Kerberos version 4 to authenticate. Kerberos version 4 support + has been removed from Debian, and accordingly from the zephyr server. + This version of the zephyr server uses only Kerberos 5 to + authenticate, and thus is almost certainly incompatible with any of + your currently deployed clients. + . + A server that authenticates both ways can be built for lenny from the + zephyr source package, see: + /usr/share/doc/libzephyr4-krb5/README.krb4-5 + . + Continue with the upgrade? + +Template: zephyr-server/read_conf +Type: boolean +Default: true +Description: for internal use + We want to try and capture user changes when they edit a config file + manually. To do this we look at the file in the config script. However, + in the case of preconfigure, the config script is run twice before the + postinst is run. Thus we may read the wrong value before the edited value + is written out in postinst. If this is false we skip reading config files + until postinst runs. diff --git a/debian/zephyr.vars b/debian/zephyr.vars new file mode 100644 index 0000000..eaf70f0 --- /dev/null +++ b/debian/zephyr.vars @@ -0,0 +1,11 @@ +# $Id$ + +# Zephyr default variables file. Format is: +# +# var = value + +# Exposure setting defaults to realm-visible. +exposure = realm-visible + +# Initialization programs. +#initprogs = /etc/athena/zinit diff --git a/get_vers.sh b/get_vers.sh new file mode 100755 index 0000000..2f7f2a4 --- /dev/null +++ b/get_vers.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +top_srcdir=${1:-`pwd`} + +if test -f ${top_srcdir}/VERSION; then + VERSION=`cat ${top_srcdir}/VERSION` +elif test -d ${top_srcdir}/.git; then + VERSION=`(cd $top_srcdir; git describe --abbrev=6 --dirty | sed -e 's/%7E/~/')` + + if test "$(git symbolic-ref HEAD)" != refs/heads/master; then + REF=$(git symbolic-ref --short HEAD) + if test "$REF" = "fatal: ref HEAD is not a symbolic ref"; then + VERSION="$VERSION: detached head" + else + VERSION="$VERSION $(echo $REF | awk -F/ '{print $NF}' | tr 'a-z-' 'A-Z ')" + fi + fi +fi + +if test -z "$VERSION"; then + VERSION='FROM SPACE' +fi + +echo $VERSION diff --git a/h/internal.h b/h/internal.h new file mode 100644 index 0000000..b6e6804 --- /dev/null +++ b/h/internal.h @@ -0,0 +1,208 @@ + +#ifndef __INTERNAL_H__ +#define __INTERNAL_H__ + +#include +#include +#include + +#ifdef HAVE_KRB4 +#include +#include +#endif + +#ifdef HAVE_KRB5 +#include +#endif + +#ifdef HAVE_HESIOD +#include +#endif + +#include +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif +#ifndef REALM_SZ /* XXX */ +#define REALM_SZ NS_MAXDNAME +#endif +#define MAX_PRINCIPAL_SIZE 1024 + +#define SERVER_SVC_FALLBACK htons((unsigned short) 2103) +#define HM_SVC_FALLBACK htons((unsigned short) 2104) +#define HM_SRV_SVC_FALLBACK htons((unsigned short) 2105) + +#define ZSUBAUTH (Z_MakeAuthenticationSaveKey) + +#define ZAUTH_UNSET (-3) /* Internal to client library. */ +#define Z_MAXFRAGS 500 /* Max number of packet fragments */ +#define Z_MAXNOTICESIZE 400000 /* Max size of incoming notice */ +#define Z_MAXQUEUESIZE 1500000 /* Max size of input queue notices */ +#define Z_FRAGFUDGE 13 /* Room to for multinotice field */ +#define Z_NOTICETIMELIMIT 30 /* Time to wait for fragments */ +#define Z_INITFILTERSIZE 30 /* Starting size of uid filter */ +#define Z_FILTERTIMELIMIT 900 /* Max time to cache packet ids */ + +#define Z_AUTHMODE_NONE 0 /* no authentication */ +#define Z_AUTHMODE_KRB4 1 /* authenticate using Kerberos V4 */ +#define Z_AUTHMODE_KRB5 2 /* authenticate using Kerberos V5 */ + +#define Z_KEYUSAGE_CLT_CKSUM 1027 /* client->server notice checksum */ +#define Z_KEYUSAGE_SRV_CKSUM 1029 /* server->client notice checksum */ + +struct _Z_Hole { + struct _Z_Hole *next; + int first; + int last; +}; + +struct _Z_InputQ { + struct _Z_InputQ *next; + struct _Z_InputQ *prev; + ZNotice_Kind_t kind; + unsigned ZEPHYR_INT32 timep; + int packet_len; + char *packet; + int complete; + struct sockaddr_in from; + struct _Z_Hole *holelist; + ZUnique_Id_t uid; + int auth; + int header_len; + char *header; + int msg_len; + char *msg; +}; + +extern struct _Z_InputQ *__Q_Head, *__Q_Tail; + +extern int __Zephyr_open; /* 0 if FD opened, 1 otherwise */ +extern int __HM_set; /* 0 if dest addr set, 1 otherwise */ +extern int __Zephyr_server; /* 0 if normal client, 1 if server or zhm */ + +#ifdef HAVE_KRB5 +extern krb5_context Z_krb5_ctx; +Code_t Z_krb5_lookup_cksumtype(krb5_enctype, krb5_cksumtype *); + +struct _Z_SessionKey { + struct _Z_SessionKey *next; + struct _Z_SessionKey *prev; + krb5_keyblock *keyblock; + time_t send_time; + time_t first_use; +}; + +extern struct _Z_SessionKey *Z_keys_head, *Z_keys_tail; + +/* + * The maximum time we allow for a notice to get delivered. This is used for + * two timeouts in key expirey. First, we assume that any subscription notice + * was reached the server within that time; this allows us to assume old keys + * sent sufficiently long before a newer, verified key are stale. Second, we + * assume notices authenticated with an old key reach us in that time; this + * allows us to prune stale keys after a timeout. +*/ +#define KEY_TIMEOUT 60 +#endif + +extern ZLocations_t *__locate_list; +extern int __locate_num; +extern int __locate_next; + +extern ZSubscription_t *__subscriptions_list; +extern int __subscriptions_num; +extern int __subscriptions_next; + +extern int __Zephyr_port; /* Port number */ +extern struct in_addr __My_addr; +extern int __Zephyr_fd; +extern int __Q_CompleteLength; +extern struct sockaddr_in __HM_addr; +extern char __Zephyr_realm[]; + +typedef Code_t (*Z_SendProc) (ZNotice_t *, char *, int, int); + +struct _Z_InputQ *Z_GetFirstComplete (void); +struct _Z_InputQ *Z_GetNextComplete (struct _Z_InputQ *); +struct _Z_InputQ *Z_SearchQueue (ZUnique_Id_t *, ZNotice_Kind_t); +Code_t Z_XmitFragment (ZNotice_t*, char *,int,int); +void Z_RemQueue (struct _Z_InputQ *); +Code_t Z_AddNoticeToEntry (struct _Z_InputQ*, ZNotice_t*, int); +Code_t Z_FormatAuthHeader (ZNotice_t *, char *, int, int *, Z_AuthProc); +Code_t Z_FormatAuthHeaderWithASCIIAddress (ZNotice_t *, char *, int, int *); +Code_t Z_FormatHeader (ZNotice_t *, char *, int, int *, Z_AuthProc); +Code_t Z_FormatRawHeader (ZNotice_t *, char*, int, + int*, char **, char **); +Code_t Z_ReadEnqueue (void); +Code_t Z_ReadWait (void); +int Z_PacketWaiting (void); +Code_t Z_SendLocation (char*, char*, char*, Z_AuthProc, char*); +Code_t Z_SendFragmentedNotice (ZNotice_t *notice, int len, + Z_AuthProc cert_func, + Z_SendProc send_func); +Code_t Z_WaitForComplete (void); +Code_t Z_WaitForNotice (ZNotice_t *notice, + int (*pred)(ZNotice_t *, void *), void *arg, + int timeout); + + +Code_t Z_NewFormatHeader (ZNotice_t *, char *, int, int *, Z_AuthProc); +Code_t Z_NewFormatAuthHeader (ZNotice_t *, char *, int, int *, Z_AuthProc); +Code_t Z_NewFormatRawHeader (ZNotice_t *, char *, int, int *, char **, + int *, char **, char **); +Code_t Z_AsciiFormatRawHeader (ZNotice_t *, char *, int, int *, char **, + int *, char **, char **); + +void Z_gettimeofday(struct _ZTimeval *ztv, struct timezone *tz); + +Code_t Z_MakeAuthenticationSaveKey(ZNotice_t*, char *,int, int*); + +#ifdef HAVE_KRB5 +int ZGetCreds(krb5_creds **creds_out); +int ZGetCredsRealm(krb5_creds **creds_out, char *realm); +Code_t Z_Checksum(krb5_data *cksumbuf, krb5_keyblock *keyblock, + krb5_cksumtype cksumtype, krb5_keyusage cksumusage, + char **asn1_data, unsigned int *asn1_len); +Code_t Z_ExtractEncCksum(krb5_keyblock *keyblock, krb5_enctype *enctype, + krb5_cksumtype *cksumtype); +int Z_krb5_verify_cksum(krb5_keyblock *keyblock, krb5_data *cksumbuf, + krb5_cksumtype cksumtype, krb5_keyusage cksumusage, + unsigned char *asn1_data, int asn1_len); +Code_t Z_MakeZcodeAuthentication(register ZNotice_t *notice, + char *buffer, int buffer_len, + int *phdr_len, + krb5_creds *creds); +Code_t Z_InsertZcodeChecksum(krb5_keyblock *keyblock, ZNotice_t *notice, + char *buffer, + char *cksum_start, int cksum_len, + char *cstart, char *cend, int buffer_len, + int *length_ajdust, int from_server); +unsigned long z_quad_cksum(const unsigned char *, uint32_t *, long, + int, unsigned char *); +Code_t ZFormatAuthenticNoticeV5(ZNotice_t*, char*, int, int*, krb5_keyblock *); +#endif +#ifdef HAVE_KRB4 +Code_t ZFormatAuthenticNotice(ZNotice_t*, char*, int, int*, C_Block); +#endif + +#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE +#define Z_keydata(keyblock) ((keyblock)->contents) +#define Z_keylen(keyblock) ((keyblock)->length) +#define Z_credskey(creds) (&(creds)->keyblock) +#define Z_enctype(keyblock) ((keyblock)->enctype) +#else +#define Z_keydata(keyblock) ((keyblock)->keyvalue.data) +#define Z_keylen(keyblock) ((keyblock)->keyvalue.length) +#define Z_credskey(creds) (&(creds)->session) +#define Z_enctype(keyblock) ((keyblock)->keytype) +#endif + +#ifdef HAVE_KRB5_TICKET_ENC_PART2 +#define Z_tktprincp(tkt) ((tkt)->enc_part2 != 0) +#define Z_tktprinc(tkt) ((tkt)->enc_part2->client) +#else +#define Z_tktprincp(tkt) ((tkt)->client != 0) +#define Z_tktprinc(tkt) ((tkt)->client) +#endif + +#endif /* __INTERNAL_H__ */ diff --git a/h/sysdep.h b/h/sysdep.h new file mode 100644 index 0000000..368ba5a --- /dev/null +++ b/h/sysdep.h @@ -0,0 +1,191 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains system-dependent header code. + * + * Created by: Greg Hudson + * + * $Id$ + * + * Copyright (c) 1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef __SYSDEP_H__ +#define __SYSDEP_H__ + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#ifndef __USE_XOPEN_EXTENDED +#ifdef HAVE_GETSID +#define __USE_XOPEN_EXTENDED +#endif +#include +#ifdef __USE_XOPEN_EXTENDED +#undef __USE_XOPEN_EXTENDED +#endif +#else +#include +#endif +#endif +#include +#include +#include +#include + +#ifdef STDC_HEADERS +# include +#else +# ifdef HAVE_MALLOC_H +# include +# else +char *malloc(), *realloc(); +# endif +char *getenv(), *strerror(), *ctime(), *strcpy(); +time_t time(); +ZEPHYR_INT32 random(); +#endif + +#ifndef HAVE_RANDOM +#ifdef HAVE_LRAND48 +#define random lrand48 +#define srandom srand48 +#else +#define random rand +#define srandom srand +#endif +#endif + +#ifndef HAVE_STRERROR +extern char *sys_errlist[]; +# define strerror(x) (sys_errlist[(x)]) +#endif + +/* Strings. */ +#ifdef STDC_HEADERS +# include +#else +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *strchr(), *strrchr(); +# ifndef HAVE_MEMCPY +# define memcpy(d, s, n) bcopy ((s), (d), (n)) +# define memcmp bcmp +# endif +# ifndef HAVE_MEMMOVE +# define memmove(d, s, n) bcopy ((s), (d), (n)) +# endif +#endif + +/* Exit status handling and wait(). */ +#ifdef HAVE_SYS_WAIT_H +# include +#endif +#ifndef WEXITSTATUS +# define WEXITSTATUS(stat_val) ((unsigned)(stat_val) >> 8) +#endif +#ifndef WIFEXITED +# define WIFEXITED(stat_val) (((stat_val) & 255) == 0) +#endif + +#ifdef HAVE_SYS_CDEFS_H +#include +#endif + +/* Because we have public header files (and our prototypes need to agree with + * those header files), use __STDC__ to guess whether the compiler can handle + * stdarg, const, and prototypes. */ +#ifdef __STDC__ +# include +# define VA_START(ap, last) va_start(ap, last) +# ifndef __P +# define __P(x) x +# endif +#else +# include +# define VA_START(ap, last) va_start(ap) +# define const +# ifndef __P +# define __P(x) () +# endif +#endif + +/* openlog(). */ +#ifdef LOG_AUTH +/* A decent syslog */ +#define OPENLOG(str, opts, facility) openlog(str, opts, facility) +#else +/* Probably a 4.2-type syslog */ +#define OPENLOG(str, opts, facility) openlog(str, opts) +#endif + +#ifdef HAVE_FCNTL_H +# include +#endif + +#ifdef HAVE_PATHS_H +# include +# define TEMP_DIRECTORY _PATH_VARTMP +#else +# define TEMP_DIRECTORY FOUND_TMP +#endif + +#ifdef HAVE_UNISTD_H +# include +#else +# ifdef HAVE_SYS_FILE_H +# include +# endif +uid_t getuid(); +char *ttyname(); +#ifdef HAVE_GETHOSTID +ZEPHYR_INT32 gethostid(); +#endif +#endif + +#ifndef STDIN_FILENO +#define STDIN_FILENO 0 +#define STDOUT_FILENO 1 +#define STDERR_FILENO 2 +#endif + +#include + +/* Kerberos compatibility. */ +#ifdef HAVE_KRB4 +# include +# include +# include +# ifndef HAVE_KRB_GET_ERR_TEXT +# define krb_get_err_text(n) krb_err_txt[n] +# endif +# ifndef HAVE_KRB_LOG +# define krb_log log +# endif +#endif + +#ifdef HAVE_SYS_UTSNAME_H +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_SYS_MSGBUF_H +#include +#endif + +#ifndef MSG_BSIZE +#define MSG_BSIZE BUFSIZ +#endif + +#endif /* __SYSDEP_H__ */ + diff --git a/h/zephyr/mit-copyright.h b/h/zephyr/mit-copyright.h new file mode 100644 index 0000000..9b39b21 --- /dev/null +++ b/h/zephyr/mit-copyright.h @@ -0,0 +1,24 @@ +/* + +Copyright 1987,1988,1995 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ diff --git a/h/zephyr/zephyr.h b/h/zephyr/zephyr.h new file mode 100644 index 0000000..06cf541 --- /dev/null +++ b/h/zephyr/zephyr.h @@ -0,0 +1,385 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains global definitions + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of + * Technology. For copying and distribution information, see the + * file "mit-copyright.h". + */ + +#ifndef __ZEPHYR_H__ +#define __ZEPHYR_H__ + +#include +#include +#include +#include + +#include + +#ifndef IPPROTO_MAX /* Make sure not already included */ +#include +#endif + +#include + +/* Service names */ +#define HM_SVCNAME "zephyr-hm" +#define HM_SRV_SVCNAME "zephyr-hm-srv" +#define SERVER_SVCNAME "zephyr-clt" +#define SERVER_SERVICE "zephyr" +#define SERVER_INSTANCE "zephyr" +#define SERVER_KRB5_SERVICE "zephyr" + +#define ZVERSIONHDR "ZEPH" +#define ZVERSIONMAJOR 0 +#define ZVERSIONMINOR 2 + +#define Z_MAXPKTLEN 1024 +#define Z_MAXHEADERLEN 832 +#define Z_MAXOTHERFIELDS 10 /* Max unknown fields in ZNotice_t */ +#define Z_NUMFIELDS 19 + +/* Authentication levels returned by ZCheckAuthentication */ +#define ZAUTH_FAILED (-1) +#define ZAUTH_YES 1 +#define ZAUTH_NO 0 + +#define ZNOTICE_SOCKADDR 1 +#define ZNOTICE_CHARSET 1 + +#define ZCHARSET_UNKNOWN 0 +/* The following are from http://www.iana.org/assignments/character-sets */ +#define ZCHARSET_ISO_8859_1 4 +#define ZCHARSET_UTF_8 106 + +typedef char ZPacket_t[Z_MAXPKTLEN]; + +/* Packet type */ +typedef enum { + UNSAFE = 0, UNACKED = 1, ACKED = 2, HMACK = 3, HMCTL = 4, SERVACK = 5, + SERVNAK = 6, CLIENTACK = 7, STAT = 8 +} ZNotice_Kind_t; +extern const char * const ZNoticeKinds[9]; + +struct _ZTimeval { + int tv_sec; + int tv_usec; +}; + +/* Unique ID format */ +typedef struct _ZUnique_Id_t { + struct in_addr zuid_addr; + struct _ZTimeval tv; +} ZUnique_Id_t; + +/* Checksum */ +typedef unsigned int ZChecksum_t; + +/* Notice definition */ +typedef struct _ZNotice_t { + char *z_packet; + char *z_version; + ZNotice_Kind_t z_kind; + ZUnique_Id_t z_uid; + union { + struct sockaddr sa; + struct sockaddr_in ip4; + struct sockaddr_in6 ip6; + } z_sender_sockaddr; + /* heavily deprecated: */ +#define z_sender_addr z_sender_sockaddr.ip4.sin_addr + /* probably a bad idea?: */ + struct _ZTimeval z_time; + unsigned short z_port; + unsigned short z_charset; + int z_auth; + int z_checked_auth; + int z_authent_len; + char *z_ascii_authent; + char *z_class; + char *z_class_inst; + char *z_opcode; + char *z_sender; + char *z_recipient; + char *z_default_format; + char *z_multinotice; + ZUnique_Id_t z_multiuid; + ZChecksum_t z_checksum; + char *z_ascii_checksum; + int z_num_other_fields; + char *z_other_fields[Z_MAXOTHERFIELDS]; + char *z_message; + int z_message_len; + int z_num_hdr_fields; + char **z_hdr_fields; +} ZNotice_t; + +/* Subscription structure */ +typedef struct _ZSubscriptions_t { + char *zsub_recipient; + char *zsub_class; + char *zsub_classinst; +} ZSubscription_t; + +/* Function return code */ +typedef int Code_t; + +/* Locations structure */ +typedef struct _ZLocations_t { + char *host; + char *time; + char *tty; +} ZLocations_t; + +typedef struct _ZAsyncLocateData_t { + char *user; + ZUnique_Id_t uid; + char *version; +} ZAsyncLocateData_t; + +/* for ZSetDebug */ +#ifdef Z_DEBUG +void (*__Z_debug_print)(const char *fmt, va_list args, void *closure); +void *__Z_debug_print_closure; +#endif + +int ZCompareUIDPred(ZNotice_t *, void *); +int ZCompareMultiUIDPred(ZNotice_t *, void *); + +/* Defines for ZFormatNotice, et al. */ +typedef Code_t (*Z_AuthProc)(ZNotice_t*, char *, int, int *); +Code_t ZMakeAuthentication(ZNotice_t*, char *,int, int*); +Code_t ZMakeZcodeAuthentication(ZNotice_t*, char *,int, int*); +Code_t ZMakeZcodeRealmAuthentication(ZNotice_t*, char *,int, int*, char*); +Code_t ZResetAuthentication(void); + +char *ZGetSender(void); +char *ZGetVariable(char *); +Code_t ZSetVariable(char *var, char *value); +Code_t ZUnsetVariable(char *var); +int ZGetWGPort(void); +Code_t ZSetDestAddr(struct sockaddr_in *); +Code_t ZParseNotice(char*, int, ZNotice_t *); +Code_t ZReadAscii(char*, int, unsigned char*, int); +Code_t ZReadAscii32(char *, int, unsigned long *); +Code_t ZReadAscii16(char *, int, unsigned short *); +Code_t ZReadZcode(unsigned char*, unsigned char*, int, int *); +Code_t ZSendPacket(char*, int, int); +Code_t ZSendList(ZNotice_t*, char *[], int, Z_AuthProc); +Code_t ZSrvSendList(ZNotice_t*, char*[], int, Z_AuthProc, + Code_t (*)(ZNotice_t *, char *, int, int)); +Code_t ZSendRawList(ZNotice_t*, char *[], int); +Code_t ZSendNotice(ZNotice_t *, Z_AuthProc); +Code_t ZSendRawNotice(ZNotice_t *); +Code_t ZSrvSendNotice(ZNotice_t*, Z_AuthProc, + Code_t (*)(ZNotice_t *, char *, int, int)); +Code_t ZFormatNotice(ZNotice_t*, char**, int*, Z_AuthProc); +Code_t ZNewFormatNotice(ZNotice_t*, char**, int*, Z_AuthProc); +Code_t ZFormatNoticeList(ZNotice_t*, char**, int, + char **, int*, Z_AuthProc); +Code_t ZFormatRawNoticeList(ZNotice_t *, char *[], int, char **, int *); +Code_t ZFormatSmallNotice(ZNotice_t*, ZPacket_t, int*, Z_AuthProc); +Code_t ZFormatSmallRawNotice(ZNotice_t *, ZPacket_t, int *); +Code_t ZNewFormatSmallRawNotice(ZNotice_t *, ZPacket_t, int *); +Code_t ZFormatSmallRawNoticeList(ZNotice_t *, char *[], int, ZPacket_t, int *); +Code_t ZLocateUser(char *, int *, Z_AuthProc); +Code_t ZRequestLocations(char *, ZAsyncLocateData_t *, + ZNotice_Kind_t, Z_AuthProc); +Code_t ZhmStat(struct in_addr *, ZNotice_t *); +Code_t ZInitialize(void); +Code_t ZSetServerState(int); +Code_t ZSetFD(int); +int ZCompareUID(ZUnique_Id_t*, ZUnique_Id_t*); +Code_t ZSrvSendRawList(ZNotice_t*, char*[], int, + Code_t (*)(ZNotice_t *, char *, int, int)); +Code_t ZMakeAscii(char*, int, unsigned char*, int); +Code_t ZMakeAscii32(char *, int, unsigned long); +Code_t ZMakeAscii16(char *, int, unsigned int); +Code_t ZMakeZcode(char*, int, unsigned char*, int); +Code_t ZMakeZcode32(char *, int, unsigned long); +Code_t ZReceivePacket(ZPacket_t, int*, struct sockaddr_in*); +Code_t ZCheckAuthentication(ZNotice_t*, struct sockaddr_in*); +Code_t ZCheckZcodeAuthentication(ZNotice_t*, struct sockaddr_in*); +Code_t ZCheckZcodeRealmAuthentication(ZNotice_t*, struct sockaddr_in*, char *realm); +Code_t ZInitLocationInfo(char *hostname, char *tty); +Code_t ZSetLocation(char *exposure); +Code_t ZUnsetLocation(void); +Code_t ZFlushMyLocations(void); +Code_t ZFlushUserLocations(char *); +char *ZParseExposureLevel(char *text); +Code_t ZFormatRawNotice(ZNotice_t *, char**, int *); +Code_t ZRetrieveSubscriptions(unsigned short, int*); +Code_t ZRetrieveDefaultSubscriptions(int *); +Code_t ZGetSubscriptions(ZSubscription_t *, int *); +Code_t ZOpenPort(unsigned short *port); +Code_t ZClosePort(void); +Code_t ZFlushLocations(void); +Code_t ZFlushSubscriptions(void); +Code_t ZFreeNotice(ZNotice_t *notice); +Code_t ZGetLocations(ZLocations_t *, int *); +Code_t ZParseLocations(register ZNotice_t *notice, + register ZAsyncLocateData_t *zald, int *nlocs, + char **user); +int ZCompareALDPred(ZNotice_t *notice, void *zald); +void ZFreeALD(register ZAsyncLocateData_t *zald); +Code_t ZCheckIfNotice(ZNotice_t *notice, struct sockaddr_in *from, + register int (*predicate)(ZNotice_t *,void *), + void *args); +Code_t ZPeekPacket(char **buffer, int *ret_len, + struct sockaddr_in *from); +Code_t ZPeekNotice(ZNotice_t *notice, struct sockaddr_in *from); +Code_t ZIfNotice(ZNotice_t *notice, struct sockaddr_in *from, + int (*predicate)(ZNotice_t *, void *), void *args); +Code_t ZPeekIfNotice(ZNotice_t *notice, struct sockaddr_in *from, + int (*predicate)(ZNotice_t *, char *), char *args); +Code_t ZSubscriptions(ZSubscription_t *sublist, int nitems, + unsigned int port, + char *opcode, + Code_t (*send_routine)(ZNotice_t *, char *, int, int)); +Code_t ZPunt(ZSubscription_t *sublist, int nitems, unsigned int port); +Code_t ZSubscribeTo(ZSubscription_t *sublist, int nitems, + unsigned int port); +Code_t ZSubscribeToSansDefaults(ZSubscription_t *sublist, int nitems, + unsigned int port); +Code_t ZUnsubscribeTo(ZSubscription_t *sublist, int nitems, + unsigned int port); +Code_t ZCancelSubscriptions(unsigned int port); +Code_t ZFlushUserSubscriptions(char *recip); +int ZPending(void); +Code_t ZReceiveNotice(ZNotice_t *notice, struct sockaddr_in *from); +const char *ZGetCharsetString(char *charset); +unsigned short ZGetCharset(char *charset); +const char *ZCharsetToString(unsigned short charset); +Code_t ZTransliterate(char *in, int inlen, char *inset, char *outset, char **out, int *outlen); +#ifdef Z_DEBUG +void Z_debug(const char *, ...); +#endif +char *ZExpandRealm(char *realm); +Code_t ZDumpSession(char **buffer, int *ret_len); +Code_t ZLoadSession(char *buffer, int len); + +/* Compatibility */ +#define ZNewLocateUser ZLocateUser + +/* Not macros to retrieve Zephyr library values. */ +const char *ZGetRealm(void); +int ZGetFD (void); +int ZQLength (void); +struct sockaddr_in ZGetDestAddr (void); + + +#ifdef Z_DEBUG +void ZSetDebug (void (*)(const char *, va_list, void *), char *); +void Z_debug_stderr(const char *format, va_list args, void *closure); +#define ZSetDebug(proc,closure) (__Z_debug_print=(proc), \ + __Z_debug_print_closure=(closure), \ + (void) 0) +#else +#define ZSetDebug(proc,closure) +#endif + +/* Maximum queue length */ +#define Z_MAXQLEN 30 + +/* Successful function return */ +#define ZERR_NONE 0 + +/* Hostmanager wait time (in secs) */ +#define HM_TIMEOUT 10 + +/* Server wait time (in secs) */ +#define SRV_TIMEOUT 30 + +#define ZAUTH (ZMakeAuthentication) +#define ZCAUTH (ZMakeZcodeAuthentication) +#define ZNOAUTH ((Z_AuthProc)0) + +/* Packet strings */ +#define ZSRVACK_SENT "SENT" /* SERVACK codes */ +#define ZSRVACK_NOTSENT "LOST" +#define ZSRVACK_FAIL "FAIL" + +/* Server internal class */ +#define ZEPHYR_ADMIN_CLASS "ZEPHYR_ADMIN" /* Class */ + +/* Control codes sent to a server */ +#define ZEPHYR_CTL_CLASS "ZEPHYR_CTL" /* Class */ + +#define ZEPHYR_CTL_REALM "REALM" /* Inst: From realm */ +#define REALM_ADD_SUBSCRIBE "ADD_SUBSCRIBE" /* Opcode: Add subs */ +#define REALM_REQ_SUBSCRIBE "REQ_SUBSCRIBE" /* Opcode: Request subs */ +#define REALM_SUBSCRIBE "RLM_SUBSCRIBE" /* Opcode: Subscribe realm */ +#define REALM_UNSUBSCRIBE "RLM_UNSUBSCRIBE" /* Opcode: Unsub realm */ + +#define ZEPHYR_CTL_CLIENT "CLIENT" /* Inst: From client */ +#define CLIENT_SUBSCRIBE "SUBSCRIBE" /* Opcode: Subscribe */ +#define CLIENT_SUBSCRIBE_NODEFS "SUBSCRIBE_NODEFS" /* Opcode: Subscribe */ +#define CLIENT_UNSUBSCRIBE "UNSUBSCRIBE" /* Opcode: Unsubsubscribe */ +#define CLIENT_CANCELSUB "CLEARSUB" /* Opcode: Clear all subs */ +#define CLIENT_GIMMESUBS "GIMME" /* Opcode: Give me subs */ +#define CLIENT_GIMMEDEFS "GIMMEDEFS" /* Opcode: Give me default + * subscriptions */ +#define CLIENT_FLUSHSUBS "FLUSHSUBS" /* Opcode: Clear subs for princ */ + +#define ZEPHYR_CTL_HM "HM" /* Inst: From HM */ +#define HM_BOOT "BOOT" /* Opcode: Boot msg */ +#define HM_FLUSH "FLUSH" /* Opcode: Flush me */ +#define HM_DETACH "DETACH" /* Opcode: Detach me */ +#define HM_ATTACH "ATTACH" /* Opcode: Attach me */ + +/* Control codes send to a HostManager */ +#define HM_CTL_CLASS "HM_CTL" /* Class */ + +#define HM_CTL_SERVER "SERVER" /* Inst: From server */ +#define SERVER_SHUTDOWN "SHUTDOWN" /* Opcode: Server shutdown */ +#define SERVER_PING "PING" /* Opcode: PING */ + +#define HM_CTL_CLIENT "CLIENT" /* Inst: From client */ +#define CLIENT_FLUSH "FLUSH" /* Opcode: Send flush to srv */ +#define CLIENT_NEW_SERVER "NEWSERV" /* Opcode: Find new server */ + +/* HM Statistics */ +#define HM_STAT_CLASS "HM_STAT" /* Class */ + +#define HM_STAT_CLIENT "HMST_CLIENT" /* Inst: From client */ +#define HM_GIMMESTATS "GIMMESTATS" /* Opcode: get stats */ + +/* Login class messages */ +#define LOGIN_CLASS "LOGIN" /* Class */ + +/* Class Instance is principal of user who is logging in or logging out */ + +#define EXPOSE_NONE "NONE" /* Opcode: Not visible */ +#define EXPOSE_OPSTAFF "OPSTAFF" /* Opcode: Opstaff visible */ +#define EXPOSE_REALMVIS "REALM-VISIBLE" /* Opcode: Realm visible */ +#define EXPOSE_REALMANN "REALM-ANNOUNCED"/* Opcode: Realm announced */ +#define EXPOSE_NETVIS "NET-VISIBLE" /* Opcode: Net visible */ +#define EXPOSE_NETANN "NET-ANNOUNCED" /* Opcode: Net announced */ +#define LOGIN_USER_LOGIN "USER_LOGIN" /* Opcode: user login + (from server) */ +#define LOGIN_USER_LOGOUT "USER_LOGOUT" /* Opcode: User logout */ +#define LOGIN_USER_FLUSH "USER_FLUSH" /* Opcode: flush all locs */ + +/* Locate class messages */ +#define LOCATE_CLASS "USER_LOCATE" /* Class */ + +#define LOCATE_HIDE "USER_HIDE" /* Opcode: Hide me */ +#define LOCATE_UNHIDE "USER_UNHIDE" /* Opcode: Unhide me */ + +/* Class Instance is principal of user to locate */ +#define LOCATE_LOCATE "LOCATE" /* Opcode: Locate user */ + +/* WG_CTL class messages */ +#define WG_CTL_CLASS "WG_CTL" /* Class */ + +#define WG_CTL_USER "USER" /* Inst: User request */ +#define USER_REREAD "REREAD" /* Opcode: Reread desc file */ +#define USER_SHUTDOWN "SHUTDOWN" /* Opcode: Go catatonic */ +#define USER_STARTUP "STARTUP" /* Opcode: Come out of it */ +#define USER_EXIT "EXIT" /* Opcode: Exit the client */ + +#endif /* __ZEPHYR_H__ */ diff --git a/lib/Makefile.in b/lib/Makefile.in new file mode 100644 index 0000000..d76f2a9 --- /dev/null +++ b/lib/Makefile.in @@ -0,0 +1,81 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ +top_builddir=.. + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +LIBS=@LIBS@ + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ +RANLIB=@RANLIB@ + +DEBUG=-O +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ ${DEBUG} +ALL_CFLAGS=${CFLAGS} -DSYSCONFDIR=\"${sysconfdir}\" -I${top_srcdir}/h \ + -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=@LIBZEPHYR_LIBS@ -lcom_err @LIBICONV@ + +OBJS = zephyr_err.lo ZAsyncLocate.lo ZCkAuth.lo ZCkIfNot.lo ZClosePort.lo \ + ZCmpUID.lo ZCmpUIDP.lo ZFlsLocs.lo ZFlsSubs.lo ZFmtAuth.lo \ + ZFmtList.lo ZFmtNotice.lo ZFmtRaw.lo ZFmtRawLst.lo ZFmtSmRLst.lo \ + ZFmtSmRaw.lo ZFreeNot.lo ZGetLocs.lo ZGetSender.lo ZGetSubs.lo \ + ZGetWGPort.lo ZhmStat.lo ZIfNotice.lo ZInit.lo ZLocations.lo \ + ZMakeAscii.lo ZMkAuth.lo ZNewLocU.lo ZOpenPort.lo ZParseNot.lo \ + ZPeekIfNot.lo ZPeekNot.lo ZPeekPkt.lo ZPending.lo ZReadAscii.lo \ + ZRecvNot.lo ZRecvPkt.lo ZRetSubs.lo ZSendList.lo ZSendNot.lo \ + ZSendPkt.lo ZSendRaw.lo ZSendRLst.lo ZSetDest.lo ZSetFD.lo ZSetSrv.lo \ + ZSubs.lo ZVariables.lo ZWait4Not.lo Zinternal.lo ZMakeZcode.lo \ + ZReadZcode.lo ZCkZAut.lo quad_cksum.lo charset.lo ZExpnRlm.lo \ + ZDumpSession.lo + +.SUFFIXES: .lo + +all: libzephyr.la + +libzephyr.la: ${OBJS} + ${LIBTOOL} --mode=link ${CC} -rpath ${libdir} -version-info 4:0:0 \ + ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +${BUILDTOP}/h/zephyr/zephyr_err.h: zephyr_err.c +zephyr_err.c: zephyr_err.et + compile_et ${srcdir}/zephyr_err.et + cp -f zephyr_err.h ${BUILDTOP}/h/zephyr + +.c.lo: + ${LIBTOOL} --mode=compile ${CC} -c -o $@ ${ALL_CFLAGS} $< + +check: + PYTHONPATH=${top_srcdir}/python python $(srcdir)/zephyr_tests.py --builddir=$(BUILDTOP) + PYTHONPATH=${top_srcdir}/python $(srcdir)/zephyr_run_doctests --builddir=$(BUILDTOP) + +install: libzephyr.la + ${LIBTOOL} --mode=install ${INSTALL} -m 644 libzephyr.la \ + ${DESTDIR}${libdir} + ${INSTALL} -m 644 ${srcdir}/zephyr.1 ${DESTDIR}${mandir}/man1 + +clean: + rm -f zephyr_err.c zephyr_err.h + ${LIBTOOL} --mode=clean rm -f ${OBJS} libzephyr.la + +${OBJS}: ${top_srcdir}/h/internal.h ${top_srcdir}/h/sysdep.h +${OBJS}: ${BUILDTOP}/h/config.h ${BUILDTOP}/h/zephyr/zephyr.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr_err.h + +.PHONY: all check install clean + diff --git a/lib/ZAsyncLocate.c b/lib/ZAsyncLocate.c new file mode 100644 index 0000000..41ecffb --- /dev/null +++ b/lib/ZAsyncLocate.c @@ -0,0 +1,168 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for asynchronous location functions. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1990,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZAsyncLocate_c[] = "$Id$"; +#endif + +Code_t +ZRequestLocations(char *user, + register ZAsyncLocateData_t *zald, + ZNotice_Kind_t kind, /* UNSAFE, UNACKED, or ACKED */ + Z_AuthProc auth) +{ + int retval; + ZNotice_t notice; + + if (ZGetFD() < 0) + if ((retval = ZOpenPort((u_short *)0)) != ZERR_NONE) + return (retval); + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = kind; + notice.z_port = __Zephyr_port; + notice.z_class = LOCATE_CLASS; + notice.z_class_inst = user; + notice.z_opcode = LOCATE_LOCATE; + notice.z_sender = 0; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_message_len = 0; + + if ((retval = ZSendNotice(¬ice, auth)) != ZERR_NONE) + return(retval); + + if ((zald->user = (char *) malloc(strlen(user)+1)) == NULL) { + return(ENOMEM); + } + if ((zald->version = (char *) malloc(strlen(notice.z_version)+1)) == NULL) { + free(zald->user); + return(ENOMEM); + } + zald->uid = notice.z_multiuid; + strcpy(zald->user,user); + strcpy(zald->version,notice.z_version); + + return(ZERR_NONE); +} + +Code_t +ZParseLocations(register ZNotice_t *notice, + register ZAsyncLocateData_t *zald, + int *nlocs, + char **user) +{ + char *ptr, *end; + int i; + + ZFlushLocations(); /* This never fails (this function is part of the + library, so it is allowed to know this). */ + + /* non-matching protocol version numbers means the + server is probably an older version--must punt */ + + if (zald && strcmp(notice->z_version, zald->version)) + return(ZERR_VERS); + + if (notice->z_kind == SERVNAK) + return (ZERR_SERVNAK); + + /* flag ACKs as special */ + if (notice->z_kind == SERVACK && + !strcmp(notice->z_opcode, LOCATE_LOCATE)) { + *nlocs = -1; + return(ZERR_NONE); + } + + if (notice->z_kind != ACKED) + return (ZERR_INTERNAL); + + end = notice->z_message+notice->z_message_len; + + __locate_num = 0; + + for (ptr=notice->z_message;ptrz_message, i=0; i<__locate_num; i++) { + unsigned int len; + + len = strlen (ptr) + 1; + __locate_list[i].host = (char *) malloc(len); + if (!__locate_list[i].host) + return (ENOMEM); + (void) strcpy(__locate_list[i].host, ptr); + ptr += len; + + len = strlen (ptr) + 1; + __locate_list[i].time = (char *) malloc(len); + if (!__locate_list[i].time) + return (ENOMEM); + (void) strcpy(__locate_list[i].time, ptr); + ptr += len; + + len = strlen (ptr) + 1; + __locate_list[i].tty = (char *) malloc(len); + if (!__locate_list[i].tty) + return (ENOMEM); + (void) strcpy(__locate_list[i].tty, ptr); + ptr += len; + } + + __locate_next = 0; + *nlocs = __locate_num; + if (user) { + if (zald) { + if ((*user = (char *) malloc(strlen(zald->user)+1)) == NULL) + return(ENOMEM); + strcpy(*user,zald->user); + } else { + if ((*user = (char *) malloc(strlen(notice->z_class_inst)+1)) == NULL) + return(ENOMEM); + strcpy(*user,notice->z_class_inst); + } + } + return (ZERR_NONE); +} + +int +ZCompareALDPred(ZNotice_t *notice, + void *zald) +{ + return(ZCompareUID(&(notice->z_multiuid), + &(((ZAsyncLocateData_t *) zald)->uid))); +} + +void +ZFreeALD(register ZAsyncLocateData_t *zald) +{ + if (!zald) return; + + if (zald->user) free(zald->user); + if (zald->version) free(zald->version); + (void) memset(zald, 0, sizeof(*zald)); +} diff --git a/lib/ZCkAuth.c b/lib/ZCkAuth.c new file mode 100644 index 0000000..ea024a9 --- /dev/null +++ b/lib/ZCkAuth.c @@ -0,0 +1,67 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZCheckAuthentication function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZCheckAuthentication_c[] = + "$Id$"; +#endif + +#include + +#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA +#define krb5_free_data(ctx, dat) free((dat)->data) +#endif + +/* Check authentication of the notice. + If it looks authentic but fails the Kerberos check, return -1. + If it looks authentic and passes the Kerberos check, return 1. + If it doesn't look authentic, return 0 + + When not using Kerberos, return true if the notice claims to be authentic. + Only used by clients; the server uses its own routine. + */ +Code_t +ZCheckAuthentication(ZNotice_t *notice, + struct sockaddr_in *from) +{ +#if defined(HAVE_KRB4) && !defined(HAVE_KRB5) + int result; + ZChecksum_t our_checksum; + C_Block *session; + CREDENTIALS cred; + + /* If the value is already known, return it. */ + if (notice->z_checked_auth != ZAUTH_UNSET) + return (notice->z_checked_auth); + + if (!notice->z_auth) + return (ZAUTH_NO); + + if ((result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, + __Zephyr_realm, &cred)) != 0) + return (ZAUTH_NO); + + session = (C_Block *)cred.session; + + our_checksum = des_quad_cksum((unsigned char *)notice->z_packet, + NULL, + notice->z_default_format+ + strlen(notice->z_default_format) + 1 + - notice->z_packet, + 0, session); + + /* if mismatched checksum, then the packet was corrupted */ + return ((our_checksum == notice->z_checksum) ? ZAUTH_YES : ZAUTH_FAILED); +#else + return ZCheckZcodeAuthentication(notice, from); +#endif +} diff --git a/lib/ZCkIfNot.c b/lib/ZCkIfNot.c new file mode 100644 index 0000000..e8fcaf2 --- /dev/null +++ b/lib/ZCkIfNot.c @@ -0,0 +1,57 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZCheckIfNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZCheckIfNotice_c[] = "$Id$"; +#endif + +Code_t +ZCheckIfNotice(ZNotice_t *notice, + struct sockaddr_in *from, + register int (*predicate)(ZNotice_t *, void *), + void *args) +{ + ZNotice_t tmpnotice; + Code_t retval; + register char *buffer; + register struct _Z_InputQ *qptr; + + if ((retval = Z_ReadEnqueue()) != ZERR_NONE) + return (retval); + + qptr = Z_GetFirstComplete(); + + while (qptr) { + if ((retval = ZParseNotice(qptr->packet, qptr->packet_len, + &tmpnotice)) != ZERR_NONE) + return (retval); + if ((*predicate)(&tmpnotice, args)) { + if (!(buffer = (char *) malloc((unsigned) qptr->packet_len))) + return (ENOMEM); + (void) memcpy(buffer, qptr->packet, qptr->packet_len); + if (from) + *from = qptr->from; + if ((retval = ZParseNotice(buffer, qptr->packet_len, + notice)) != ZERR_NONE) { + free(buffer); + return (retval); + } + Z_RemQueue(qptr); + return (ZERR_NONE); + } + qptr = Z_GetNextComplete(qptr); + } + + return (ZERR_NONOTICE); +} diff --git a/lib/ZCkZAut.c b/lib/ZCkZAut.c new file mode 100644 index 0000000..6900971 --- /dev/null +++ b/lib/ZCkZAut.c @@ -0,0 +1,232 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZCheckAuthentication function. + * + * Created by: Robert French + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ +/* $Header$ */ + +#ifndef lint +static const char rcsid_ZCheckAuthentication_c[] = + "$Id$"; +#endif + +#include + +#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA +#define krb5_free_data(ctx, dat) free((dat)->data) +#endif + +/* Check authentication of the notice. + If it looks authentic but fails the Kerberos check, return -1. + If it looks authentic and passes the Kerberos check, return 1. + If it doesn't look authentic, return 0 + + When not using Kerberos, return true if the notice claims to be authentic. + Only used by clients; the server uses its own routine. + */ +#ifdef HAVE_KRB5 +static Code_t Z_CheckZcodeAuthentication(ZNotice_t *notice, + struct sockaddr_in *from, + krb5_keyblock *keyblock) +{ + krb5_error_code result; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + krb5_data cksumbuf; + int valid; + char *cksum0_base, *cksum1_base = NULL, *cksum2_base; + char *x; + unsigned char *asn1_data, *key_data, *cksum_data; + int asn1_len, key_len, cksum0_len = 0, cksum1_len = 0, cksum2_len = 0; + + /* Figure out what checksum type to use */ + key_data = Z_keydata(keyblock); + key_len = Z_keylen(keyblock); + result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); + if (result) { + return (ZAUTH_FAILED); + } + + /* Assemble the things to be checksummed */ + /* first part is from start of packet through z_default_format: + * - z_version + * - z_num_other_fields + * - z_kind + * - z_uid + * - z_port + * - z_auth + * - z_authent_len + * - z_ascii_authent + * - z_class + * - z_class_inst + * - z_opcode + * - z_sender + * - z_recipient + * - z_default_format + */ + cksum0_base = notice->z_packet; + x = notice->z_default_format; + cksum0_len = x + strlen(x) + 1 - cksum0_base; + /* second part is from z_multinotice through other fields: + * - z_multinotice + * - z_multiuid + * - z_sender_(sock)addr + * - z_charset + * - z_other_fields[] + */ + if (notice->z_num_hdr_fields > 15 ) { + cksum1_base = notice->z_multinotice; + if (notice->z_num_other_fields) + x = notice->z_other_fields[notice->z_num_other_fields - 1]; + else { + /* see also server/kstuff.c:ZCheck{Realm,}Authentication */ + /* XXXXXXXXXXXXXXXXXXXXXXX */ + if (notice->z_num_hdr_fields > 16) + x = cksum1_base + strlen(cksum1_base) + 1; /* multinotice */ + if (notice->z_num_hdr_fields > 17) + x = x + strlen(x) + 1; /* multiuid */ + if (notice->z_num_hdr_fields > 18) + x = x + strlen(x) + 1; /* sender */ + } + cksum1_len = x + strlen(x) + 1 - cksum1_base; /* charset / extra field */ + } + + /* last part is the message body */ + cksum2_base = notice->z_message; + cksum2_len = notice->z_message_len; + + /* The following code checks for old-style checksums, which will go + away once Kerberos 4 does. */ + if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') && + key_len == 8 && + (enctype == (krb5_enctype)ENCTYPE_DES_CBC_CRC || + enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD4 || + enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD5)) { + /* try old-format checksum (covers cksum0 only) */ + + ZChecksum_t our_checksum; + + our_checksum = z_quad_cksum((unsigned char *)cksum0_base, NULL, cksum0_len, 0, + key_data); + if (our_checksum == notice->z_checksum) { + return ZAUTH_YES; + } + } + + cksumbuf.length = cksum0_len + cksum1_len + cksum2_len; + cksumbuf.data = malloc(cksumbuf.length); + if (!cksumbuf.data) { + return ZAUTH_NO; + } + /* HOLDING: cksumbuf.data */ + + cksum_data = (unsigned char *)cksumbuf.data; + memcpy(cksum_data, cksum0_base, cksum0_len); + if (cksum1_len) + memcpy(cksum_data + cksum0_len, cksum1_base, cksum1_len); + memcpy(cksum_data + cksum0_len + cksum1_len, + cksum2_base, cksum2_len); + + /* decode zcoded checksum */ + /* The encoded form is always longer than the original */ + asn1_len = strlen(notice->z_ascii_checksum) + 1; + asn1_data = malloc(asn1_len); + if (!asn1_data) { + free(cksumbuf.data); + return ZAUTH_FAILED; + } + /* HOLDING: asn1_data, cksumbuf.data */ + result = ZReadZcode((unsigned char *)notice->z_ascii_checksum, + asn1_data, asn1_len, &asn1_len); + if (result != ZERR_NONE) { + free(asn1_data); + free(cksumbuf.data); + return ZAUTH_FAILED; + } + /* HOLDING: asn1_data, cksumbuf.data */ + + valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, + Z_KEYUSAGE_SRV_CKSUM, asn1_data, asn1_len); + + free(asn1_data); + free(cksumbuf.data); + + if (valid) + return ZAUTH_YES; + else + return ZAUTH_FAILED; +} +#endif + +Code_t ZCheckZcodeAuthentication(ZNotice_t *notice, + struct sockaddr_in *from) +{ +#ifdef HAVE_KRB5 + Code_t answer; + krb5_creds *creds; + struct _Z_SessionKey *savedkey, *todelete; +#endif + + /* If the value is already known, return it. */ + if (notice->z_checked_auth != ZAUTH_UNSET) + return (notice->z_checked_auth); + + if (!notice->z_auth) + return (ZAUTH_NO); + + if (!notice->z_ascii_checksum) + return (ZAUTH_NO); + +#ifdef HAVE_KRB5 + /* Try each of the saved session keys. */ + for (savedkey = Z_keys_head; savedkey != NULL; savedkey = savedkey->next) { + answer = Z_CheckZcodeAuthentication(notice, from, savedkey->keyblock); + if (answer == ZAUTH_YES) { + /* Save the time of the first use of each key. */ + if (!savedkey->first_use) { + savedkey->first_use = time(NULL); + } else { + /* + * Any keys sent sufficiently long before this one is stale. If + * we know it has been long enough since the server learned of + * this key, we can prune keys made stale by this one. + */ + if (time(NULL) > savedkey->first_use + KEY_TIMEOUT) { + while (Z_keys_tail && + Z_keys_tail->send_time + KEY_TIMEOUT < savedkey->send_time) { + todelete = Z_keys_tail; + Z_keys_tail = Z_keys_tail->prev; + Z_keys_tail->next = NULL; + + krb5_free_keyblock(Z_krb5_ctx, todelete->keyblock); + free(todelete); + } + } + } + return answer; + } + } + + /* + * If each of those fails, pull from the ccache. This is to preserve the + * behavior of things like zwgc/zctl where another program actually + * generates the subscription notices. + */ + if (ZGetCreds(&creds)) + return ZAUTH_NO; + + answer = Z_CheckZcodeAuthentication(notice, from, Z_credskey(creds)); + + krb5_free_creds(Z_krb5_ctx, creds); + return answer; +#else + return (notice->z_auth ? ZAUTH_YES : ZAUTH_NO); +#endif +} diff --git a/lib/ZClosePort.c b/lib/ZClosePort.c new file mode 100644 index 0000000..bd212b4 --- /dev/null +++ b/lib/ZClosePort.c @@ -0,0 +1,29 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZClosePort function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZClosePort_c[] = "$Id$"; +#endif + +Code_t +ZClosePort(void) +{ + if (__Zephyr_fd >= 0 && __Zephyr_open) + (void) close(__Zephyr_fd); + + __Zephyr_fd = -1; + __Zephyr_open = 0; + + return (ZERR_NONE); +} diff --git a/lib/ZCmpUID.c b/lib/ZCmpUID.c new file mode 100644 index 0000000..a448deb --- /dev/null +++ b/lib/ZCmpUID.c @@ -0,0 +1,24 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZCompareUID function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZCompareUID_c[] = "$Id$"; +#endif + +#include + +int +ZCompareUID(ZUnique_Id_t *uid1, + ZUnique_Id_t *uid2) +{ + return (!memcmp((char *)uid1, (char *)uid2, sizeof (*uid1))); +} diff --git a/lib/ZCmpUIDP.c b/lib/ZCmpUIDP.c new file mode 100644 index 0000000..abb05a4 --- /dev/null +++ b/lib/ZCmpUIDP.c @@ -0,0 +1,31 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZCompareUIDPred function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZCompareUIDPred_c[] = "$Id$"; +#endif + +#include + +int +ZCompareUIDPred(ZNotice_t *notice, + void *uid) +{ + return (ZCompareUID(¬ice->z_uid, (ZUnique_Id_t *) uid)); +} + +int +ZCompareMultiUIDPred(ZNotice_t *notice, + void *uid) +{ + return (ZCompareUID(¬ice->z_multiuid, (ZUnique_Id_t *) uid)); +} diff --git a/lib/ZDumpSession.c b/lib/ZDumpSession.c new file mode 100644 index 0000000..01c4444 --- /dev/null +++ b/lib/ZDumpSession.c @@ -0,0 +1,138 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the session dump and restore function. + * + * Created by: David Benjamin + * + * $Id$ + * + * Copyright (c) 2013 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZDumpSession_c[] = "$Id$"; +#endif + +#include + +#define SESSION_VERSION 1 + +Code_t +ZDumpSession(char **buffer, + int *ret_len) +{ +#ifdef HAVE_KRB5 + struct _Z_SessionKey *key; + uint32_t num_keys = 0; +#endif + char *ptr; + int len; + + /* + * We serialize the port number and all keys. All numbers are + * stored in big-endian. Byte strings are prefixed with a 32-bit + * length. First field is 16-bit version number. Keys are stored + * in reverse. + */ + + len = 2 + 2; /* version, port number */ +#ifdef HAVE_KRB5 + len += 4; /* num_keys */ + for (key = Z_keys_head; key != NULL; key = key->next) { + num_keys++; + len += 4 + 4; /* enctype, length */ + len += key->keyblock->length; /* contents */ + } +#endif + + *ret_len = len; + if (!(*buffer = (char *) malloc((unsigned)*ret_len))) + return (ENOMEM); + + ptr = *buffer; + *((uint16_t*) ptr) = htons(SESSION_VERSION); ptr += 2; + *((uint16_t*) ptr) = htons(__Zephyr_port); ptr += 2; +#ifdef HAVE_KRB5 + *((uint32_t *)ptr) = htonl(num_keys); ptr += 4; + for (key = Z_keys_tail; key != NULL; key = key->prev) { + *((uint32_t*) ptr) = htonl(key->keyblock->enctype); ptr += 4; + *((uint32_t*) ptr) = htonl(key->keyblock->length); ptr += 4; + memcpy(ptr, key->keyblock->contents, key->keyblock->length); + ptr += key->keyblock->length; + } +#endif + + return (ZERR_NONE); +} + +Code_t +ZLoadSession(char *buffer, int len) +{ +#ifdef HAVE_KRB5 + struct _Z_SessionKey *key; + uint32_t num_keys, keylength; + krb5_enctype enctype; + int i; +#endif + Code_t ret; + uint16_t version, port; + + if (len < 2) return (EINVAL); + version = ntohs(*((uint16_t *) buffer)); buffer += 2; len -= 2; + if (version != SESSION_VERSION) + return (EINVAL); + + if (len < 2) return (EINVAL); + port = ntohs(*((uint16_t *) buffer)); buffer += 2; len -= 2; + if ((ret = ZOpenPort(&port)) != ZERR_NONE) + return ret; + +#ifdef HAVE_KRB5 + if (len < 4) return (EINVAL); + num_keys = ntohl(*((uint32_t *) buffer)); buffer += 4; len -= 4; + + for (i = 0; i < num_keys; i++) { + key = (struct _Z_SessionKey *)malloc(sizeof(struct _Z_SessionKey)); + if (!key) + return (ENOMEM); + if (len < 4) { + free(key); + return (EINVAL); + } + enctype = ntohl(*((uint32_t *) buffer)); buffer += 4; len -= 4; + if (len < 4) { + free(key); + return (EINVAL); + } + keylength = ntohl(*((uint32_t *) buffer)); buffer += 4; len -= 4; + if (len < keylength) { + free(key); + return (EINVAL); + } + ret = krb5_init_keyblock(Z_krb5_ctx, enctype, keylength, &key->keyblock); + if (ret) { + free(key); + return ret; + } + memcpy((char *)key->keyblock->contents, buffer, keylength); + buffer += keylength; len -= keylength; + /* Just set recent times. It means we might not be able to + retire the keys, but that's fine. */ + key->send_time = time(NULL); + key->first_use = time(NULL); + /* Prepend to the key list. */ + key->prev = NULL; + key->next = Z_keys_head; + if (Z_keys_head) + Z_keys_head->prev = key; + Z_keys_head = key; + if (!Z_keys_tail) + Z_keys_tail = key; + } +#endif + + if (len) + return (EINVAL); + return (ZERR_NONE); +} diff --git a/lib/ZExpnRlm.c b/lib/ZExpnRlm.c new file mode 100644 index 0000000..6f904b6 --- /dev/null +++ b/lib/ZExpnRlm.c @@ -0,0 +1,101 @@ +#include +#include +#include + +char * +ZExpandRealm(char *realm) +{ + char *cp1, *cp2; + static char expand[REALM_SZ]; +#ifdef HAVE_KRB5 + krb5_error_code result; + char **list_realms; + result = krb5_get_host_realm(Z_krb5_ctx, realm, &list_realms); + if (result) { + /* Error, just return upper-cased realm */ + cp2 = realm; + cp1 = expand; + while (*cp2) { + *cp1++ = toupper(*cp2++); + } + *cp1 = '\0'; + return expand; + } + strncpy(expand, list_realms[0], sizeof(expand)); + expand[sizeof(expand)-1] = '\0'; + result = krb5_free_host_realm(Z_krb5_ctx, list_realms); + return expand; +#else +#ifndef HAVE_KRB4 + struct hostent *he; + + he = gethostbyname(realm); + + if (!he || !he->h_name) + /* just use the raw realm */ + cp2 = realm; + else + cp2 = he->h_name; + + cp1 = expand; + while (*cp2) { + *cp1++ = toupper(*cp2++); + } + *cp1 = '\0'; + + return(expand); +#else + int retval; + FILE *rlm_file; + char krb_host[NS_MAXDNAME + 1]; + static char krb_realm[REALM_SZ+1]; + char linebuf[BUFSIZ]; + char scratch[64]; + +/* upcase what we got */ + cp2 = realm; + cp1 = expand; + while (*cp2) { + *cp1++ = toupper(*cp2++); + } + *cp1 = '\0'; + + if ((rlm_file = fopen("/etc/krb.conf", "r")) == (FILE *) 0) { + return(expand); + } + + if (fgets(linebuf, BUFSIZ, rlm_file) == NULL) { + /* error reading */ + (void) fclose(rlm_file); + return(expand); + } + + if (sscanf(linebuf, "%s", krb_realm) < 1) { + /* error reading */ + (void) fclose(rlm_file); + return(expand); + } + + if (!strncmp(krb_realm, expand, strlen(expand))) { + (void) fclose(rlm_file); + return(krb_realm); + } + + while (1) { + /* run through the file, looking for admin host */ + if (fgets(linebuf, BUFSIZ, rlm_file) == NULL) { + (void) fclose(rlm_file); + return(expand); + } + + if (sscanf(linebuf, "%s %s admin %s", krb_realm, krb_host, scratch) + < 2) + continue; + if (!strncmp(krb_realm, expand, strlen(expand))) { + (void) fclose(rlm_file); + return(krb_realm); + } + } +#endif /* HAVE_KRB4 */ +#endif +} diff --git a/lib/ZFlsLocs.c b/lib/ZFlsLocs.c new file mode 100644 index 0000000..3708b24 --- /dev/null +++ b/lib/ZFlsLocs.c @@ -0,0 +1,39 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFlushLocations function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZFlushLocations_c[] = "$Id$"; +#endif + +#include + +Code_t +ZFlushLocations(void) +{ + int i; + + if (!__locate_list) + return (ZERR_NONE); + + for (i=0;i<__locate_num;i++) { + free(__locate_list[i].host); + free(__locate_list[i].time); + free(__locate_list[i].tty); + } + + free((char *)__locate_list); + + __locate_list = 0; + __locate_num = 0; + + return (ZERR_NONE); +} diff --git a/lib/ZFlsSubs.c b/lib/ZFlsSubs.c new file mode 100644 index 0000000..ae37949 --- /dev/null +++ b/lib/ZFlsSubs.c @@ -0,0 +1,40 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFlushSubscriptions function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZFlushSubscriptions_c[] = "$Id$"; +#endif + +Code_t +ZFlushSubscriptions(void) +{ + register int i; + + if (!__subscriptions_list) + return (ZERR_NONE); + + for (i=0;i<__subscriptions_num;i++) { + free(__subscriptions_list[i].zsub_class); + free(__subscriptions_list[i].zsub_classinst); + free(__subscriptions_list[i].zsub_recipient); + } + + free((char *)__subscriptions_list); + + __subscriptions_list = 0; + __subscriptions_num = 0; + + return (ZERR_NONE); +} + diff --git a/lib/ZFmtAuth.c b/lib/ZFmtAuth.c new file mode 100644 index 0000000..f658f7c --- /dev/null +++ b/lib/ZFmtAuth.c @@ -0,0 +1,134 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFormatAuthenticNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZFormatAuthenticNotice_c[] = "$Id$"; +#endif + +#include + +#ifdef HAVE_KRB4 +Code_t +ZFormatAuthenticNotice(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len, + C_Block session) +{ + ZNotice_t newnotice; + char *ptr; + int retval, hdrlen; + + newnotice = *notice; + newnotice.z_auth = 1; + newnotice.z_authent_len = 0; + newnotice.z_ascii_authent = ""; + + if ((retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, + &hdrlen, &ptr, NULL)) != ZERR_NONE) + return (retval); + + newnotice.z_checksum = + (ZChecksum_t)des_quad_cksum((void *)buffer, NULL, ptr - buffer, 0, (C_Block *)session); + + if ((retval = Z_FormatRawHeader(&newnotice, buffer, buffer_len, + &hdrlen, NULL, NULL)) != ZERR_NONE) + return (retval); + + ptr = buffer+hdrlen; + + if (newnotice.z_message_len+hdrlen > buffer_len) + return (ZERR_PKTLEN); + + (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len); + + *len = hdrlen+newnotice.z_message_len; + + if (*len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + return (ZERR_NONE); +} +#endif + +#ifdef HAVE_KRB5 +Code_t +ZFormatAuthenticNoticeV5(ZNotice_t *notice, + register char *buffer, + register int buffer_len, + int *len, + krb5_keyblock *keyblock) +{ + ZNotice_t newnotice; + char *ptr; + int retval, hdrlen, hdr_adj; + krb5_enctype enctype; + krb5_cksumtype cksumtype; +#ifdef HAVE_KRB4 + int key_len; +#endif + char *cksum_start, *cstart, *cend; + int cksum_len; + +#ifdef HAVE_KRB4 + key_len = Z_keylen(keyblock); +#endif + retval = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); + if (retval) + return (ZAUTH_FAILED); + +#ifdef HAVE_KRB4 + if (key_len == 8 && (enctype == (krb5_enctype)ENCTYPE_DES_CBC_CRC || + enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD4 || + enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD5)) { + C_Block tmp; + memcpy(&tmp, Z_keydata(keyblock), key_len); + return ZFormatAuthenticNotice(notice, buffer, buffer_len, len, + tmp); + } +#endif + + newnotice = *notice; + newnotice.z_auth = 1; + newnotice.z_authent_len = 0; + newnotice.z_ascii_authent = ""; + + if ((retval = Z_NewFormatRawHeader(&newnotice, buffer, buffer_len, + &hdrlen, + &cksum_start, &cksum_len, &cstart, + &cend)) != ZERR_NONE) + return (retval); + + /* we know this is only called by the server */ + retval = Z_InsertZcodeChecksum(keyblock, &newnotice, buffer, + cksum_start, cksum_len, cstart, cend, + buffer_len, &hdr_adj, 1); + if (retval) + return retval; + + hdrlen += hdr_adj; + + ptr = buffer+hdrlen; + + if (newnotice.z_message_len+hdrlen > buffer_len) + return (ZERR_PKTLEN); + + (void) memcpy(ptr, newnotice.z_message, newnotice.z_message_len); + + *len = hdrlen+newnotice.z_message_len; + + if (*len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + return (ZERR_NONE); +} +#endif diff --git a/lib/ZFmtList.c b/lib/ZFmtList.c new file mode 100644 index 0000000..adad0fb --- /dev/null +++ b/lib/ZFmtList.c @@ -0,0 +1,59 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFormatNoticeList function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZFormatNoticeList_c[] = + "$Id$"; +#endif + +Code_t +ZFormatNoticeList(ZNotice_t *notice, + register char **list, + int nitems, + char **buffer, + int *ret_len, + Z_AuthProc cert_routine) +{ + char header[Z_MAXHEADERLEN]; + register int i; + int hdrlen, size; + char *ptr; + Code_t retval; + + if ((retval = Z_FormatHeader(notice, header, sizeof(header), &hdrlen, + cert_routine)) != ZERR_NONE) + return (retval); + + size = 0; + for (i=0;i + +Code_t +ZFormatNotice(register ZNotice_t *notice, + char **buffer, + int *ret_len, + Z_AuthProc cert_routine) +{ + char header[Z_MAXHEADERLEN]; + int hdrlen; + Code_t retval; + + if ((retval = Z_FormatHeader(notice, header, sizeof(header), &hdrlen, + cert_routine)) != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + /* Length can never be zero, don't have to worry about malloc(0). */ + if (!(*buffer = (char *) malloc((unsigned)*ret_len))) + return (ENOMEM); + + (void) memcpy(*buffer, header, hdrlen); + (void) memcpy(*buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} + +Code_t +ZNewFormatNotice(register ZNotice_t *notice, + char **buffer, + int *ret_len, + Z_AuthProc cert_routine) +{ + char header[Z_MAXHEADERLEN]; + int hdrlen; + Code_t retval; + + if ((retval = Z_NewFormatHeader(notice, header, sizeof(header), &hdrlen, + cert_routine)) != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + /* Length can never be zero, don't have to worry about malloc(0). */ + if (!(*buffer = (char *) malloc((unsigned)*ret_len))) + return (ENOMEM); + + (void) memcpy(*buffer, header, hdrlen); + (void) memcpy(*buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} diff --git a/lib/ZFmtRaw.c b/lib/ZFmtRaw.c new file mode 100644 index 0000000..691ded0 --- /dev/null +++ b/lib/ZFmtRaw.c @@ -0,0 +1,42 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFormatRawNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZFormatRawNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZFormatRawNotice(register ZNotice_t *notice, + char **buffer, + int *ret_len) +{ + char header[Z_MAXHEADERLEN]; + int hdrlen; + Code_t retval; + + if ((retval = Z_FormatRawHeader(notice, header, sizeof(header), + &hdrlen, NULL, NULL)) != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + /* *ret_len is never 0, don't have to worry about malloc(0) */ + if (!(*buffer = (char *) malloc((unsigned) *ret_len))) + return (ENOMEM); + + (void) memcpy(*buffer, header, hdrlen); + (void) memcpy(*buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} diff --git a/lib/ZFmtRawLst.c b/lib/ZFmtRawLst.c new file mode 100644 index 0000000..f08040e --- /dev/null +++ b/lib/ZFmtRawLst.c @@ -0,0 +1,55 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFormatRawNoticeList function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZFormatRawNoticeList_c[] = "$Id$"; +#endif + +#include + +Code_t +ZFormatRawNoticeList(ZNotice_t *notice, + char *list[], + int nitems, + char **buffer, + int *ret_len) +{ + char header[Z_MAXHEADERLEN]; + int hdrlen, i, size; + char *ptr; + Code_t retval; + + if ((retval = Z_FormatRawHeader(notice, header, sizeof(header), + &hdrlen, NULL, NULL)) != ZERR_NONE) + return (retval); + + size = 0; + for (i=0;i + +Code_t +ZFormatSmallRawNoticeList(ZNotice_t *notice, + char *list[], + int nitems, + ZPacket_t buffer, + int *ret_len) +{ + Code_t retval; + int hdrlen, i, size; + char *ptr; + + if ((retval = Z_FormatRawHeader(notice, buffer, Z_MAXHEADERLEN, + &hdrlen, NULL, NULL)) != ZERR_NONE) + return (retval); + + size = 0; + for (i=0;i Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + ptr = buffer+hdrlen; + + for (;nitems;nitems--, list++) { + i = strlen(*list)+1; + (void) memcpy(ptr, *list, i); + ptr += i; + } + + return (ZERR_NONE); +} diff --git a/lib/ZFmtSmRaw.c b/lib/ZFmtSmRaw.c new file mode 100644 index 0000000..3de04ad --- /dev/null +++ b/lib/ZFmtSmRaw.c @@ -0,0 +1,62 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFormatSmallRawNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZFormatRawNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZFormatSmallRawNotice(ZNotice_t *notice, + ZPacket_t buffer, + int *ret_len) +{ + Code_t retval; + int hdrlen; + + if ((retval = Z_FormatRawHeader(notice, buffer, Z_MAXHEADERLEN, + &hdrlen, NULL, NULL)) != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + if (*ret_len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + (void) memcpy(buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} + +Code_t +ZNewFormatSmallRawNotice(ZNotice_t *notice, + ZPacket_t buffer, + int *ret_len) +{ + Code_t retval; + int hdrlen; + + if ((retval = Z_AsciiFormatRawHeader(notice, buffer, Z_MAXHEADERLEN, + &hdrlen, NULL, NULL, NULL, NULL)) + != ZERR_NONE) + return (retval); + + *ret_len = hdrlen+notice->z_message_len; + + if (*ret_len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + (void) memcpy(buffer+hdrlen, notice->z_message, notice->z_message_len); + + return (ZERR_NONE); +} diff --git a/lib/ZFreeNot.c b/lib/ZFreeNot.c new file mode 100644 index 0000000..663dbf8 --- /dev/null +++ b/lib/ZFreeNot.c @@ -0,0 +1,24 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZFreeNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZFreeNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZFreeNotice(ZNotice_t *notice) +{ + free(notice->z_packet); + return 0; +} diff --git a/lib/ZGetLocs.c b/lib/ZGetLocs.c new file mode 100644 index 0000000..1c018da --- /dev/null +++ b/lib/ZGetLocs.c @@ -0,0 +1,42 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZGetLocations function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZGetLocations_c[] = "$Id$"; +#endif + +#include + +#define min(a,b) ((a)<(b)?(a):(b)) + +Code_t +ZGetLocations(ZLocations_t *location, + int *numlocs) +{ + int i; + + if (!__locate_list) + return (ZERR_NOLOCATIONS); + + if (__locate_next == __locate_num) + return (ZERR_NOMORELOCS); + + for (i=0;i + +#ifndef lint +static const char rcsid_ZGetSender_c[] = + "$Id$"; +#endif + +#include + +char * +ZGetSender(void) +{ + struct passwd *pw; + static char *sender = NULL; +#ifdef HAVE_KRB5 + krb5_ccache ccache; + krb5_principal principal; + char *prname; + int result; +#else +#ifdef HAVE_KRB4 + char pname[ANAME_SZ], pinst[INST_SZ], prealm[REALM_SZ]; +#endif +#endif + + /* Return it if already cached */ + if (sender) + return (sender); + +#ifdef HAVE_KRB5 + result = krb5_cc_default(Z_krb5_ctx, &ccache); + if (!result) { + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &principal); + if (!result) { + krb5_unparse_name(Z_krb5_ctx, principal, &prname); + sender = strdup(prname); + krb5_free_unparsed_name(Z_krb5_ctx, prname); + krb5_free_principal(Z_krb5_ctx, principal); + return sender; + } + krb5_cc_close(Z_krb5_ctx, ccache); + } +#else +#ifdef HAVE_KRB4 + if (krb_get_tf_fullname((char *)TKT_FILE, pname, pinst, prealm) == KSUCCESS) + { + sender = malloc(ANAME_SZ+INST_SZ+REALM_SZ+3); + if (sender) + (void) sprintf(sender, "%s%s%s@%s", pname, (pinst[0]?".":""), + pinst, prealm); + return (sender); + } +#endif +#endif + + /* XXX a uid_t is a u_short (now), but getpwuid + * wants an int. AARGH! */ + pw = getpwuid((int) getuid()); + if (!pw) + return ("unknown"); + sender = malloc(strlen(pw->pw_name) + strlen(__Zephyr_realm) + 2); + if (sender) + (void) sprintf(sender, "%s@%s", pw->pw_name, __Zephyr_realm); + return (sender); +} diff --git a/lib/ZGetSubs.c b/lib/ZGetSubs.c new file mode 100644 index 0000000..7f8947f --- /dev/null +++ b/lib/ZGetSubs.c @@ -0,0 +1,44 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZGetSubscriptions function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZGetSubscriptions_c[] = "$Id$"; +#endif + +#include + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +Code_t +ZGetSubscriptions(ZSubscription_t *subscription, + int *numsubs) +{ + int i; + + if (!__subscriptions_list) + return (ZERR_NOSUBSCRIPTIONS); + + if (__subscriptions_next == __subscriptions_num) + return (ZERR_NOMORESUBSCRIPTIONS); + + for (i = 0; i < MIN(*numsubs, __subscriptions_num-__subscriptions_next); i++) + subscription[i] = __subscriptions_list[i+__subscriptions_next]; + + if (__subscriptions_num-__subscriptions_next < *numsubs) + *numsubs = __subscriptions_num-__subscriptions_next; + + __subscriptions_next += *numsubs; + + return (ZERR_NONE); +} diff --git a/lib/ZGetWGPort.c b/lib/ZGetWGPort.c new file mode 100644 index 0000000..b3ef17c --- /dev/null +++ b/lib/ZGetWGPort.c @@ -0,0 +1,41 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZGetWGPort function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZGetWGPort_c[] = "$Id$"; +#endif + +#include + +int +ZGetWGPort(void) +{ + char *envptr, name[128]; + FILE *fp; + int wgport; + + envptr = getenv("WGFILE"); + if (!envptr) { + (void) sprintf(name, "/tmp/wg.%d", getuid()); + envptr = name; + } + if (!(fp = fopen(envptr, "r"))) + return (-1); + + /* if fscanf fails, return -1 via wgport */ + if (fscanf(fp, "%d", &wgport) != 1) + wgport = -1; + + (void) fclose(fp); + + return (wgport); +} diff --git a/lib/ZIfNotice.c b/lib/ZIfNotice.c new file mode 100644 index 0000000..a3652b5 --- /dev/null +++ b/lib/ZIfNotice.c @@ -0,0 +1,62 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZIfNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZIfNotice_c[] = "$Id$"; +#endif + +Code_t +ZIfNotice(ZNotice_t *notice, + struct sockaddr_in *from, + int (*predicate)(ZNotice_t *, void *), + void *args) +{ + ZNotice_t tmpnotice; + Code_t retval; + char *buffer; + struct _Z_InputQ *qptr; + + if ((retval = Z_WaitForComplete()) != ZERR_NONE) + return (retval); + + qptr = Z_GetFirstComplete(); + + for (;;) { + while (qptr) { + if ((retval = ZParseNotice(qptr->packet, qptr->packet_len, + &tmpnotice)) != ZERR_NONE) + return (retval); + if ((*predicate)(&tmpnotice, args)) { + if (!(buffer = (char *) malloc((unsigned) qptr->packet_len))) + return (ENOMEM); + (void) memcpy(buffer, qptr->packet, qptr->packet_len); + if (from) + *from = qptr->from; + if ((retval = ZParseNotice(buffer, qptr->packet_len, + notice)) != ZERR_NONE) { + free(buffer); + return (retval); + } + Z_RemQueue(qptr); + return (ZERR_NONE); + } + qptr = Z_GetNextComplete(qptr); + } + if ((retval = Z_ReadWait()) != ZERR_NONE) + return (retval); + qptr = Z_GetFirstComplete(); /* need to look over all of + the queued messages, in case + a fragment has been reassembled */ + } +} diff --git a/lib/ZInit.c b/lib/ZInit.c new file mode 100644 index 0000000..abaa2a4 --- /dev/null +++ b/lib/ZInit.c @@ -0,0 +1,435 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZInitialize function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZInitialize_c[] = + "$Id$"; +#endif + +#include + +#include +#ifdef HAVE_KRB4 +#include +#endif +#ifdef HAVE_KRB5 +#include +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +#if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM) +#include + +static int z_get_host_realm_replacement(char *, char ***); +#endif + +#if defined(HAVE_KRB5) +int Zauthtype = 5; +#elif defined(HAVE_KRB4) +int Zauthtype = 4; +#else +int Zauthtype = 0; +#endif + +Code_t +ZInitialize(void) +{ + struct servent *hmserv; + struct hostent *hostent; + char addr[4], hostname[NS_MAXDNAME]; + struct in_addr servaddr; + struct sockaddr_in sin; + unsigned int sinsize = sizeof(sin); + int s; + Code_t code; + ZNotice_t notice; +#ifdef HAVE_KRB5 + char **krealms = NULL; +#else +#ifdef HAVE_KRB4 + char *krealm = NULL; + int krbval; + char d1[ANAME_SZ], d2[INST_SZ]; +#endif +#endif + + /* On OS X you don't need to initialize the Kerberos error tables + as long as you link with -framework Kerberos */ +#if !(defined(__APPLE__) && defined(__MACH__)) +#ifdef HAVE_KRB4 + initialize_krb_error_table(); +#endif +#ifdef HAVE_KRB5 + initialize_krb5_error_table(); +#endif +#endif + +#if defined(__APPLE__) && defined(__MACH__) + add_error_table(&et_zeph_error_table); +#else + initialize_zeph_error_table(); +#endif + + (void) memset((char *)&__HM_addr, 0, sizeof(__HM_addr)); + + __HM_addr.sin_family = AF_INET; + + /* Set up local loopback address for HostManager */ + addr[0] = 127; + addr[1] = 0; + addr[2] = 0; + addr[3] = 1; + + hmserv = (struct servent *)getservbyname(HM_SVCNAME, "udp"); + __HM_addr.sin_port = (hmserv) ? hmserv->s_port : HM_SVC_FALLBACK; + + (void) memcpy((char *)&__HM_addr.sin_addr, addr, 4); + + __HM_set = 0; + + /* Initialize the input queue */ + __Q_Tail = NULL; + __Q_Head = NULL; + +#ifdef HAVE_KRB5 + if ((code = krb5_init_context(&Z_krb5_ctx))) + return(code); +#endif + + /* if the application is a server, there might not be a zhm. The + code will fall back to something which might not be "right", + but this is is ok, since none of the servers call krb_rd_req. */ + + servaddr.s_addr = INADDR_NONE; + if (! __Zephyr_server) { + if ((code = ZOpenPort(NULL)) != ZERR_NONE) + return(code); + + if ((code = ZhmStat(NULL, ¬ice)) != ZERR_NONE) + return(code); + + ZClosePort(); + + /* the first field, which is NUL-terminated, is the server name. + If this code ever support a multiplexing zhm, this will have to + be made smarter, and probably per-message */ + +#ifdef HAVE_KRB5 +#ifndef KRB5_REFERRAL_REALM + code = krb5_get_host_realm(Z_krb5_ctx, notice.z_message, &krealms); + if (code) + return(code); +#else + code = z_get_host_realm_replacement(notice.z_message, &krealms); +#endif +#else +#ifdef HAVE_KRB4 + krealm = krb_realmofhost(notice.z_message); +#endif +#endif + hostent = gethostbyname(notice.z_message); + if (hostent && hostent->h_addrtype == AF_INET) + memcpy(&servaddr, hostent->h_addr, sizeof(servaddr)); + + ZFreeNotice(¬ice); + } + +#ifdef HAVE_KRB5 + if (krealms) { + strcpy(__Zephyr_realm, krealms[0]); + krb5_free_host_realm(Z_krb5_ctx, krealms); + } else { + char *p; /* XXX define this somewhere portable */ + /* XXX check ticket file here */ + code = krb5_get_default_realm(Z_krb5_ctx, &p); + if (code) + return code; + strcpy(__Zephyr_realm, p); +#ifdef HAVE_KRB5_FREE_DEFAULT_REALM + krb5_free_default_realm(Z_krb5_ctx, p); +#else + free(p); +#endif + } +#else +#ifdef HAVE_KRB4 + if (krealm) { + strcpy(__Zephyr_realm, krealm); + } else if ((krb_get_tf_fullname(TKT_FILE, d1, d2, __Zephyr_realm) + != KSUCCESS) && + ((krbval = krb_get_lrealm(__Zephyr_realm, 1)) != KSUCCESS)) { + return (krbval); + } +#else + strcpy(__Zephyr_realm, "local-realm"); +#endif +#endif + + __My_addr.s_addr = INADDR_NONE; + if (servaddr.s_addr != INADDR_NONE) { + /* Try to get the local interface address by connecting a UDP + * socket to the server address and getting the local address. + * Some broken operating systems (e.g. Solaris 2.0-2.5) yield + * INADDR_ANY (zero), so we have to check for that. */ + s = socket(AF_INET, SOCK_DGRAM, 0); + if (s != -1) { + memset(&sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + memcpy(&sin.sin_addr, &servaddr, sizeof(servaddr)); + sin.sin_port = HM_SRV_SVC_FALLBACK; + if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) == 0 + && getsockname(s, (struct sockaddr *) &sin, &sinsize) == 0 + && sin.sin_addr.s_addr != 0) + memcpy(&__My_addr, &sin.sin_addr, sizeof(__My_addr)); + close(s); + } + } + if (__My_addr.s_addr == INADDR_NONE) { + /* We couldn't figure out the local interface address by the + * above method. Try by resolving the local hostname. (This + * is a pretty broken thing to do, and unfortunately what we + * always do on server machines.) */ + if (gethostname(hostname, sizeof(hostname)) == 0) { + hostent = gethostbyname(hostname); + if (hostent && hostent->h_addrtype == AF_INET) + memcpy(&__My_addr, hostent->h_addr, sizeof(__My_addr)); + } + } + /* If the above methods failed, zero out __My_addr so things will + * sort of kind of work. */ + if (__My_addr.s_addr == INADDR_NONE) + __My_addr.s_addr = 0; + + /* Get the sender so we can cache it */ + (void) ZGetSender(); + + return (ZERR_NONE); +} + +const char * ZGetRealm (void) { + return __Zephyr_realm; +} + +int ZGetFD (void) { + return __Zephyr_fd; +} + +int ZQLength (void) { + return __Q_CompleteLength; +} + +struct sockaddr_in ZGetDestAddr (void) { + return __HM_addr; +} + +#if defined(HAVE_KRB5) && defined(KRB5_REFERRAL_REALM) +#include +#include +#include + +static int txt_lookup(char *qname, char **result) { + int ret, buflen, left; + void *buf = NULL; + void *bufend = NULL; + HEADER *hdr; + unsigned char *p; + char dname[NS_MAXDNAME]; + int queries, answers; + + ret = res_init(); + if (ret < 0) + return -1; + + buflen = 0; + do { + buflen = buflen ? buflen * 2 : 2048; + buf = (buf == NULL) ? malloc(buflen) : realloc(buf, buflen); + + ret = res_search(qname, C_IN, T_TXT, buf, buflen); + } while (ret > buflen); + + if (ret < 0) + return -1; + + buflen = ret; + left = ret; + bufend = buflen + (unsigned char *)buf; + + hdr = (HEADER *)buf; + p = buf; + queries = ntohs(hdr->qdcount); + answers = ntohs(hdr->ancount); + p += sizeof (HEADER); + left -= sizeof (HEADER); + + while (queries--) { + ret = dn_expand(buf, bufend, p, dname, sizeof dname); + if (ret < 0 || (ret + 4) > left) + return -1; + p += ret + 4; + left -= ret + 4; + } + + if (!ret || !answers) + return -1; + + while (answers--) { + int class, type; + + ret = dn_expand(buf, bufend, p, dname, sizeof dname); + if (ret < 0 || ret > left) + return -1; + p += ret; + left -= ret; + + if (left < 10) + return -1; + type = ntohs(*(uint16_t *)p); + p += 2; + class = ntohs(*(uint16_t *)p); + p += 6; + ret = ntohs(*(uint16_t *)p); + p += 2; + left -= 10; + + if (ret > left) + return -1; + + if (class == C_IN && type == T_TXT) { + *result = malloc(ret); + if (*result == NULL) + return -1; + memcpy(*result, p + 1, ret - 1); + (*result)[ret - 1] = 0; + return 0; + } + + p += ret; + } + return -1; +} + +static int +z_get_host_realm_replacement(char *inhost, char ***krealms) { + char *host, *p; + char *realm = NULL; + char *default_realm = NULL; + char *tmp_realm; + char *qname; + profile_t prof; + int ret; + + host = strdup(inhost); + + for (p = host; *p; p++) + if (isupper(*p)) + *p = tolower(*p); + + p = host; + while (p && !default_realm) { + if (*p == '.') { + p++; + if (default_realm == NULL) { + default_realm = p; + } + } else { + p = strchr(p, '.'); + } + } + + p = host; + tmp_realm = NULL; + + krb5_get_profile(Z_krb5_ctx, &prof); + while(p) { + ret = profile_get_string(prof, "domain_realm", p, + 0, NULL, &tmp_realm); + if (ret) { + profile_abandon(prof); + free(host); + return ret; + } + + if (tmp_realm != NULL) + break; + + if (*p == '.') + p++; + else + p = strchr(p, '.'); + } + + if (tmp_realm != NULL) { + realm = strdup(tmp_realm); + profile_release_string(tmp_realm); + if (realm == NULL) { + free(host); + return errno; + } + } + profile_abandon(prof); + + if (realm == NULL) { + p = host; + do { + qname = malloc(strlen(p) + strlen("_kerberos..") + 1); + if (qname == NULL) { + free(host); + return errno; + } + sprintf(qname, "_kerberos.%s.", p); + ret = txt_lookup(qname, &realm); + free(qname); + + p = strchr(p,'.'); + if (p) + p++; + } while (ret && p && p[0]); + } + + if (realm == NULL) { + if (default_realm != NULL) { + realm = strdup(default_realm); + if (realm == NULL) { + free(host); + return errno; + } + + for (p = realm; *p; p++) + if (islower(*p)) + *p = toupper(*p); + } else { + ret = krb5_get_default_realm(Z_krb5_ctx, &realm); + if (ret) { + free(host); + return ret; + } + } + } + + free(host); + + if ((*krealms = calloc(2, sizeof(*krealms))) == NULL) { + if (realm) + free(realm); + return errno; + } + + (*krealms)[0] = realm; + (*krealms)[1] = NULL; + + return 0; +} +#endif diff --git a/lib/ZLocations.c b/lib/ZLocations.c new file mode 100644 index 0000000..e7537da --- /dev/null +++ b/lib/ZLocations.c @@ -0,0 +1,192 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSetLocation, ZUnsetLocation, and + * ZFlushMyLocations functions. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZLocations_c[] = + "$Id$"; +#endif + +#include + +#include + +static char host[NS_MAXDNAME], *mytty = "space"; +static int location_info_set = 0; + +Code_t +ZInitLocationInfo(char *hostname, + char *tty) +{ + char *ttyp, *p; + struct hostent *hent; + + if (hostname) { + strcpy(host, hostname); + } else { + if (gethostname(host, sizeof(host)) < 0) + return (errno); + hent = gethostbyname(host); + if (hent) { + (void) strncpy(host, hent->h_name, sizeof(host)); + host[sizeof(host) - 1] = '\0'; + } + } + if (tty) { + mytty = strdup(tty); + } else { + ttyp = ttyname(0); + if (ttyp && *ttyp) { + p = strchr(ttyp + 1, '/'); + mytty = strdup(p ? p + 1 : ttyp); + } else { + mytty = strdup("unknown"); + } + } + if (mytty == NULL) + return errno; + location_info_set = 1; + return (ZERR_NONE); +} + +Code_t +ZSetLocation(char *exposure) +{ + return (Z_SendLocation(LOGIN_CLASS, exposure, ZGetSender(), ZAUTH, + "$sender logged in to $1 on $3 at $2")); +} + +Code_t +ZUnsetLocation(void) +{ + return (Z_SendLocation(LOGIN_CLASS, LOGIN_USER_LOGOUT, ZGetSender(), + ZNOAUTH, "$sender logged out of $1 on $3 at $2")); +} + +Code_t +ZFlushMyLocations(void) +{ + return (Z_SendLocation(LOGIN_CLASS, LOGIN_USER_FLUSH, ZGetSender(), + ZAUTH, "")); +} + +Code_t +ZFlushUserLocations(char *target) +{ + return (Z_SendLocation(LOGIN_CLASS, LOGIN_USER_FLUSH, target, ZAUTH, "")); +} + +char * +ZParseExposureLevel(char *text) +{ + if (!strcasecmp(text, EXPOSE_NONE)) + return (EXPOSE_NONE); + else if (!strcasecmp(text, EXPOSE_OPSTAFF)) + return (EXPOSE_OPSTAFF); + else if (!strcasecmp(text, EXPOSE_REALMVIS)) + return (EXPOSE_REALMVIS); + else if (!strcasecmp(text, EXPOSE_REALMANN)) + return (EXPOSE_REALMANN); + else if (!strcasecmp(text, EXPOSE_NETVIS)) + return (EXPOSE_NETVIS); + else if (!strcasecmp(text, EXPOSE_NETANN)) + return (EXPOSE_NETANN); + else + return(NULL); +} + +/* lifted from lib/ZSendPkt.c wait_for_hmack, but waits for SERVACK instead */ +static int +wait_for_srvack(ZNotice_t *notice, void *uid) +{ + return ((notice->z_kind == SERVACK || notice->z_kind == SERVNAK) + && ZCompareUID(¬ice->z_uid, (ZUnique_Id_t *)uid)); +} + +Code_t +Z_SendLocation(char *class, + char *opcode, + char *target, + Z_AuthProc auth, + char *format) +{ + int retval; + time_t ourtime; + ZNotice_t notice, retnotice; + char *bptr[3]; + short wg_port = ZGetWGPort(); + + if (!location_info_set) + ZInitLocationInfo(NULL, NULL); + + memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = ACKED; + notice.z_port = (u_short) ((wg_port == -1) ? 0 : wg_port); + notice.z_class = class; + notice.z_class_inst = target; + notice.z_opcode = opcode; + notice.z_sender = 0; + notice.z_recipient = ""; + notice.z_num_other_fields = 0; + notice.z_default_format = format; + + bptr[0] = host; + ourtime = time((time_t *)0); + bptr[1] = ctime(&ourtime); + bptr[1][strlen(bptr[1])-1] = '\0'; + bptr[2] = mytty; + + if ((retval = ZSendList(¬ice, bptr, 3, auth)) != ZERR_NONE) + return (retval); + + retval = Z_WaitForNotice (&retnotice, wait_for_srvack, ¬ice.z_uid, + SRV_TIMEOUT); + if (retval != ZERR_NONE) + return retval; + + if (retnotice.z_kind == SERVNAK) { + if (!retnotice.z_message_len) { + ZFreeNotice(&retnotice); + return (ZERR_SERVNAK); + } + if (!strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) { + ZFreeNotice(&retnotice); + return (ZERR_AUTHFAIL); + } + if (!strcmp(retnotice.z_message, ZSRVACK_FAIL)) { + ZFreeNotice(&retnotice); + return (ZERR_LOGINFAIL); + } + ZFreeNotice(&retnotice); + return (ZERR_SERVNAK); + } + + if (retnotice.z_kind != SERVACK) { + ZFreeNotice(&retnotice); + return (ZERR_INTERNAL); + } + + if (!retnotice.z_message_len) { + ZFreeNotice(&retnotice); + return (ZERR_INTERNAL); + } + + if (strcmp(retnotice.z_message, ZSRVACK_SENT) && + strcmp(retnotice.z_message, ZSRVACK_NOTSENT)) { + ZFreeNotice(&retnotice); + return (ZERR_INTERNAL); + } + + ZFreeNotice(&retnotice); + + return (ZERR_NONE); +} diff --git a/lib/ZMakeAscii.c b/lib/ZMakeAscii.c new file mode 100644 index 0000000..cd0e24b --- /dev/null +++ b/lib/ZMakeAscii.c @@ -0,0 +1,92 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZMakeAscii function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include + +#ifndef lint +static const char rcsid_ZMakeAscii_c[] = "$Id$"; +#endif + +static char *itox_chars = "0123456789ABCDEF"; + +Code_t +ZMakeAscii(register char *ptr, + int len, + unsigned char *field, + int num) +{ + int i; + + for (i=0;i> 4)]; + *ptr++ = itox_chars[(int) (field[i] & 0xf)]; + len -= 2; + } + + *ptr = '\0'; + return ZERR_NONE; +} + +Code_t +ZMakeAscii32(register char *ptr, + int len, + unsigned long value) +{ + if (len < 11) + return ZERR_FIELDLEN; + *ptr++ = '0'; + *ptr++ = 'x'; + *ptr++ = itox_chars[(value >> 28) & 0xf]; + *ptr++ = itox_chars[(value >> 24) & 0xf]; + *ptr++ = itox_chars[(value >> 20) & 0xf]; + *ptr++ = itox_chars[(value >> 16) & 0xf]; + *ptr++ = itox_chars[(value >> 12) & 0xf]; + *ptr++ = itox_chars[(value >> 8) & 0xf]; + *ptr++ = itox_chars[(value >> 4) & 0xf]; + *ptr++ = itox_chars[(value >> 0) & 0xf]; + *ptr = 0; + return ZERR_NONE; +} + +Code_t +ZMakeAscii16(register char *ptr, + int len, + unsigned int value) +{ + if (len < 7) + return ZERR_FIELDLEN; + *ptr++ = '0'; + *ptr++ = 'x'; + *ptr++ = itox_chars[(value >> 12) & 0xf]; + *ptr++ = itox_chars[(value >> 8) & 0xf]; + *ptr++ = itox_chars[(value >> 4) & 0xf]; + *ptr++ = itox_chars[(value >> 0) & 0xf]; + *ptr = 0; + return ZERR_NONE; +} + diff --git a/lib/ZMakeZcode.c b/lib/ZMakeZcode.c new file mode 100644 index 0000000..63397a5 --- /dev/null +++ b/lib/ZMakeZcode.c @@ -0,0 +1,80 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZMakeZcode function. + * + * Created by: Jeffrey Hutzelman + * + * $Id$ + * + * Copyright (c) 1987, 2002 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include + +#ifndef lint +static const char rcsid_ZMakeZcode_c[] = "$Id$"; +#endif + +Code_t +ZMakeZcode32(char *ptr, + int len, + unsigned long val) +{ + unsigned char buf[4]; + buf[0] = (val >> 24) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[3] = val & 0xff; + return ZMakeZcode(ptr, len, buf, 4); +} + +Code_t +ZMakeZcode(register char *ptr, + int len, + unsigned char *field, + int num) +{ + int i; + + /* + * This optimistic check lets us discover quickly if the buffer + * is not even large enough to hold the field without escapes. + * It also insures we'll have space for the leading 'Z' and the + * trailing NUL. Note that this does _not_ remove the need for + * checking length as we encode. + */ + if (len < num + 2) + return ZERR_FIELDLEN; + *ptr++ = 'Z'; + --len; + for (i=0;i + +#ifndef lint +static const char rcsid_ZMakeAuthentication_c[] = "$Id$"; +#endif + +#ifdef HAVE_KRB4 +#include +#endif + +#if defined(HAVE_KRB5) && !HAVE_KRB5_FREE_DATA +#define krb5_free_data(ctx, dat) free((dat)->data) +#endif + +Code_t +ZResetAuthentication(void) +{ + return ZERR_NONE; +} + +Code_t +ZMakeAuthentication(register ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len) +{ +#ifdef HAVE_KRB5 + return ZMakeZcodeAuthentication(notice, buffer, buffer_len, len/*?XXX*/); +#else +#ifdef HAVE_KRB4 + int result; + KTEXT_ST authent; + char *cstart, *cend; + ZChecksum_t checksum; + CREDENTIALS cred; + C_Block *session; + + result = krb_mk_req(&authent, SERVER_SERVICE, + SERVER_INSTANCE, __Zephyr_realm, 0); + if (result != MK_AP_OK) + return (result+krb_err_base); + result = krb_get_cred(SERVER_SERVICE, SERVER_INSTANCE, + __Zephyr_realm, &cred); + if (result != KSUCCESS) + return (result+krb_err_base); + + session = (C_Block *)cred.session; + + notice->z_auth = 1; + notice->z_authent_len = authent.length; + notice->z_ascii_authent = (char *)malloc((unsigned)authent.length*3); + /* zero length authent is an error, so malloc(0) is not a problem */ + if (!notice->z_ascii_authent) + return (ENOMEM); + if ((result = ZMakeAscii(notice->z_ascii_authent, + authent.length*3, + authent.dat, + authent.length)) != ZERR_NONE) { + free(notice->z_ascii_authent); + return (result); + } + result = Z_FormatRawHeader(notice, buffer, buffer_len, len, &cstart, + &cend); + free(notice->z_ascii_authent); + notice->z_authent_len = 0; + if (result) + return(result); + + /* Compute a checksum over the header and message. */ + checksum = des_quad_cksum((unsigned char *)buffer, NULL, cstart - buffer, 0, session); + checksum ^= des_quad_cksum((unsigned char *)cend, NULL, buffer + *len - cend, 0, + session); + checksum ^= des_quad_cksum((unsigned char *)notice->z_message, NULL, notice->z_message_len, + 0, session); + notice->z_checksum = checksum; + ZMakeAscii32(cstart, buffer + buffer_len - cstart, checksum); + + return (ZERR_NONE); +#else + notice->z_checksum = 0; + notice->z_auth = 1; + notice->z_authent_len = 0; + notice->z_ascii_authent = ""; + return (Z_FormatRawHeader(notice, buffer, buffer_len, len, NULL, NULL)); +#endif +#endif +} + +Code_t +Z_MakeAuthenticationSaveKey(register ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len) +{ +#ifndef HAVE_KRB5 + /* Key management not implemented for krb4. */ + return ZMakeAuthentication(notice, buffer, buffer_len, len); +#else + Code_t result; + krb5_creds *creds = NULL; + krb5_keyblock *keyblock; + struct _Z_SessionKey *savedkey; + + /* Look up creds and checksum the notice. */ + if ((result = ZGetCreds(&creds))) + return result; + if ((result = Z_MakeZcodeAuthentication(notice, buffer, buffer_len, len, + creds))) { + krb5_free_creds(Z_krb5_ctx, creds); + return result; + } + + /* Save the key. */ + keyblock = Z_credskey(creds); + + if (Z_keys_head && + Z_keys_head->keyblock->enctype == keyblock->enctype && + Z_keys_head->keyblock->length == keyblock->length && + memcmp(Z_keys_head->keyblock->contents, keyblock->contents, + keyblock->length) == 0) { + /* + * Optimization: if the key hasn't changed, replace the current entry, + * rather than make a new one. + */ + Z_keys_head->send_time = time(NULL); + Z_keys_head->first_use = 0; + } else { + savedkey = (struct _Z_SessionKey *)malloc(sizeof(struct _Z_SessionKey)); + if (!savedkey) { + krb5_free_creds(Z_krb5_ctx, creds); + return ENOMEM; + } + + if ((result = krb5_copy_keyblock(Z_krb5_ctx, keyblock, &savedkey->keyblock))) { + free(savedkey); + krb5_free_creds(Z_krb5_ctx, creds); + return result; + } + savedkey->send_time = time(NULL); + savedkey->first_use = 0; + + savedkey->prev = NULL; + savedkey->next = Z_keys_head; + if (Z_keys_head) + Z_keys_head->prev = savedkey; + Z_keys_head = savedkey; + if (!Z_keys_tail) + Z_keys_tail = savedkey; + } + + krb5_free_creds(Z_krb5_ctx, creds); + return result; +#endif +} + +/* only used by server? */ +Code_t +ZMakeZcodeAuthentication(register ZNotice_t *notice, + char *buffer, + int buffer_len, + int *phdr_len) +{ + return ZMakeZcodeRealmAuthentication(notice, buffer, buffer_len, phdr_len, + __Zephyr_realm); +} + +Code_t +ZMakeZcodeRealmAuthentication(register ZNotice_t *notice, + char *buffer, + int buffer_len, + int *phdr_len, + char *realm) +{ +#ifdef HAVE_KRB5 + Code_t result; + krb5_creds *creds = NULL; + + result = ZGetCredsRealm(&creds, realm); + if (!result) + result = Z_MakeZcodeAuthentication(notice, buffer, buffer_len, phdr_len, + creds); + if (creds != NULL) + krb5_free_creds(Z_krb5_ctx, creds); + return result; +#else /* HAVE_KRB5 */ + return ZERR_INTERNAL; +#endif +} + +#ifdef HAVE_KRB5 +Code_t +Z_MakeZcodeAuthentication(register ZNotice_t *notice, + char *buffer, + int buffer_len, + int *phdr_len, + krb5_creds *creds) +{ + krb5_error_code result = 0; + krb5_keyblock *keyblock; + krb5_auth_context authctx; + krb5_data *authent; + char *cksum_start, *cstart, *cend; + int cksum_len, zcode_len = 0, phdr_adj = 0; + + notice->z_ascii_authent = NULL; + + keyblock = Z_credskey(creds); + + authent = (krb5_data *)malloc(sizeof(krb5_data)); + if (authent == NULL) + result = ENOMEM; + authent->data = NULL; /* so that we can blithely krb5_fre_data_contents on + the way out */ + + if (!result) + result = krb5_auth_con_init(Z_krb5_ctx, &authctx); + + if (!result) { + result = krb5_mk_req_extended(Z_krb5_ctx, &authctx, 0 /* options */, + 0 /* in_data */, creds, authent); + krb5_auth_con_free(Z_krb5_ctx, authctx); + } + if (!result || result == KRB5KRB_AP_ERR_TKT_EXPIRED) { + notice->z_auth = 1; + if (result == 0) { + notice->z_authent_len = authent->length; + } else { + notice->z_authent_len = 0; + result = 0; + } + zcode_len = notice->z_authent_len * 2 + 2; /* 2x growth plus Z and null */ + notice->z_ascii_authent = (char *)malloc(zcode_len); + if (notice->z_ascii_authent == NULL) + result = ENOMEM; + } + if (!result) + result = ZMakeZcode(notice->z_ascii_authent, zcode_len, + (unsigned char *)authent->data, notice->z_authent_len); + + /* format the notice header, with a zero checksum */ + if (!result) + result = Z_NewFormatRawHeader(notice, buffer, buffer_len, phdr_len, + &cksum_start, &cksum_len, &cstart, &cend); + notice->z_authent_len = 0; + if (!result) + result = Z_InsertZcodeChecksum(keyblock, notice, buffer, cksum_start, + cksum_len, cstart, cend, buffer_len, + &phdr_adj, 0); + if (!result) + *phdr_len += phdr_adj; + + if (notice->z_ascii_authent != NULL) + free(notice->z_ascii_authent); + krb5_free_data_contents(Z_krb5_ctx, authent); + if (authent != NULL) + free(authent); + return result; +} + +int +ZGetCreds(krb5_creds **creds_out) +{ + return ZGetCredsRealm(creds_out, __Zephyr_realm); +} + +int +ZGetCredsRealm(krb5_creds **creds_out, + char *realm) +{ + krb5_creds creds_in; + krb5_creds creds_tmp; + krb5_ccache ccache; /* XXX make this a global or static?*/ + int result; + + result = krb5_cc_default(Z_krb5_ctx, &ccache); + if (result) + return result; + + memset((char *)&creds_in, 0, sizeof(creds_in)); + result = krb5_build_principal(Z_krb5_ctx, &creds_in.server, + strlen(realm), + realm, + SERVER_SERVICE, SERVER_INSTANCE, + NULL); + if (result) { + krb5_cc_close(Z_krb5_ctx, ccache); + return result; + } + + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client); + if (!result) { + result = krb5_cc_retrieve_cred(Z_krb5_ctx, ccache, +#ifdef KRB5_TC_SUPPORTED_KTYPES + KRB5_TC_SUPPORTED_KTYPES, /* MIT */ +#else + 0, /* Heimdal or other Space KRB5 */ +#endif + &creds_in, &creds_tmp); + if (!result) { + *creds_out = malloc(sizeof(creds_tmp)); + if (*creds_out == NULL) + result = errno; + else + memcpy(*creds_out, &creds_tmp, sizeof(creds_tmp)); + } + } + if (result == KRB5_CC_NOTFOUND || result == KRB5_CC_END) + result = krb5_get_credentials(Z_krb5_ctx, 0, ccache, &creds_in, creds_out); + + krb5_cc_close(Z_krb5_ctx, ccache); + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* I also hope this is ok */ + + return result; +} +#endif diff --git a/lib/ZNewLocU.c b/lib/ZNewLocU.c new file mode 100644 index 0000000..c598c26 --- /dev/null +++ b/lib/ZNewLocU.c @@ -0,0 +1,49 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZNewLocateUser function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZNewLocateUser_c[] = + "$Id$"; +#endif + +Code_t +ZLocateUser(char *user, + int *nlocs, + Z_AuthProc auth) +{ + Code_t retval; + ZNotice_t notice; + ZAsyncLocateData_t zald; + + (void) ZFlushLocations(); /* ZFlushLocations never fails (the library + is allowed to know this). */ + + if ((retval = ZRequestLocations(user, &zald, UNACKED, auth)) != ZERR_NONE) + return(retval); + + retval = Z_WaitForNotice (¬ice, ZCompareALDPred, &zald, SRV_TIMEOUT); + if (retval == ZERR_NONOTICE) + return ETIMEDOUT; + if (retval != ZERR_NONE) + return retval; + + if ((retval = ZParseLocations(¬ice, &zald, nlocs, NULL)) != ZERR_NONE) { + ZFreeNotice(¬ice); + return(retval); + } + + ZFreeNotice(¬ice); + ZFreeALD(&zald); + return(ZERR_NONE); +} diff --git a/lib/ZOpenPort.c b/lib/ZOpenPort.c new file mode 100644 index 0000000..b15ee28 --- /dev/null +++ b/lib/ZOpenPort.c @@ -0,0 +1,73 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZOpenPort function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZOpenPort_c[] = "$Id$"; +#endif + +#include +#include + +Code_t +ZOpenPort(u_short *port) +{ + struct sockaddr_in bindin; + unsigned int len; + int val = 1; + + (void) ZClosePort(); + + if ((__Zephyr_fd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + __Zephyr_fd = -1; + return errno; + } + + bindin.sin_family = AF_INET; + + if (port && *port) { + bindin.sin_port = *port; + if (setsockopt(__Zephyr_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val) < 0) + return errno; + } else { + bindin.sin_port = 0; + } + + bindin.sin_addr.s_addr = INADDR_ANY; + + if (bind(__Zephyr_fd, (struct sockaddr *)&bindin, sizeof(bindin)) < 0) { + if (errno == EADDRINUSE && port && *port) + return ZERR_PORTINUSE; + else + return errno; + } + + if (port && *port) { + /* turn SO_REUSEADDR back off so no one else can steal it */ + val = 0; + if (setsockopt(__Zephyr_fd, SOL_SOCKET, SO_REUSEADDR, &val, sizeof val) < 0) + return errno; + } + + if (!bindin.sin_port) { + len = sizeof(bindin); + if (getsockname(__Zephyr_fd, (struct sockaddr *)&bindin, &len)) + return errno; + } + + __Zephyr_port = bindin.sin_port; + __Zephyr_open = 1; + + if (port) + *port = bindin.sin_port; + + return ZERR_NONE; +} diff --git a/lib/ZParseNot.c b/lib/ZParseNot.c new file mode 100644 index 0000000..48311b5 --- /dev/null +++ b/lib/ZParseNot.c @@ -0,0 +1,315 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZParseNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZParseNotice_c[] = + "$Id$"; +#endif + +#include +#include +#include +#include +#include + +inline static int +_bad_packet(int line, char *where, ZNotice_t *notice, char *what) { + if (__Zephyr_server) { + syslog(LOG_ERR, "ZParseNotice: bad packet (%s) from %s.%d at line %d", + what, inet_ntoa(notice->z_uid.zuid_addr), notice->z_port, line); + } else { +#ifdef Z_DEBUG + Z_debug("ZParseNotice: bad packet (%s) from %s.%d at line %d", + what, inet_ntoa(notice->z_uid.zuid_addr), notice->z_port, line); +#endif + } + + return ZERR_BADPKT; +} + +/* Skip to the next NUL-terminated field in the packet. */ +inline static char * +next_field(char *ptr, + char *end) +{ + while (ptr < end && *ptr != '\0') + ptr++; + if (ptr < end) + ptr++; + return (ptr); +} + +Code_t +ZParseNotice(char *buffer, + int len, + ZNotice_t *notice) +{ + char *ptr, *end; + unsigned long temp; + int maj, numfields, i; + +#ifndef __LINE__ +#define __LINE__ -1 +#endif +#define BAD_PACKET(what) return _bad_packet(__LINE__, ptr, notice, what) + + (void) memset((char *)notice, 0, sizeof(ZNotice_t)); + + ptr = buffer; + end = buffer+len; + + notice->z_packet = buffer; + + notice->z_version = ptr; + if (strncmp(ptr, ZVERSIONHDR, sizeof(ZVERSIONHDR) - 1)) + return (ZERR_VERS); + ptr += sizeof(ZVERSIONHDR) - 1; + if (!*ptr) + BAD_PACKET("null version string"); + + maj = atoi(ptr); + if (maj != ZVERSIONMAJOR) + return (ZERR_VERS); + ptr = next_field(ptr, end); + + if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) + BAD_PACKET("parsing num_hdr_fields"); + numfields = temp; + notice->z_num_hdr_fields = numfields; + ptr = next_field(ptr, end); + + /*XXX 3 */ + numfields -= 2; /* numfields, version, and checksum */ + if (numfields < 0) + BAD_PACKET("no header fields"); + + if (numfields && ptr < end) { + if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) + BAD_PACKET("parsing kind"); + notice->z_kind = (ZNotice_Kind_t)temp; + numfields--; + ptr = next_field(ptr, end); + } + else + BAD_PACKET("missing kind"); + + if (numfields && ptr < end) { + if (ZReadAscii(ptr, end-ptr, (unsigned char *)¬ice->z_uid, + sizeof(ZUnique_Id_t)) == ZERR_BADFIELD) + BAD_PACKET("parsing uid"); + notice->z_time.tv_sec = ntohl((u_long) notice->z_uid.tv.tv_sec); + notice->z_time.tv_usec = ntohl((u_long) notice->z_uid.tv.tv_usec); + numfields--; + ptr = next_field(ptr, end); + } + else + BAD_PACKET("missing uid"); + + if (numfields && ptr < end) { + if (ZReadAscii16(ptr, end-ptr, ¬ice->z_port) == ZERR_BADFIELD) + BAD_PACKET("parsing port"); + notice->z_port = htons(notice->z_port); + numfields--; + ptr = next_field(ptr, end); + } + else + BAD_PACKET("missing port"); + + if (numfields && ptr < end) { + if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) + BAD_PACKET("parsing auth"); + notice->z_auth = temp; + numfields--; + ptr = next_field(ptr, end); + } + else + BAD_PACKET("missing auth"); + notice->z_checked_auth = ZAUTH_UNSET; + + if (numfields && ptr < end) { + if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) + BAD_PACKET("parsing authenticator length"); + notice->z_authent_len = temp; + numfields--; + ptr = next_field(ptr, end); + } + else + BAD_PACKET("missing authenticator length"); + + if (numfields && ptr < end) { + notice->z_ascii_authent = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + BAD_PACKET("missing authenticator field"); + + if (numfields && ptr < end) { + notice->z_class = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_class = ""; + + if (numfields && ptr < end) { + notice->z_class_inst = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_class_inst = ""; + + if (numfields && ptr < end) { + notice->z_opcode = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_opcode = ""; + + if (numfields && ptr < end) { + notice->z_sender = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_sender = ""; + + if (numfields && ptr < end) { + notice->z_recipient = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_recipient = ""; + + if (numfields && ptr < end) { + notice->z_default_format = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_default_format = ""; + + if (numfields && ptr < end) { + notice->z_ascii_checksum = ptr; + + if (ZReadAscii32(ptr, end-ptr, &temp) == ZERR_BADFIELD) + notice->z_checksum = 0; + else + notice->z_checksum = temp; + + numfields--; + ptr = next_field (ptr, end); + } + else + { + notice->z_ascii_checksum = ""; + notice->z_checksum = 0; + } + + if (numfields && ptr < end) { + notice->z_multinotice = ptr; + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_multinotice = ""; + + if (numfields && ptr < end) { + if (ZReadAscii(ptr, end-ptr, (unsigned char *)¬ice->z_multiuid, + sizeof(ZUnique_Id_t)) == ZERR_BADFIELD) + BAD_PACKET("parsing multiuid"); + notice->z_time.tv_sec = ntohl((u_long) notice->z_multiuid.tv.tv_sec); + notice->z_time.tv_usec = ntohl((u_long) notice->z_multiuid.tv.tv_usec); + numfields--; + ptr = next_field(ptr, end); + } + else + notice->z_multiuid = notice->z_uid; + + if (numfields && ptr < end) { + /* we will take it on faith that ipv6 addresses are longer than ipv4 + addresses */ + unsigned char addrbuf[sizeof(notice->z_sender_sockaddr.ip6.sin6_addr)]; + int alen; + + /* because we're paranoid about naughtily misformatted packets */ + if (memchr(ptr, '\0', end - ptr) == NULL) + BAD_PACKET("unterminated address field"); + + if (*ptr == 'Z') { + if (ZReadZcode((unsigned char *)ptr, addrbuf, + sizeof(addrbuf), &alen) == ZERR_BADFIELD) + BAD_PACKET("parsing Zcode address"); + } else { + alen = sizeof(notice->z_sender_sockaddr.ip4.sin_addr); + if (ZReadAscii(ptr, end - ptr, (unsigned char *)addrbuf, + alen) == ZERR_BADFIELD) + BAD_PACKET("parsing NetASCII address"); + } + + if (alen == sizeof(notice->z_sender_sockaddr.ip6.sin6_addr)) { + notice->z_sender_sockaddr.ip6.sin6_family = AF_INET6; + memcpy(¬ice->z_sender_sockaddr.ip6.sin6_addr, addrbuf, alen); +#ifdef HAVE_SOCKADDR_IN6_SIN6_LEN + notice->z_sender_sockaddr.ip6.sin6_len = sizeof(notice->z_sender_sockaddr.ip6); +#endif + } else if (alen == sizeof(notice->z_sender_sockaddr.ip4.sin_addr)) { + notice->z_sender_sockaddr.ip4.sin_family = AF_INET; + memcpy(¬ice->z_sender_sockaddr.ip4.sin_addr, addrbuf, alen); +#ifdef HAVE_SOCKADDR_IN_SIN_LEN + notice->z_sender_sockaddr.ip4.sin_len = sizeof(notice->z_sender_sockaddr.ip4); +#endif + } else + BAD_PACKET("address claims to be neither IPv4 or IPv6"); + + numfields--; + ptr = next_field(ptr, end); + } else { + memset(¬ice->z_sender_sockaddr, 0, + sizeof notice->z_sender_sockaddr); + notice->z_sender_sockaddr.ip4.sin_family = AF_INET; + notice->z_sender_sockaddr.ip4.sin_addr = notice->z_uid.zuid_addr; +#ifdef HAVE_SOCKADDR_IN_SIN_LEN + notice->z_sender_sockaddr.ip4.sin_len = sizeof(notice->z_sender_sockaddr.ip4); +#endif + } + + if (numfields && ptr < end) { + if (ZReadAscii16(ptr, end-ptr, ¬ice->z_charset) == ZERR_BADFIELD) + BAD_PACKET("parsing charset"); + notice->z_charset = htons(notice->z_charset); + + numfields--; + ptr = next_field(ptr, end); + } else + notice->z_charset = ZCHARSET_UNKNOWN; + + for (i=0;ptr < end && iz_other_fields[i] = ptr; + ptr = next_field(ptr, end); + } + notice->z_num_other_fields = i; + + for (i=0;ptr < end && numfields;numfields--) + ptr = next_field(ptr, end); + + if (numfields || *(ptr - 1) != '\0') + BAD_PACKET("end of headers"); + + notice->z_message = (void *)ptr; + notice->z_message_len = len-(ptr-buffer); + + return (ZERR_NONE); +} diff --git a/lib/ZPeekIfNot.c b/lib/ZPeekIfNot.c new file mode 100644 index 0000000..3bc3e90 --- /dev/null +++ b/lib/ZPeekIfNot.c @@ -0,0 +1,57 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZPeekIfNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZPeekIfNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZPeekIfNotice(ZNotice_t *notice, + struct sockaddr_in *from, + int (*predicate)(ZNotice_t *, char *), + char *args) +{ + ZNotice_t tmpnotice; + Code_t retval; + char *buffer; + struct _Z_InputQ *qptr; + + if ((retval = Z_WaitForComplete()) != ZERR_NONE) + return (retval); + + for (;;) { + qptr = Z_GetFirstComplete(); + while (qptr) { + if ((retval = ZParseNotice(qptr->packet, qptr->packet_len, + &tmpnotice)) != ZERR_NONE) + return (retval); + if ((*predicate)(&tmpnotice, args)) { + if (!(buffer = (char *) malloc((unsigned) qptr->packet_len))) + return (ENOMEM); + (void) memcpy(buffer, qptr->packet, qptr->packet_len); + if (from) + *from = qptr->from; + if ((retval = ZParseNotice(buffer, qptr->packet_len, + notice)) != ZERR_NONE) { + free(buffer); + return (retval); + } + return (ZERR_NONE); + } + qptr = Z_GetNextComplete(qptr); + } + if ((retval = Z_ReadWait()) != ZERR_NONE) + return (retval); + } +} diff --git a/lib/ZPeekNot.c b/lib/ZPeekNot.c new file mode 100644 index 0000000..18c2026 --- /dev/null +++ b/lib/ZPeekNot.c @@ -0,0 +1,31 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for ZPeekNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZPeekNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZPeekNotice(ZNotice_t *notice, + struct sockaddr_in *from) +{ + char *buffer; + int len; + Code_t retval; + + if ((retval = ZPeekPacket(&buffer, &len, from)) != ZERR_NONE) + return (retval); + + return (ZParseNotice(buffer, len, notice)); +} diff --git a/lib/ZPeekPkt.c b/lib/ZPeekPkt.c new file mode 100644 index 0000000..53c5dd7 --- /dev/null +++ b/lib/ZPeekPkt.c @@ -0,0 +1,43 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for ZPeekPacket function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZPeekPacket_c[] = "$Id$"; +#endif + +#include + +Code_t +ZPeekPacket(char **buffer, + int *ret_len, + struct sockaddr_in *from) +{ + Code_t retval; + struct _Z_InputQ *nextq; + + if ((retval = Z_WaitForComplete()) != ZERR_NONE) + return (retval); + + nextq =Z_GetFirstComplete(); + + *ret_len = nextq->packet_len; + + if (!(*buffer = (char *) malloc((unsigned) *ret_len))) + return (ENOMEM); + + (void) memcpy(*buffer, nextq->packet, *ret_len); + + if (from) + *from = nextq->from; + + return (ZERR_NONE); +} diff --git a/lib/ZPending.c b/lib/ZPending.c new file mode 100644 index 0000000..6053c69 --- /dev/null +++ b/lib/ZPending.c @@ -0,0 +1,35 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZPending function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZPending_c[] = "$Id$"; +#endif + +#include + +int +ZPending(void) +{ + int retval; + + if (ZGetFD() < 0) { + errno = ZERR_NOPORT; + return (-1); + } + + if ((retval = Z_ReadEnqueue()) != ZERR_NONE) { + errno = retval; + return (-1); + } + + return(ZQLength()); +} diff --git a/lib/ZReadAscii.c b/lib/ZReadAscii.c new file mode 100644 index 0000000..69c1ecd --- /dev/null +++ b/lib/ZReadAscii.c @@ -0,0 +1,88 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZReadAscii function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987, 1990 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZReadAscii_c[] = "$Id$"; +#endif /* lint */ + +#include +#include + +#define Z_cnvt_xtoi(c) ((temp=(c)-'0'),(temp<10)?temp:((temp-='A'-'9'-1),(temp<16)?temp:-1)) + +Code_t +ZReadAscii(char *ptr, + int len, + unsigned char *field, + int num) +{ + int i; + unsigned int hexbyte; + register int c1, c2; + register int temp; + + for (i=0;i= 1 && *ptr == ' ') { + ptr++; + len--; + } + if (len >= 2 && ptr[0] == '0' && ptr[1] == 'x') { + ptr += 2; + len -= 2; + } + if (len < 2) + return ZERR_BADFIELD; + c1 = Z_cnvt_xtoi(ptr[0]); + if (c1 < 0) + return ZERR_BADFIELD; + c2 = Z_cnvt_xtoi(ptr[1]); + if (c2 < 0) + return ZERR_BADFIELD; + hexbyte = (c1 << 4) | c2; + field[i] = hexbyte; + ptr += 2; + len -= 2; + } + + return *ptr ? ZERR_BADFIELD : ZERR_NONE; +} + +Code_t +ZReadAscii32(char *ptr, + int len, + unsigned long *value_ptr) +{ + unsigned char buf[4]; + Code_t retval; + + retval = ZReadAscii(ptr, len, buf, 4); + if (retval != ZERR_NONE) + return retval; + *value_ptr = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3]; + return ZERR_NONE; +} + +Code_t +ZReadAscii16(char *ptr, + int len, + unsigned short *value_ptr) +{ + unsigned char buf[2]; + Code_t retval; + + retval = ZReadAscii(ptr, len, buf, 2); + if (retval != ZERR_NONE) + return retval; + *value_ptr = (buf[0] << 8) | buf[1]; + return ZERR_NONE; +} + diff --git a/lib/ZReadZcode.c b/lib/ZReadZcode.c new file mode 100644 index 0000000..dc97990 --- /dev/null +++ b/lib/ZReadZcode.c @@ -0,0 +1,48 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZReadZcode function. + * + * Created by: Jeffrey Hutzelman + * + * $Id$ + * + * Copyright (c) 1987, 1990, 2002 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZReadZcode_c[] = "$Id$"; +#endif /* lint */ + +#include +#include + + +Code_t +ZReadZcode(unsigned char *ptr, + unsigned char *field, + int max, + int *len) +{ + int n = 0; + + if (*ptr++ != 'Z') + return ZERR_BADFIELD; + + while (*ptr && n < max) { + if (*ptr == 0xff) { + ptr++; + switch (*ptr++) { + case 0xf0: field[n++] = 0x00; continue; + case 0xf1: field[n++] = 0xff; continue; + default: return ZERR_BADFIELD; + } + } else { + field[n++] = *ptr++; + } + } + if (*ptr) + return (ZERR_BADFIELD); + *len = n; + return (ZERR_NONE); +} diff --git a/lib/ZRecvNot.c b/lib/ZRecvNot.c new file mode 100644 index 0000000..e3b14a4 --- /dev/null +++ b/lib/ZRecvNot.c @@ -0,0 +1,52 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for ZReceiveNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZReceiveNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZReceiveNotice(ZNotice_t *notice, + struct sockaddr_in *from) +{ + char *buffer; + struct _Z_InputQ *nextq; + int len, auth; + Code_t retval; + + if ((retval = Z_WaitForComplete()) != ZERR_NONE) + return (retval); + + nextq = Z_GetFirstComplete(); + if (!nextq) + return (ENOMEM); + + len = nextq->packet_len; + + if (!(buffer = (char *) malloc((unsigned) len))) + return (ENOMEM); + + if (from) + *from = nextq->from; + + (void) memcpy(buffer, nextq->packet, len); + + auth = nextq->auth; + Z_RemQueue(nextq); + + if ((retval = ZParseNotice(buffer, len, notice)) != ZERR_NONE) + return (retval); + notice->z_checked_auth = auth; + return ZERR_NONE; +} diff --git a/lib/ZRecvPkt.c b/lib/ZRecvPkt.c new file mode 100644 index 0000000..3f36ddc --- /dev/null +++ b/lib/ZRecvPkt.c @@ -0,0 +1,44 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for ZReceivePacket function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZReceivePacket_c[] = "$Id$"; +#endif + +#include + +Code_t +ZReceivePacket(ZPacket_t buffer, + int *ret_len, + struct sockaddr_in *from) +{ + Code_t retval; + struct _Z_InputQ *nextq; + + if ((retval = Z_WaitForComplete()) != ZERR_NONE) + return (retval); + + nextq = Z_GetFirstComplete(); + + *ret_len = nextq->packet_len; + if (*ret_len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + (void) memcpy(buffer, nextq->packet, *ret_len); + + if (from) + *from = nextq->from; + + Z_RemQueue(nextq); + + return (ZERR_NONE); +} diff --git a/lib/ZRetSubs.c b/lib/ZRetSubs.c new file mode 100644 index 0000000..9926171 --- /dev/null +++ b/lib/ZRetSubs.c @@ -0,0 +1,185 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZRetrieveSubscriptions and + * ZRetrieveDefaultSubscriptions functions. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZRetrieveSubscriptions_c[] = + "$Id$"; +#endif + +static Code_t Z_RetSubs (register ZNotice_t *, int *, Z_AuthProc); + +/* Need STDC definition when possible for unsigned short argument. */ +Code_t +ZRetrieveSubscriptions(unsigned short port, + int *nsubs) +{ + int retval; + ZNotice_t notice; + char asciiport[50]; + + if (!port) /* use default port */ + port = __Zephyr_port; + + retval = ZMakeAscii16(asciiport, sizeof(asciiport), ntohs(port)); + if (retval != ZERR_NONE) + return (retval); + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_message = asciiport; + notice.z_message_len = strlen(asciiport)+1; + notice.z_opcode = CLIENT_GIMMESUBS; + + return(Z_RetSubs(¬ice, nsubs, ZAUTH)); +} + +Code_t +ZRetrieveDefaultSubscriptions(int *nsubs) +{ + ZNotice_t notice; + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_message = (char *) 0; + notice.z_message_len = 0; + notice.z_opcode = CLIENT_GIMMEDEFS; + + return(Z_RetSubs(¬ice, nsubs, ZNOAUTH)); + +} + +static Code_t +Z_RetSubs(register ZNotice_t *notice, + int *nsubs, + Z_AuthProc auth_routine) +{ + register int i; + int retval,nrecv,gimmeack; + ZNotice_t retnotice; + char *ptr,*end,*ptr2; + ZSubscription_t *list = __subscriptions_list; + + retval = ZFlushSubscriptions(); + + if (retval != ZERR_NONE && retval != ZERR_NOSUBSCRIPTIONS) + return (retval); + + if (ZGetFD() < 0) + if ((retval = ZOpenPort((u_short *)0)) != ZERR_NONE) + return (retval); + + notice->z_kind = ACKED; + notice->z_port = __Zephyr_port; + notice->z_class = ZEPHYR_CTL_CLASS; + notice->z_class_inst = ZEPHYR_CTL_CLIENT; + notice->z_sender = 0; + notice->z_recipient = ""; + notice->z_default_format = ""; + + if ((retval = ZSendNotice(notice,auth_routine)) != ZERR_NONE) + return (retval); + + nrecv = 0; + gimmeack = 0; + list = (ZSubscription_t *) 0; + + while (!nrecv || !gimmeack) { + retval = Z_WaitForNotice (&retnotice, ZCompareMultiUIDPred, + ¬ice->z_multiuid, SRV_TIMEOUT); + if (retval == ZERR_NONOTICE) + return ETIMEDOUT; + else if (retval != ZERR_NONE) + return retval; + + if (retnotice.z_kind == SERVNAK) { + ZFreeNotice(&retnotice); + return (ZERR_SERVNAK); + } + /* non-matching protocol version numbers means the + server is probably an older version--must punt */ + if (strcmp(notice->z_version,retnotice.z_version)) { + ZFreeNotice(&retnotice); + return(ZERR_VERS); + } + if (retnotice.z_kind == SERVACK && + !strcmp(retnotice.z_opcode,notice->z_opcode)) { + ZFreeNotice(&retnotice); + gimmeack = 1; + continue; + } + + if (retnotice.z_kind != ACKED) { + ZFreeNotice(&retnotice); + return (ZERR_INTERNAL); + } + + nrecv++; + + end = retnotice.z_message+retnotice.z_message_len; + + __subscriptions_num = 0; + for (ptr=retnotice.z_message;ptr + +Code_t ZSendList(ZNotice_t *notice, + char *list[], + int nitems, + Z_AuthProc cert_routine) +{ + return(ZSrvSendList(notice, list, nitems, cert_routine, Z_XmitFragment)); +} + +Code_t +ZSrvSendList(ZNotice_t *notice, + char *list[], + int nitems, + Z_AuthProc cert_routine, + Code_t (*send_routine)(ZNotice_t *, char *, int, int)) +{ + Code_t retval; + ZNotice_t newnotice; + char *buffer; + int len; + + if ((retval = ZFormatNoticeList(notice, list, nitems, &buffer, + &len, cert_routine)) != ZERR_NONE) + return (retval); + + if ((retval = ZParseNotice(buffer, len, &newnotice)) != ZERR_NONE) + return (retval); + + retval = Z_SendFragmentedNotice(&newnotice, len, cert_routine, + send_routine); + + free(buffer); + + return (retval); +} diff --git a/lib/ZSendNot.c b/lib/ZSendNot.c new file mode 100644 index 0000000..4fc246d --- /dev/null +++ b/lib/ZSendNot.c @@ -0,0 +1,53 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSendNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSendNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZSendNotice(ZNotice_t *notice, + Z_AuthProc cert_routine) +{ + return(ZSrvSendNotice(notice, cert_routine, Z_XmitFragment)); +} + +/* Despite its name, this is not used by the server */ +Code_t +ZSrvSendNotice(ZNotice_t *notice, + Z_AuthProc cert_routine, + Code_t (*send_routine)(ZNotice_t *, char *, int, int)) +{ + Code_t retval; + ZNotice_t newnotice; + char *buffer; + int len; + + if ((retval = ZFormatNotice(notice, &buffer, &len, + cert_routine)) != ZERR_NONE) + return (retval); + + if ((retval = ZParseNotice(buffer, len, &newnotice)) != ZERR_NONE) { + free(buffer); + return (retval); + } + + + retval = Z_SendFragmentedNotice(&newnotice, len, cert_routine, + send_routine); + + free(buffer); + + return (retval); +} diff --git a/lib/ZSendPkt.c b/lib/ZSendPkt.c new file mode 100644 index 0000000..143eacd --- /dev/null +++ b/lib/ZSendPkt.c @@ -0,0 +1,68 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSendPacket function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSendPacket_c[] = + "$Id$"; +#endif + +#include +#include + +static int wait_for_hmack(ZNotice_t *, void *); + +Code_t +ZSendPacket(char *packet, + int len, + int waitforack) +{ + Code_t retval; + struct sockaddr_in dest; + ZNotice_t notice, acknotice; + + if (!packet || len < 0) + return (ZERR_ILLVAL); + + if (len > Z_MAXPKTLEN) + return (ZERR_PKTLEN); + + if (ZGetFD() < 0) + if ((retval = ZOpenPort((u_short *)0)) != ZERR_NONE) + return (retval); + + dest = ZGetDestAddr(); + + if (sendto(ZGetFD(), packet, len, 0, (struct sockaddr *)&dest, + sizeof(dest)) < 0) + return (errno); + + if (!waitforack) + return (ZERR_NONE); + + if ((retval = ZParseNotice(packet, len, ¬ice)) != ZERR_NONE) + return (retval); + + retval = Z_WaitForNotice(&acknotice, wait_for_hmack, ¬ice.z_uid, + HM_TIMEOUT); + if (retval == ETIMEDOUT) + return ZERR_HMDEAD; + if (retval == ZERR_NONE) + ZFreeNotice (&acknotice); + return retval; +} + +static int +wait_for_hmack(ZNotice_t *notice, + void *uid) +{ + return (notice->z_kind == HMACK && ZCompareUID(¬ice->z_uid, (ZUnique_Id_t *)uid)); +} diff --git a/lib/ZSendRLst.c b/lib/ZSendRLst.c new file mode 100644 index 0000000..3cb4c63 --- /dev/null +++ b/lib/ZSendRLst.c @@ -0,0 +1,48 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSendRawNotice function. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSendRawList_c[] = "$Id$"; +#endif + +#include + +Code_t ZSendRawList(ZNotice_t *notice, + char *list[], + int nitems) +{ + return(ZSrvSendRawList(notice, list, nitems, Z_XmitFragment)); +} + +Code_t ZSrvSendRawList(ZNotice_t *notice, + char *list[], + int nitems, + Code_t (*send_routine)(ZNotice_t *, char *, int, int)) +{ + Code_t retval; + ZNotice_t newnotice; + char *buffer; + int len; + + if ((retval = ZFormatRawNoticeList(notice, list, nitems, &buffer, + &len)) != ZERR_NONE) + return (retval); + + if ((retval = ZParseNotice(buffer, len, &newnotice)) != ZERR_NONE) + return (retval); + + retval = Z_SendFragmentedNotice(&newnotice, len, NULL, send_routine); + + free(buffer); + + return (retval); +} diff --git a/lib/ZSendRaw.c b/lib/ZSendRaw.c new file mode 100644 index 0000000..b4eadc3 --- /dev/null +++ b/lib/ZSendRaw.c @@ -0,0 +1,39 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSendRawNotice function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSendRawNotice_c[] = "$Id$"; +#endif + +#include + +Code_t +ZSendRawNotice(ZNotice_t *notice) +{ + Code_t retval; + ZNotice_t newnotice; + char *buffer; + int len; + + if ((retval = ZFormatRawNotice(notice, &buffer, &len)) != + ZERR_NONE) + return (retval); + + if ((retval = ZParseNotice(buffer, len, &newnotice)) != ZERR_NONE) + return (retval); + + retval = Z_SendFragmentedNotice(&newnotice, len, NULL, Z_XmitFragment); + + free(buffer); + + return (retval); +} diff --git a/lib/ZSetDest.c b/lib/ZSetDest.c new file mode 100644 index 0000000..4869fbf --- /dev/null +++ b/lib/ZSetDest.c @@ -0,0 +1,27 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSetDestAddr function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSetDestAddr_c[] = "$Id$"; +#endif + +#include + +Code_t +ZSetDestAddr(struct sockaddr_in *addr) +{ + __HM_addr = *addr; + + __HM_set = 1; + + return (ZERR_NONE); +} diff --git a/lib/ZSetFD.c b/lib/ZSetFD.c new file mode 100644 index 0000000..b0f3df7 --- /dev/null +++ b/lib/ZSetFD.c @@ -0,0 +1,28 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSetFD function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSetFD_c[] = "$Id$"; +#endif + +#include + +Code_t +ZSetFD(int fd) +{ + (void) ZClosePort(); + + __Zephyr_fd = fd; + __Zephyr_open = 0; + + return (ZERR_NONE); +} diff --git a/lib/ZSetSrv.c b/lib/ZSetSrv.c new file mode 100644 index 0000000..a3c67c0 --- /dev/null +++ b/lib/ZSetSrv.c @@ -0,0 +1,25 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSetServerState function. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZSetServerState_c[] = "$Id$"; +#endif + +#include + +Code_t +ZSetServerState(int state) +{ + __Zephyr_server = state; + + return (ZERR_NONE); +} diff --git a/lib/ZSubs.c b/lib/ZSubs.c new file mode 100644 index 0000000..535f3f9 --- /dev/null +++ b/lib/ZSubs.c @@ -0,0 +1,258 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZSubscribeTo, ZUnsubscribeTo, and + * ZCancelSubscriptions functions. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef lint +static const char rcsid_ZSubscriptions_c[] = "$Id$"; +#endif + +static Code_t Z_SendAndWaitForServer(ZNotice_t *notice, char *buf, int len, + int waitforack); + +#ifdef CMU_ZCTL_PUNT +Code_t +ZPunt(ZSubscription_t *sublist, + int nitems, + unsigned int port) +{ + return (ZSubscriptions(sublist, nitems, port, "SUPPRESS", + Z_SendAndWaitForServer)); +} +#endif + +Code_t +ZSubscribeTo(ZSubscription_t *sublist, + int nitems, + unsigned int port) +{ + return (ZSubscriptions(sublist, nitems, port, CLIENT_SUBSCRIBE, + Z_SendAndWaitForServer)); +} + +Code_t +ZSubscribeToSansDefaults(ZSubscription_t *sublist, + int nitems, + unsigned int port) +{ + return (ZSubscriptions(sublist, nitems, port, CLIENT_SUBSCRIBE_NODEFS, + Z_SendAndWaitForServer)); +} + +Code_t +ZUnsubscribeTo(ZSubscription_t *sublist, + int nitems, + unsigned int port) +{ + return (ZSubscriptions(sublist, nitems, port, CLIENT_UNSUBSCRIBE, + Z_SendAndWaitForServer)); +} + +Code_t +ZCancelSubscriptions(unsigned int port) +{ + return (ZSubscriptions((ZSubscription_t *)0, 0, port, CLIENT_CANCELSUB, + Z_SendAndWaitForServer)); +} + +/* + * This routine must do its own fragmentation. Subscriptions must + * not be broken across packet boundaries, or else the server will + * mis-interpret them. + */ + +Code_t +ZSubscriptions(register ZSubscription_t *sublist, + int nitems, + unsigned int port, + char *opcode, + Code_t (*send_routine)(ZNotice_t *, char *, int, int)) +{ + register int i, j; + int retval; + ZNotice_t notice; + char header[Z_MAXHEADERLEN]; + char **list; + char *recip; + int hdrlen; + /* Space available for data, adjusted below. Take off Z_FRAGFUDGE twice. + The first is to account for Z_SendFragmentedNotice's space. The second + to account for hdrlen not being constant. Zcode escapes bytes 0x00 and + 0xFF, so some bytes are encoded as two bytes. */ + int size_avail = Z_MAXPKTLEN-Z_FRAGFUDGE-Z_FRAGFUDGE; + int size, start, numok; + Z_AuthProc cert_routine; + + /* nitems = 0 means cancel all subscriptions; still need to allocate a */ + /* array for one item so we can cancel, however. */ + + list = (char **)malloc((unsigned)((nitems==0)?1:nitems)*3*sizeof(char *)); + if (!list) + return (ENOMEM); + + (void) memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = ACKED; + notice.z_port = port; + notice.z_class = ZEPHYR_CTL_CLASS; + notice.z_class_inst = ZEPHYR_CTL_CLIENT; + notice.z_opcode = opcode; + notice.z_sender = 0; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_message_len = 0; + + /* format the header to figure out how long it is */ + retval = Z_FormatHeader(¬ice, header, sizeof(header), &hdrlen, ZAUTH); + if (retval != ZERR_NONE) { + free((char *)list); + return(retval); + } + + /* if a subscription request, we save the key */ + if (strcmp(opcode, CLIENT_SUBSCRIBE) == 0 || + strcmp(opcode, CLIENT_SUBSCRIBE_NODEFS) == 0) { + cert_routine = ZSUBAUTH; + } else { + cert_routine = ZAUTH; + } + + /* compute amount of room left */ + size_avail -= hdrlen; + size = size_avail; + + /* assemble subs into an array of pointers */ + for (i=0;iz_multiuid, ¬ice->z_uid)) + return (retval); + if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *)0, + ZCompareUIDPred, (char *)¬ice->z_uid)) != + ZERR_NONE) + return (retval); + if (retnotice.z_kind == SERVNAK) { + ZFreeNotice(&retnotice); + return (ZERR_SERVNAK); + } + if (retnotice.z_kind != SERVACK) { + ZFreeNotice(&retnotice); + return (ZERR_INTERNAL); + } + ZFreeNotice(&retnotice); + return (ZERR_NONE); +} + +Code_t +ZFlushUserSubscriptions(char *recip) +{ + register Code_t retval; + ZNotice_t notice, retnotice; + + (void)memset((char *)¬ice, 0, sizeof(notice)); + notice.z_kind = ACKED; + notice.z_class = ZEPHYR_CTL_CLASS; + notice.z_class_inst = ZEPHYR_CTL_CLIENT; + notice.z_opcode = CLIENT_FLUSHSUBS; + notice.z_recipient = ""; + notice.z_default_format = ""; + if (recip) { + notice.z_message = recip; + notice.z_message_len = strlen(recip) + 1; + } else { + notice.z_message_len = 0; + } + + if ((retval = ZSendNotice(¬ice, ZAUTH)) != ZERR_NONE) + return (retval); + + if ((retval = ZIfNotice(&retnotice, (struct sockaddr_in *)0, + ZCompareUIDPred, (char *)¬ice.z_uid)) != + ZERR_NONE) + return (retval); + if (retnotice.z_kind == SERVNAK) { + ZFreeNotice(&retnotice); + return (ZERR_SERVNAK); + } + if (retnotice.z_kind != SERVACK) { + ZFreeNotice(&retnotice); + return (ZERR_INTERNAL); + } + ZFreeNotice(&retnotice); + return (ZERR_NONE); +} diff --git a/lib/ZVariables.c b/lib/ZVariables.c new file mode 100644 index 0000000..fb8c9e5 --- /dev/null +++ b/lib/ZVariables.c @@ -0,0 +1,195 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZGetVariable, ZSetVariable, and ZUnsetVariable + * functions. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_ZVariables_c[] = "$Id$"; +#endif + +#include + +#include +#include + +Code_t get_localvarfile(char *bfr); +static char *get_varval(char *fn, char *val); +static int varline(char *bfr, char *var); + +char * +ZGetVariable(char *var) +{ + char varfile[128], *ret; + Code_t code; + + code = get_localvarfile(varfile); + if (code) + return ((char *)0); + + if ((ret = get_varval(varfile, var)) != ZERR_NONE) + return (ret); + + sprintf(varfile, "%s/zephyr/zephyr.vars", SYSCONFDIR); + return (get_varval(varfile, var)); +} + +Code_t +ZSetVariable(char *var, char *value) +{ + int written; + FILE *fpin, *fpout; + char varfile[128], varfilebackup[128], varbfr[512]; + Code_t code; + + written = 0; + + code = get_localvarfile(varfile); + if (code) + return code; + + (void) strcpy(varfilebackup, varfile); + (void) strcat(varfilebackup, ".backup"); + + if (!(fpout = fopen(varfilebackup, "w"))) + return (errno); + if ((fpin = fopen(varfile, "r")) != NULL) { + while (fgets(varbfr, sizeof varbfr, fpin) != (char *) 0) { + if (varbfr[strlen(varbfr)-1] < ' ') + varbfr[strlen(varbfr)-1] = '\0'; + if (varline(varbfr, var)) { + fprintf(fpout, "%s = %s\n", var, value); + written = 1; + } + else + fprintf(fpout, "%s\n", varbfr); + } + (void) fclose(fpin); /* don't care about errs on input */ + } + if (!written) + fprintf(fpout, "%s = %s\n", var, value); + if (fclose(fpout) == EOF) + return(EIO); /* can't rely on errno */ + if (rename(varfilebackup, varfile)) + return (errno); + return (ZERR_NONE); +} + +Code_t +ZUnsetVariable(char *var) +{ + FILE *fpin, *fpout; + char varfile[128], varfilebackup[128], varbfr[512]; + Code_t code; + + code = get_localvarfile(varfile); + if (code) + return code; + + (void) strcpy(varfilebackup, varfile); + (void) strcat(varfilebackup, ".backup"); + + if (!(fpout = fopen(varfilebackup, "w"))) + return (errno); + if ((fpin = fopen(varfile, "r")) != NULL) { + while (fgets(varbfr, sizeof varbfr, fpin) != (char *) 0) { + if (varbfr[strlen(varbfr)-1] < ' ') + varbfr[strlen(varbfr)-1] = '\0'; + if (!varline(varbfr, var)) + fprintf(fpout, "%s\n", varbfr); + } + (void) fclose(fpin); /* don't care about read close errs */ + } + if (fclose(fpout) == EOF) + return(EIO); /* errno isn't reliable */ + if (rename(varfilebackup, varfile)) + return (errno); + return (ZERR_NONE); +} + +Code_t +get_localvarfile(char *bfr) +{ + char *envptr; + struct passwd *pwd; + + envptr = getenv("ZEPHYR_VARS"); + if (envptr) + (void) strcpy(bfr, envptr); + else { + envptr = getenv("HOME"); + if (envptr) + (void) strcpy(bfr, envptr); + else { + if (!(pwd = getpwuid((int) getuid()))) + return errno; + (void) strcpy(bfr, pwd->pw_dir); + } + + (void) strcat(bfr, "/"); + (void) strcat(bfr, ".zephyr.vars"); + } + return (0); +} + +static char * +get_varval(char *fn, char *var) +{ + FILE *fp; + static char varbfr[512]; + int i; + + fp = fopen(fn, "r"); + if (!fp) + return ((char *)0); + + while (fgets(varbfr, sizeof varbfr, fp) != (char *) 0) { + if (varbfr[strlen(varbfr)-1] < ' ') + varbfr[strlen(varbfr)-1] = '\0'; + if (!(i = varline(varbfr, var))) + continue; + (void) fclose(fp); /* open read-only, don't care */ + return (varbfr+i); + } + (void) fclose(fp); /* open read-only, don't care */ + return ((char *)0); +} + +/* If the variable in the line bfr[] is the same as var, return index to + the variable value, else return 0. */ +static int +varline(char *bfr, char *var) +{ + register char *cp; + size_t namelen; + + if (!bfr[0] || bfr[0] == '#') /* comment or null line */ + return (0); + + cp = bfr; + while (*cp && !isspace(*cp) && (*cp != '=')) + cp++; + +#define max(a,b) ((a > b) ? (a) : (b)) + + namelen = cp - bfr; + if (strncasecmp(bfr, var, max(strlen(var), namelen))) + return(0); /* var is not the var in + bfr ==> no match */ + + cp = strchr(bfr, '='); + if (!cp) + return(0); + cp++; + while (*cp && isspace(*cp)) /* space up to variable value */ + cp++; + + return (cp - bfr); /* return index */ +} diff --git a/lib/ZWait4Not.c b/lib/ZWait4Not.c new file mode 100644 index 0000000..d6c5409 --- /dev/null +++ b/lib/ZWait4Not.c @@ -0,0 +1,70 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the ZCheckIfNotice/select loop used for waiting for + * a notice, with a timeout. + * + * Created by: + * + * $Id$ + * + * Copyright (c) 1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include "mit-copyright.h" + +#ifndef lint +static const char rcsid_ZWaitForNotice_c[] = "$Id$"; +#endif + +#include +#include + +Code_t +Z_WaitForNotice(ZNotice_t *notice, + int (*pred) __P((ZNotice_t *, void *)), + void *arg, + int timeout) +{ + Code_t retval; + struct timeval tv, t0; + fd_set fdmask; + int i, fd; + + retval = ZCheckIfNotice (notice, (struct sockaddr_in *) 0, pred, + (char *) arg); + if (retval == ZERR_NONE) + return ZERR_NONE; + if (retval != ZERR_NONOTICE) + return retval; + + fd = ZGetFD (); + FD_ZERO (&fdmask); + tv.tv_sec = timeout; + tv.tv_usec = 0; + gettimeofday (&t0, (struct timezone *) 0); + t0.tv_sec += timeout; + while (1) { + FD_SET (fd, &fdmask); + i = select (fd + 1, &fdmask, (fd_set *) 0, (fd_set *) 0, &tv); + if (i == 0) + return ETIMEDOUT; + if (i < 0 && errno != EINTR) + return errno; + if (i > 0) { + retval = ZCheckIfNotice (notice, (struct sockaddr_in *) 0, pred, + (char *) arg); + if (retval != ZERR_NONOTICE) /* includes ZERR_NONE */ + return retval; + } + gettimeofday (&tv, (struct timezone *) 0); + tv.tv_usec = t0.tv_usec - tv.tv_usec; + if (tv.tv_usec < 0) { + tv.tv_usec += 1000000; + tv.tv_sec = t0.tv_sec - tv.tv_sec - 1; + } + else + tv.tv_sec = t0.tv_sec - tv.tv_sec; + } + /*NOTREACHED*/ +} diff --git a/lib/ZhmStat.c b/lib/ZhmStat.c new file mode 100644 index 0000000..f6e764c --- /dev/null +++ b/lib/ZhmStat.c @@ -0,0 +1,72 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the ZhmStat() function. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1996 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include + +#ifndef INADDR_LOOPBACK +#define INADDR_LOOPBACK 0x7f000001 +#endif + +Code_t +ZhmStat(struct in_addr *hostaddr, + ZNotice_t *notice) +{ + struct servent *sp; + struct sockaddr_in sin; + ZNotice_t req; + Code_t code; + struct timeval tv; + fd_set readers; + + (void) memset((char *)&sin, 0, sizeof(struct sockaddr_in)); + + sp = getservbyname(HM_SVCNAME, "udp"); + + sin.sin_port = (sp) ? sp->s_port : HM_SVC_FALLBACK; + sin.sin_family = AF_INET; + + if (hostaddr) + sin.sin_addr = *hostaddr; + else + sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + (void) memset((char *)&req, 0, sizeof(req)); + req.z_kind = STAT; + req.z_port = 0; + req.z_class = HM_STAT_CLASS; + req.z_class_inst = HM_STAT_CLIENT; + req.z_opcode = HM_GIMMESTATS; + req.z_sender = ""; + req.z_recipient = ""; + req.z_default_format = ""; + req.z_message_len = 0; + + if ((code = ZSetDestAddr(&sin)) != ZERR_NONE) + return(code); + + if ((code = ZSendNotice(&req, ZNOAUTH)) != ZERR_NONE) + return(code); + + /* Wait up to ten seconds for a response. */ + FD_ZERO(&readers); + FD_SET(ZGetFD(), &readers); + tv.tv_sec = 10; + tv.tv_usec = 0; + code = select(ZGetFD() + 1, &readers, NULL, NULL, &tv); + if (code < 0 && errno != EINTR) + return(errno); + if (code == 0 || (code < 0 && errno == EINTR) || ZPending() == 0) + return(ZERR_HMDEAD); + + return(ZReceiveNotice(notice, (struct sockaddr_in *) 0)); +} diff --git a/lib/Zinternal.c b/lib/Zinternal.c new file mode 100644 index 0000000..ecee122 --- /dev/null +++ b/lib/Zinternal.c @@ -0,0 +1,1422 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the internal Zephyr routines. + * + * Created by: Robert French + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of + * Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include + +#ifndef lint +static const char rcsid_Zinternal_c[] = + "$Id$"; +static const char copyright[] = + "Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology."; +#endif + +int __Zephyr_fd = -1; +int __Zephyr_open; +int __Zephyr_port = -1; +struct in_addr __My_addr; +int __Q_CompleteLength; +int __Q_Size; +struct _Z_InputQ *__Q_Head, *__Q_Tail; +struct sockaddr_in __HM_addr; +struct sockaddr_in __HM_addr_real; +int __HM_set; +int __Zephyr_server; +ZLocations_t *__locate_list; +int __locate_num; +int __locate_next; +ZSubscription_t *__subscriptions_list; +int __subscriptions_num; +int __subscriptions_next; +int Z_discarded_packets = 0; + +#ifdef HAVE_KRB5 +/* This context is used throughout */ +krb5_context Z_krb5_ctx; +/* A queue of all the currently active session keys. */ +struct _Z_SessionKey *Z_keys_head, *Z_keys_tail; + +static const struct cksum_map_s { + krb5_enctype e; + krb5_cksumtype c; +} cksum_map[] = { + /* per RFC1510 and draft-ietf-krb-wg-crypto-02.txt */ + { ENCTYPE_NULL, CKSUMTYPE_RSA_MD5 }, + { ENCTYPE_DES_CBC_CRC, CKSUMTYPE_RSA_MD5_DES }, + { ENCTYPE_DES_CBC_MD4, CKSUMTYPE_RSA_MD4_DES }, + { ENCTYPE_DES_CBC_MD5, CKSUMTYPE_RSA_MD5_DES }, + + /* + * The implementors hate us, and are inconsistent with names for + * most things defined after RFC1510. Note that des3-cbc-sha1 + * and des3-cbc-sha1-kd are listed by number to avoid confusion + * caused by inconsistency between the names used in the specs + * and those used by implementations. + * -- jhutz, 30-Nov-2002 + */ + + /* source lost in history (an expired internet-draft) */ + { 5 /* des3-cbc-md5 */, 9 /* rsa-md5-des3 */ }, + { 7 /* des3-cbc-sha1 */, 13 /* hmac-sha1-des3 */ }, + + /* per draft-ietf-krb-wg-crypto-02.txt */ + { 16 /* des3-cbc-sha1-kd */, 12 /* hmac-sha1-des3-kd */ }, + + /* per draft-raeburn-krb-rijndael-krb-02.txt */ + { 17 /* aes128-cts-hmac-sha1-96 */, 15 /* hmac-sha1-96-aes128 */ }, + { 18 /* aes256-cts-hmac-sha1-96 */, 16 /* hmac-sha1-96-aes256 */ }, + + /* per draft-brezak-win2k-krb-rc4-hmac-04.txt */ + { 23 /* rc4-hmac */, -138 /* hmac-md5 */ }, + { 24 /* rc4-hmac-exp */, -138 /* hmac-md5 */ }, + { 25 /* camellia128-cts-cmac */, 17 /* cmac-camellia128 */ }, + { 26 /* camellia256-cts-cmac */, 18 /* cmac-camellia256 */ }, +}; +#define N_CKSUM_MAP (sizeof(cksum_map) / sizeof(struct cksum_map_s)) + +Code_t +Z_krb5_lookup_cksumtype(krb5_enctype e, + krb5_cksumtype *c) +{ + unsigned int i; + + for (i = 0; i < N_CKSUM_MAP; i++) { + if (cksum_map[i].e == e) { + *c = cksum_map[i].c; + return ZERR_NONE; + } + } + return KRB5_PROG_ETYPE_NOSUPP; +} +#endif /* HAVE_KRB5 */ + +char __Zephyr_realm[REALM_SZ]; + +#ifdef Z_DEBUG +void (*__Z_debug_print)(const char *fmt, va_list args, void *closure); +void *__Z_debug_print_closure; +#endif + +#define min(a,b) ((a)<(b)?(a):(b)) + +static int Z_AddField(char **ptr, char *field, char *end); +static int find_or_insert_uid(ZUnique_Id_t *uid, ZNotice_Kind_t kind); +static Code_t Z_ZcodeFormatRawHeader(ZNotice_t *, char *, int, int *, char **, + int *, char **, char **, int cksumstyle, + int addrstyle); + +/* Find or insert uid in the old uids buffer. The buffer is a sorted + * circular queue. We make the assumption that most packets arrive in + * order, so we can usually search for a uid or just tack it onto the end. + * The first entry at at buffer[start], the last is at + * buffer[(start + num - 1) % size] */ +static int +find_or_insert_uid(ZUnique_Id_t *uid, + ZNotice_Kind_t kind) +{ + static struct _filter { + ZUnique_Id_t uid; + ZNotice_Kind_t kind; + time_t t; + } *buffer; + static long size; + static long start; + static long num; + + time_t now; + struct _filter *new; + long i, j, new_size; + int result, found = 0; + + /* Initialize the uid buffer if it hasn't been done already. */ + if (!buffer) { + size = Z_INITFILTERSIZE; + buffer = (struct _filter *) malloc(size * sizeof(*buffer)); + if (!buffer) + return 0; + } + + /* Age the uid buffer, discarding any uids older than the time limit. */ + time(&now); + while (num && (now - buffer[start % size].t) > Z_FILTERTIMELIMIT) + start++, num--; + start %= size; + + /* Make room for a new uid, since we'll probably have to insert one. */ + if (num == size) { + new_size = size * 2 + 2; + new = (struct _filter *) malloc(new_size * sizeof(*new)); + if (!new) + return 0; + for (i = 0; i < num; i++) + new[i] = buffer[(start + i) % size]; + free(buffer); + buffer = new; + size = new_size; + start = 0; + } + + /* Search for this uid in the buffer, starting from the end. */ + for (i = start + num - 1; i >= start; i--) { + result = memcmp(uid, &buffer[i % size].uid, sizeof(*uid)); + if (result == 0 && buffer[i % size].kind == kind) { + /* Remove it from the buffer. We'll re-add it at the end. */ + for (j = i; j < start + num - 1; j++) { + buffer[j % size] = buffer[(j + 1) % size]; + } + num--; + found = 1; + break; + } + } + + /* Whether or not we found it, stick it at the end. */ + i = start + num; + buffer[i % size].uid = *uid; + buffer[i % size].kind = kind; + buffer[i % size].t = now; + num++; + + return found; +} + + +/* Return 1 if there is a packet waiting, 0 otherwise */ + +int +Z_PacketWaiting(void) +{ + struct timeval tv; + fd_set readfds; + + tv.tv_sec = tv.tv_usec = 0; + FD_ZERO(&readfds); + FD_SET(ZGetFD(), &readfds); + return (select(ZGetFD() + 1, &readfds, NULL, NULL, &tv)); +} + + +/* Wait for a complete notice to become available */ + +Code_t +Z_WaitForComplete(void) +{ + Code_t retval; + + if (__Q_CompleteLength) + return (Z_ReadEnqueue()); + + while (!__Q_CompleteLength) + if ((retval = Z_ReadWait()) != ZERR_NONE) + return (retval); + + return (ZERR_NONE); +} + + +/* Read any available packets and enqueue them */ + +Code_t +Z_ReadEnqueue(void) +{ + Code_t retval; + + if (ZGetFD() < 0) + return (ZERR_NOPORT); + + while (Z_PacketWaiting()) + if ((retval = Z_ReadWait()) != ZERR_NONE) + return (retval); + + return (ZERR_NONE); +} + + +/* + * Search the queue for a notice with the proper multiuid - remove any + * notices that haven't been touched in a while + */ + +struct _Z_InputQ * +Z_SearchQueue(ZUnique_Id_t *uid, + ZNotice_Kind_t kind) +{ + register struct _Z_InputQ *qptr; + struct _Z_InputQ *next; + struct timeval tv; + + (void) gettimeofday(&tv, (struct timezone *)0); + + qptr = __Q_Head; + + while (qptr) { + if (ZCompareUID(uid, &qptr->uid) && qptr->kind == kind) + return (qptr); + next = qptr->next; + if (qptr->timep && + (qptr->timep+Z_NOTICETIMELIMIT < (unsigned long)tv.tv_sec)) + Z_RemQueue(qptr); + qptr = next; + } + return (NULL); +} + +/* + * Now we delve into really convoluted queue handling and + * fragmentation reassembly algorithms and other stuff you probably + * don't want to look at... + * + * This routine does NOT guarantee a complete packet will be ready when it + * returns. + */ + +Code_t +Z_ReadWait(void) +{ + register struct _Z_InputQ *qptr; + ZNotice_t notice; + ZPacket_t packet; + struct sockaddr_in olddest, from; + unsigned int from_len; + int packet_len, zvlen, part, partof; + char *slash; + Code_t retval; + fd_set fds; + struct timeval tv; + ZUnique_Id_t *multiuid; + + if (ZGetFD() < 0) + return (ZERR_NOPORT); + + FD_ZERO(&fds); + FD_SET(ZGetFD(), &fds); + tv.tv_sec = 60; + tv.tv_usec = 0; + + if (select(ZGetFD() + 1, &fds, NULL, NULL, &tv) < 0) + return (errno); + if (!FD_ISSET(ZGetFD(), &fds)) + return ETIMEDOUT; + + from_len = sizeof(struct sockaddr_in); + + packet_len = recvfrom(ZGetFD(), packet, sizeof(packet), 0, + (struct sockaddr *)&from, &from_len); + + if (packet_len < 0) + return (errno); + + if (!packet_len) + return (ZERR_EOF); + + /* Ignore obviously non-Zephyr packets. */ + zvlen = sizeof(ZVERSIONHDR) - 1; + if (packet_len < zvlen || memcmp(packet, ZVERSIONHDR, zvlen) != 0) { + Z_discarded_packets++; + return (ZERR_BADPKT); + } + + /* Parse the notice */ + if ((retval = ZParseNotice(packet, packet_len, ¬ice)) != ZERR_NONE) + return (retval); + + /* + * If we're not a server and the notice is of an appropriate kind, + * send back a CLIENTACK to whoever sent it to say we got it. + */ + if (!__Zephyr_server) { + if (notice.z_kind != HMACK && notice.z_kind != SERVACK && + notice.z_kind != SERVNAK && notice.z_kind != CLIENTACK) { + ZNotice_t tmpnotice; + ZPacket_t pkt; + int len; + + tmpnotice = notice; + tmpnotice.z_kind = CLIENTACK; + tmpnotice.z_message_len = 0; + olddest = __HM_addr; + __HM_addr = from; + retval = ZFormatSmallRawNotice(&tmpnotice, pkt, &len); + if (retval == ZERR_NONE) + retval = ZSendPacket(pkt, len, 0); + __HM_addr = olddest; + if (retval != ZERR_NONE) + return retval; + } + if (find_or_insert_uid(¬ice.z_uid, notice.z_kind)) + return(ZERR_NONE); + + /* Check authentication on the notice. */ + notice.z_checked_auth = ZCheckAuthentication(¬ice, &from); + } + + + /* + * Parse apart the z_multinotice field - if the field is blank for + * some reason, assume this packet stands by itself. + */ + slash = strchr(notice.z_multinotice, '/'); + if (slash) { + part = atoi(notice.z_multinotice); + partof = atoi(slash+1); + if (part < 0 || part > partof || partof <= 0) { + part = 0; + partof = notice.z_message_len; + } + } else { + part = 0; + partof = notice.z_message_len; + } + + /* Too big a packet...just ignore it! */ + if (partof > Z_MAXNOTICESIZE) + return (ZERR_NONE); + + /* The packet has garbage at the end. This likely came from a cross-realm + * zephyrd without f276622ace757977fec43633e43577350e0cf6fe, which means + * it's retransmitting blindly anyway. Drop it on the floor. + */ + if (notice.z_message_len > partof - part) + return (ZERR_NONE); + + /* Pick the appropriate key to reassemble with. */ + switch (notice.z_kind) { + case SERVACK: + case SERVNAK: + /* For SERVACK and SERNACK replies, hold on to the reply + ONLY if it's the first part of a fragmented message, i.e. + multi_uid == uid. This allows programs to wait for the uid + of the first packet, and get a response when that notice + arrives. Acknowledgements of the other fragments are discarded + (XXX we assume here that they all carry the same information + regarding failure/success) + */ + if (!__Zephyr_server && + !ZCompareUID(¬ice.z_multiuid, ¬ice.z_uid)) + /* they're not the same... throw away this packet. */ + return(ZERR_NONE); + /* fall thru to general ACK case. */ + case HMACK: + /* The HMACK, SERVACK, and SERVNAK replies shouldn't be + reassembled (they have no parts). */ + multiuid = ¬ice.z_uid; + break; + default: + multiuid = ¬ice.z_multiuid; + } + /* + * If we aren't a server and we can find a notice in the queue + * with the same multiuid field, insert the current fragment as + * appropriate. + */ + if (!__Zephyr_server && (qptr = Z_SearchQueue(multiuid, notice.z_kind))) { + /* + * If this is the first fragment, and we haven't already + * gotten a first fragment, grab the header from it. + */ + if (part == 0 && !qptr->header) { + qptr->header_len = packet_len-notice.z_message_len; + qptr->header = (char *) malloc((unsigned) qptr->header_len); + if (!qptr->header) + return (ENOMEM); + (void) memcpy(qptr->header, packet, qptr->header_len); + } + return (Z_AddNoticeToEntry(qptr, ¬ice, part)); + } + + /* + * We'll have to create a new entry...make sure the queue isn't + * going to get too big. + */ + if (__Q_Size+(__Zephyr_server ? notice.z_message_len : partof) > Z_MAXQUEUESIZE) + return (ZERR_NONE); + + /* + * This is a notice we haven't heard of, so create a new queue + * entry for it and zero it out. + */ + qptr = (struct _Z_InputQ *)malloc(sizeof(struct _Z_InputQ)); + if (!qptr) + return (ENOMEM); + (void) memset((char *)qptr, 0, sizeof(struct _Z_InputQ)); + + /* Insert the entry at the end of the queue */ + qptr->next = NULL; + qptr->prev = __Q_Tail; + if (__Q_Tail) + __Q_Tail->next = qptr; + __Q_Tail = qptr; + + if (!__Q_Head) + __Q_Head = qptr; + + + /* Copy the from field, multiuid, kind, and checked authentication. */ + qptr->from = from; + qptr->uid = *multiuid; + qptr->kind = notice.z_kind; + qptr->auth = notice.z_checked_auth; + + /* + * If this is the first part of the notice, we take the header + * from it. We only take it if this is the first fragment so that + * the Unique ID's will be predictable. + * + * If a Zephyr Server, we always take the header. + */ + if (__Zephyr_server || part == 0) { + qptr->header_len = packet_len-notice.z_message_len; + qptr->header = (char *) malloc((unsigned) qptr->header_len); + if (!qptr->header) + return ENOMEM; + (void) memcpy(qptr->header, packet, qptr->header_len); + } + + /* + * If this is not a fragmented notice, then don't bother with a + * hole list. + * If we are a Zephyr server, all notices are treated as complete. + */ + if (__Zephyr_server || (part == 0 && notice.z_message_len == partof)) { + __Q_CompleteLength++; + qptr->holelist = (struct _Z_Hole *) 0; + qptr->complete = 1; + /* allocate a msg buf for this piece */ + if (notice.z_message_len == 0) + qptr->msg = 0; + else if (!(qptr->msg = (char *) malloc((unsigned) notice.z_message_len))) + return(ENOMEM); + else + (void) memcpy(qptr->msg, notice.z_message, notice.z_message_len); + qptr->msg_len = notice.z_message_len; + __Q_Size += notice.z_message_len; + qptr->packet_len = qptr->header_len+qptr->msg_len; + if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len))) + return (ENOMEM); + (void) memcpy(qptr->packet, qptr->header, qptr->header_len); + if(qptr->msg) + (void) memcpy(qptr->packet+qptr->header_len, qptr->msg, + qptr->msg_len); + return (ZERR_NONE); + } + + /* + * We know how long the message is going to be (this is better + * than IP fragmentation...), so go ahead and allocate it all. + */ + if (!(qptr->msg = (char *) malloc((unsigned) partof)) && partof) + return (ENOMEM); + qptr->msg_len = partof; + __Q_Size += partof; + + /* + * Well, it's a fragmented notice...allocate a hole list and + * initialize it to the full packet size. Then insert the + * current fragment. + */ + if (!(qptr->holelist = (struct _Z_Hole *) + malloc(sizeof(struct _Z_Hole)))) + return (ENOMEM); + qptr->holelist->next = (struct _Z_Hole *) 0; + qptr->holelist->first = 0; + qptr->holelist->last = partof-1; + return (Z_AddNoticeToEntry(qptr, ¬ice, part)); +} + + +/* Fragment management routines - compliments, more or less, of RFC815 */ + +Code_t +Z_AddNoticeToEntry(struct _Z_InputQ *qptr, + ZNotice_t *notice, + int part) +{ + int last, oldfirst, oldlast; + struct _Z_Hole *hole, *lasthole; + struct timeval tv; + + /* Make sure this notice is expirable */ + (void) gettimeofday(&tv, (struct timezone *)0); + qptr->timep = tv.tv_sec; + + /* Bounds check. */ + if (part < 0 || notice->z_message_len < 0 || part > qptr->msg_len + || notice->z_message_len > qptr->msg_len - part) + return (ZERR_NONE); + + /* Incorporate this notice's checked authentication. */ + if (notice->z_checked_auth == ZAUTH_FAILED) + qptr->auth = ZAUTH_FAILED; + else if (notice->z_checked_auth == ZAUTH_NO && qptr->auth != ZAUTH_FAILED) + qptr->auth = ZAUTH_NO; + + last = part+notice->z_message_len-1; + + hole = qptr->holelist; + lasthole = (struct _Z_Hole *) 0; + + /* copy in the message body */ + (void) memcpy(qptr->msg+part, notice->z_message, notice->z_message_len); + + /* Search for a hole that overlaps with the current fragment */ + while (hole) { + if (part <= hole->last && last >= hole->first) + break; + lasthole = hole; + hole = hole->next; + } + + /* If we found one, delete it and reconstruct a new hole */ + if (hole) { + oldfirst = hole->first; + oldlast = hole->last; + if (lasthole) + lasthole->next = hole->next; + else + qptr->holelist = hole->next; + free((char *)hole); + /* + * Now create new hole(s) that are the original hole without + * the current fragment. + */ + if (part > oldfirst) { + hole = (struct _Z_Hole *)malloc(sizeof(struct _Z_Hole)); + if (hole == NULL) + return ENOMEM; + hole->first = oldfirst; + hole->last = part-1; + /* Prepend to the list; holelist is unordered. */ + hole->next = qptr->holelist; + qptr->holelist = hole; + } + if (last < oldlast) { + hole = (struct _Z_Hole *)malloc(sizeof(struct _Z_Hole)); + if (hole == NULL) + return ENOMEM; + hole->first = last+1; + hole->last = oldlast; + /* Prepend to the list; holelist is unordered. */ + hole->next = qptr->holelist; + qptr->holelist = hole; + } + } + + if (!qptr->holelist) { + if (!qptr->complete) + __Q_CompleteLength++; + qptr->complete = 1; + qptr->timep = 0; /* don't time out anymore */ + qptr->packet_len = qptr->header_len+qptr->msg_len; + if (!(qptr->packet = (char *) malloc((unsigned) qptr->packet_len))) + return (ENOMEM); + (void) memcpy(qptr->packet, qptr->header, qptr->header_len); + (void) memcpy(qptr->packet+qptr->header_len, qptr->msg, + qptr->msg_len); + } + + return (ZERR_NONE); +} + +void +Z_gettimeofday(struct _ZTimeval *ztv, + struct timezone *tz) +{ + struct timeval tv; + (void) gettimeofday(&tv, tz); /* yeah, yeah, I know */ + ztv->tv_sec=tv.tv_sec; + ztv->tv_usec=tv.tv_usec; +} + +Code_t +Z_FormatHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len, + Z_AuthProc cert_routine) +{ + Code_t retval; + static char version[BUFSIZ]; /* default init should be all \0 */ + + if (!notice->z_sender) + notice->z_sender = ZGetSender(); + + if (notice->z_port == 0) { + if (ZGetFD() < 0) { + retval = ZOpenPort((u_short *)0); + if (retval != ZERR_NONE) + return (retval); + } + notice->z_port = __Zephyr_port; + } + + notice->z_multinotice = ""; + + (void) Z_gettimeofday(¬ice->z_uid.tv, (struct timezone *)0); + notice->z_uid.tv.tv_sec = htonl((u_long) notice->z_uid.tv.tv_sec); + notice->z_uid.tv.tv_usec = htonl((u_long) notice->z_uid.tv.tv_usec); + + (void) memcpy(¬ice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr)); + + if (notice->z_sender_sockaddr.ip4.sin_family == 0) { + (void) memset(¬ice->z_sender_sockaddr, 0, sizeof(notice->z_sender_sockaddr)); + notice->z_sender_sockaddr.ip4.sin_family = AF_INET; /*XXX*/ + notice->z_sender_sockaddr.ip4.sin_port = notice->z_port; + (void) memcpy(¬ice->z_sender_sockaddr.ip4.sin_addr, &__My_addr, sizeof(__My_addr)); +#ifdef HAVE_SOCKADDR_IN_SIN_LEN + notice->z_sender_sockaddr.ip4.sin_len = sizeof(notice->z_sender_sockaddr.ip4); +#endif + } + + notice->z_multiuid = notice->z_uid; + + if (!version[0]) + (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR, + ZVERSIONMINOR); + notice->z_version = version; + + return Z_FormatAuthHeader(notice, buffer, buffer_len, len, cert_routine); +} + +Code_t +Z_NewFormatHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len, + Z_AuthProc cert_routine) +{ + Code_t retval; + static char version[BUFSIZ]; /* default init should be all \0 */ + struct timeval tv; + + if (!notice->z_sender) + notice->z_sender = ZGetSender(); + + if (notice->z_port == 0) { + if (ZGetFD() < 0) { + retval = ZOpenPort((u_short *)0); + if (retval != ZERR_NONE) + return (retval); + } + notice->z_port = __Zephyr_port; + } + + notice->z_multinotice = ""; + + (void) gettimeofday(&tv, (struct timezone *)0); + notice->z_uid.tv.tv_sec = htonl((u_long) tv.tv_sec); + notice->z_uid.tv.tv_usec = htonl((u_long) tv.tv_usec); + + (void) memcpy(¬ice->z_uid.zuid_addr, &__My_addr, sizeof(__My_addr)); + + (void) memset(¬ice->z_sender_sockaddr, 0, sizeof(notice->z_sender_sockaddr)); + notice->z_sender_sockaddr.ip4.sin_family = AF_INET; /*XXX*/ + notice->z_sender_sockaddr.ip4.sin_port = notice->z_port; + (void) memcpy(¬ice->z_sender_sockaddr.ip4.sin_addr, &__My_addr, sizeof(__My_addr)); +#ifdef HAVE_SOCKADDR_IN_SIN_LEN + notice->z_sender_sockaddr.ip4.sin_len = sizeof(notice->z_sender_sockaddr.ip4); +#endif + + notice->z_multiuid = notice->z_uid; + + if (!version[0]) + (void) sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR, + ZVERSIONMINOR); + notice->z_version = version; + + return Z_NewFormatAuthHeader(notice, buffer, buffer_len, len, cert_routine); +} + +Code_t +Z_FormatAuthHeaderWithASCIIAddress(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len) +{ + notice->z_auth = 0; + notice->z_authent_len = 0; + notice->z_ascii_authent = ""; + notice->z_checksum = 0; + if (!(notice->z_sender_sockaddr.sa.sa_family == AF_INET || + notice->z_sender_sockaddr.sa.sa_family == AF_INET6)) + notice->z_sender_sockaddr.sa.sa_family = AF_INET; /* \/\/hatever *//*XXX*/ + + return Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, len, + NULL, NULL, NULL, NULL, 0, 1); +} + +Code_t +Z_FormatAuthHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len, + Z_AuthProc cert_routine) +{ + if (!cert_routine) { + notice->z_auth = 0; + notice->z_authent_len = 0; + notice->z_ascii_authent = ""; + notice->z_checksum = 0; + return (Z_FormatRawHeader(notice, buffer, buffer_len, + len, NULL, NULL)); + } + + return ((*cert_routine)(notice, buffer, buffer_len, len)); +} + +Code_t +Z_NewFormatAuthHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len, + Z_AuthProc cert_routine) +{ + if (!cert_routine) { + notice->z_auth = 0; + notice->z_authent_len = 0; + notice->z_ascii_authent = ""; + notice->z_checksum = 0; + return (Z_FormatRawHeader(notice, buffer, buffer_len, + len, NULL, NULL)); + } + + return ((*cert_routine)(notice, buffer, buffer_len, len)); +} + +Code_t +Z_NewFormatRawHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *hdr_len, + char **cksum_start, + int *cksum_len, + char **cstart, + char **cend) +{ + return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, + cksum_start, cksum_len, cstart, cend, 0, 0)); +} + +Code_t +Z_AsciiFormatRawHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *hdr_len, + char **cksum_start, + int *cksum_len, + char **cstart, + char **cend) +{ + return(Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, hdr_len, + cksum_start, cksum_len, cstart, cend, 1, 0)); +} + +static Code_t +Z_ZcodeFormatRawHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *hdr_len, + char **cksum_start, + int *cksum_len, + char **cstart, + char **cend, + int cksumstyle, + int addrstyle) +{ + static char version_nogalaxy[BUFSIZ]; /* default init should be all \0 */ + char newrecip[BUFSIZ]; + char *ptr, *end; + int i; + int addrlen = 0; + unsigned char *addraddr = NULL; + + if (!(notice->z_sender_sockaddr.sa.sa_family == AF_INET || + notice->z_sender_sockaddr.sa.sa_family == AF_INET6)) + return ZERR_ILLVAL; + + if (!notice->z_class) + notice->z_class = ""; + + if (!notice->z_class_inst) + notice->z_class_inst = ""; + + if (!notice->z_opcode) + notice->z_opcode = ""; + + if (!notice->z_recipient) + notice->z_recipient = ""; + + if (!notice->z_default_format) + notice->z_default_format = ""; + + ptr = buffer; + end = buffer+buffer_len; + + if (cksum_start) + *cksum_start = ptr; + + (void) sprintf(version_nogalaxy, "%s%d.%d", ZVERSIONHDR, + ZVERSIONMAJOR, ZVERSIONMINOR); + + notice->z_version = version_nogalaxy; + + if (Z_AddField(&ptr, version_nogalaxy, end)) + return (ZERR_HEADERLEN); + + if (ZMakeAscii32(ptr, end-ptr, + (notice->z_num_hdr_fields ? (notice->z_num_hdr_fields - notice->z_num_other_fields) : Z_NUMFIELDS) + notice->z_num_other_fields) + == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii32(ptr, end-ptr, notice->z_kind) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_uid, + sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_port)) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii32(ptr, end-ptr, notice->z_auth) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (ZMakeAscii32(ptr, end-ptr, notice->z_authent_len) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (Z_AddField(&ptr, notice->z_ascii_authent, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_class, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_class_inst, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_opcode, end)) + return (ZERR_HEADERLEN); + if (Z_AddField(&ptr, notice->z_sender, end)) + return (ZERR_HEADERLEN); + if (strchr(notice->z_recipient, '@') || !*notice->z_recipient) { + if (Z_AddField(&ptr, notice->z_recipient, end)) + return (ZERR_HEADERLEN); + } + else { + if (strlen(notice->z_recipient) + strlen(__Zephyr_realm) + 2 > + sizeof(newrecip)) + return (ZERR_HEADERLEN); + (void) sprintf(newrecip, "%s@%s", notice->z_recipient, __Zephyr_realm); + if (Z_AddField(&ptr, newrecip, end)) + return (ZERR_HEADERLEN); + } + if (Z_AddField(&ptr, notice->z_default_format, end)) + return (ZERR_HEADERLEN); + + /* copy back the end pointer location for crypto checksum */ + if (cstart) + *cstart = ptr; + if (cksumstyle == 1) { + if (Z_AddField(&ptr, notice->z_ascii_checksum, end)) + return (ZERR_HEADERLEN); + } else { +#ifdef xZCODE_K4SUM + if (ZMakeZcode32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN) + return ZERR_HEADERLEN; +#else + if (ZMakeAscii32(ptr, end-ptr, notice->z_checksum) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); +#endif + ptr += strlen(ptr)+1; + } + if (cend) + *cend = ptr; + + if (Z_AddField(&ptr, notice->z_multinotice, end)) + return (ZERR_HEADERLEN); + + if (ZMakeAscii(ptr, end-ptr, (unsigned char *)¬ice->z_multiuid, + sizeof(ZUnique_Id_t)) == ZERR_FIELDLEN) + return (ZERR_HEADERLEN); + ptr += strlen(ptr)+1; + + if (!notice->z_num_hdr_fields || notice->z_num_hdr_fields > 17) { + if (notice->z_sender_sockaddr.sa.sa_family == AF_INET) { + addrlen = sizeof(notice->z_sender_sockaddr.ip4.sin_addr); + addraddr = (unsigned char *)¬ice->z_sender_sockaddr.ip4.sin_addr; + } else if (notice->z_sender_sockaddr.sa.sa_family == AF_INET6) { + addrlen = sizeof(notice->z_sender_sockaddr.ip6.sin6_addr); + addraddr = (unsigned char *)¬ice->z_sender_sockaddr.ip6.sin6_addr; + } + + if (notice->z_sender_sockaddr.sa.sa_family == AF_INET && addrstyle) { + if (ZMakeAscii(ptr, end-ptr, addraddr, addrlen) == ZERR_FIELDLEN) + return ZERR_HEADERLEN; + } else { + if (ZMakeZcode(ptr, end-ptr, addraddr, addrlen) == ZERR_FIELDLEN) + return ZERR_HEADERLEN; + } + ptr += strlen(ptr) + 1; + } + + if (!notice->z_num_hdr_fields || notice->z_num_hdr_fields > 18) { + if (ZMakeAscii16(ptr, end-ptr, ntohs(notice->z_charset)) == ZERR_FIELDLEN) + return ZERR_HEADERLEN; + ptr += strlen(ptr) + 1; + } + + for (i=0;iz_num_other_fields;i++) + if (Z_AddField(&ptr, notice->z_other_fields[i], end)) + return (ZERR_HEADERLEN); + + if (cksum_len) + *cksum_len = ptr-*cksum_start; + + *hdr_len = ptr-buffer; + + return (ZERR_NONE); +} + +Code_t +Z_FormatRawHeader(ZNotice_t *notice, + char *buffer, + int buffer_len, + int *len, + char **cstart, + char **cend) +{ + + if (!(notice->z_sender_sockaddr.sa.sa_family == AF_INET || + notice->z_sender_sockaddr.sa.sa_family == AF_INET6)) + notice->z_sender_sockaddr.sa.sa_family = AF_INET; /* \/\/hatever *//*XXX*/ + + return Z_ZcodeFormatRawHeader(notice, buffer, buffer_len, len, + NULL, NULL, cstart, cend, 0, 0); +} + +static int +Z_AddField(char **ptr, + char *field, + char *end) +{ + register int len; + + len = field ? strlen (field) + 1 : 1; + + if (*ptr+len > end) + return 1; + if (field) + (void) strcpy(*ptr, field); + else + **ptr = '\0'; + *ptr += len; + + return 0; +} + +struct _Z_InputQ * +Z_GetFirstComplete(void) +{ + struct _Z_InputQ *qptr; + + qptr = __Q_Head; + + while (qptr) { + if (qptr->complete) + return (qptr); + qptr = qptr->next; + } + + return ((struct _Z_InputQ *)0); +} + +struct _Z_InputQ * +Z_GetNextComplete(struct _Z_InputQ *qptr) +{ + qptr = qptr->next; + while (qptr) { + if (qptr->complete) + return (qptr); + qptr = qptr->next; + } + + return ((struct _Z_InputQ *)0); +} + +void +Z_RemQueue(struct _Z_InputQ *qptr) +{ + struct _Z_Hole *hole, *nexthole; + + if (qptr->complete) + __Q_CompleteLength--; + + __Q_Size -= qptr->msg_len; + + if (qptr->header) + free(qptr->header); + if (qptr->msg) + free(qptr->msg); + if (qptr->packet) + free(qptr->packet); + + hole = qptr->holelist; + while (hole) { + nexthole = hole->next; + free((char *)hole); + hole = nexthole; + } + + if (qptr == __Q_Head && __Q_Head == __Q_Tail) { + free ((char *)qptr); + __Q_Head = (struct _Z_InputQ *)0; + __Q_Tail = (struct _Z_InputQ *)0; + return; + } + + if (qptr == __Q_Head) { + __Q_Head = qptr->next; + __Q_Head->prev = (struct _Z_InputQ *)0; + free ((char *)qptr); + return; + } + if (qptr == __Q_Tail) { + __Q_Tail = qptr->prev; + __Q_Tail->next = (struct _Z_InputQ *)0; + free ((char *)qptr); + return; + } + qptr->prev->next = qptr->next; + qptr->next->prev = qptr->prev; + free ((char *)qptr); + return; +} + +Code_t +Z_SendFragmentedNotice(ZNotice_t *notice, + int len, + Z_AuthProc cert_func, + Z_SendProc send_func) +{ + ZNotice_t partnotice; + ZPacket_t buffer; + char multi[64]; + int offset, hdrsize, fragsize, ret_len, message_len, waitforack; + Code_t retval; + + hdrsize = len-notice->z_message_len; + fragsize = Z_MAXPKTLEN-hdrsize-Z_FRAGFUDGE; + + offset = 0; + + waitforack = ((notice->z_kind == UNACKED || notice->z_kind == ACKED) + && !__Zephyr_server); + + partnotice = *notice; + + while (offset < notice->z_message_len || !notice->z_message_len) { + (void) sprintf(multi, "%d/%d", offset, notice->z_message_len); + partnotice.z_multinotice = multi; + if (offset > 0) { + (void) Z_gettimeofday(&partnotice.z_uid.tv, + (struct timezone *)0); + partnotice.z_uid.tv.tv_sec = + htonl((u_long) partnotice.z_uid.tv.tv_sec); + partnotice.z_uid.tv.tv_usec = + htonl((u_long) partnotice.z_uid.tv.tv_usec); + (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, + sizeof(__My_addr)); + (void) memset(¬ice->z_sender_sockaddr, 0, sizeof(notice->z_sender_sockaddr)); + notice->z_sender_sockaddr.ip4.sin_family = AF_INET; /*XXX*/ + notice->z_sender_sockaddr.ip4.sin_port = notice->z_port; + (void) memcpy(¬ice->z_sender_sockaddr.ip4.sin_addr, &__My_addr, sizeof(__My_addr)); +#ifdef HAVE_SOCKADDR_IN_SIN_LEN + notice->z_sender_sockaddr.ip4.sin_len = sizeof(notice->z_sender_sockaddr.ip4); +#endif + } + message_len = min(notice->z_message_len-offset, fragsize); + partnotice.z_message = notice->z_message+offset; + partnotice.z_message_len = message_len; + if ((retval = Z_FormatAuthHeader(&partnotice, buffer, Z_MAXHEADERLEN, + &ret_len, cert_func)) != ZERR_NONE) { + return (retval); + } + memcpy(buffer + ret_len, partnotice.z_message, message_len); + if ((retval = (*send_func)(&partnotice, buffer, ret_len+message_len, + waitforack)) != ZERR_NONE) { + return (retval); + } + offset += fragsize; + if (!notice->z_message_len) + break; + } + + return (ZERR_NONE); +} + +/*ARGSUSED*/ +Code_t Z_XmitFragment(ZNotice_t *notice, + char *buf, + int len, + int waitforack) +{ + return(ZSendPacket(buf, len, waitforack)); +} + +/* For debugging printing */ +const char *const ZNoticeKinds[] = { + "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK", + "CLIENTACK", "STAT" +}; + +#ifdef Z_DEBUG + +#undef Z_debug +void +Z_debug(const char *format, ...) +{ + va_list pvar; + if (!__Z_debug_print) + return; + va_start (pvar, format); + (*__Z_debug_print) (format, pvar, __Z_debug_print_closure); + va_end (pvar); +} + +void +Z_debug_stderr(const char *format, + va_list args, + void *closure) +{ +#ifdef HAVE_VPRINTF + vfprintf (stderr, format, args); +#else + _doprnt (format, args, stderr); +#endif + putc ('\n', stderr); +} + +#undef ZSetDebug +void +ZSetDebug(void (*proc)(const char *, va_list, void *), + char *arg) +{ + __Z_debug_print = proc; + __Z_debug_print_closure = arg; +} +#endif /* Z_DEBUG */ + +#ifdef HAVE_KRB5 +Code_t +Z_Checksum(krb5_data *cksumbuf, + krb5_keyblock *keyblock, + krb5_cksumtype cksumtype, + krb5_keyusage cksumusage, + char **asn1_data, + unsigned int *asn1_len) +{ + krb5_error_code result; + unsigned char *data; + int len; +#ifndef HAVE_KRB5_CRYPTO_INIT + krb5_checksum checksum; +#else + Checksum checksum; + krb5_crypto cryptctx; +#endif + +#ifndef HAVE_KRB5_CRYPTO_INIT + /* Create the checksum -- MIT crypto API */ + result = krb5_c_make_checksum(Z_krb5_ctx, cksumtype, + keyblock, cksumusage, + cksumbuf, &checksum); + if (result) + return result; + /* HOLDING: checksum */ + + data = checksum.contents; + len = checksum.length; +#else + /* Create the checksum -- heimdal crypto API */ + result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, + &cryptctx); + if (result) + return result; + + /* HOLDING: cryptctx */ + result = krb5_create_checksum(Z_krb5_ctx, cryptctx, + cksumusage, cksumtype, + cksumbuf->data, cksumbuf->length, + &checksum); + krb5_crypto_destroy(Z_krb5_ctx, cryptctx); + if (result) + return result; + + len = checksum.checksum.length; + data = checksum.checksum.data; + /* HOLDING: checksum */ +#endif + + *asn1_data = malloc(len); + if (*asn1_data == NULL) + return errno; + memcpy(*asn1_data, data, len); + *asn1_len = len; + +#ifndef HAVE_KRB5_CRYPTO_INIT + krb5_free_checksum_contents(Z_krb5_ctx, &checksum); +#else + free_Checksum(&checksum); +#endif + + return 0; +} + +Code_t +Z_InsertZcodeChecksum(krb5_keyblock *keyblock, + ZNotice_t *notice, + char *buffer, + char *cksum_start, + int cksum_len, + char *cstart, + char *cend, + int buffer_len, + int *length_adjust, + int from_server) +{ + int plain_len; /* length of part not to be checksummed */ + int cksum0_len; /* length of part before checksum */ + int cksum1_len; /* length of part after checksum */ + krb5_data cksumbuf; + krb5_data cksum; + unsigned char *cksum_data; + unsigned int cksum_data_len; + char *cksum_out_data; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + Code_t result; + + result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); + if (result) + return (ZAUTH_FAILED); + + /* Assemble the things to be checksummed */ + plain_len = cksum_start - buffer; + cksum0_len = cstart - cksum_start; + cksum1_len = (cksum_start + cksum_len) - cend; + memset(&cksumbuf, 0, sizeof(cksumbuf)); + cksumbuf.length = cksum0_len + cksum1_len + notice->z_message_len; + cksumbuf.data = malloc(cksumbuf.length); + if (!cksumbuf.data) + return ENOMEM; + cksum_data = (unsigned char *)cksumbuf.data; + memcpy(cksum_data, cksum_start, cksum0_len); + memcpy(cksum_data + cksum0_len, cend, cksum1_len); + memcpy(cksum_data + cksum0_len + cksum1_len, + notice->z_message, notice->z_message_len); + /* compute the checksum */ + result = Z_Checksum(&cksumbuf, keyblock, cksumtype, + from_server ? Z_KEYUSAGE_SRV_CKSUM + : Z_KEYUSAGE_CLT_CKSUM, + &cksum_out_data, &cksum_data_len); + if (result) { + free(cksumbuf.data); + return result; + } + cksum.data = cksum_out_data; + cksum.length = cksum_data_len; + + /* + * OK.... we can zcode to a space starting at 'cstart', + * with a length of buffer_len - (plain_len + cksum_len). + * Then we tack on the end part, which is located at + * cksumbuf.data + cksum0_len and has length cksum1_len + */ + + result = ZMakeZcode(cstart, buffer_len - (plain_len + cksum_len), + (unsigned char *)cksum.data, cksum.length); + free(cksum.data); + if (!result) { + int zcode_len = strlen(cstart) + 1; + memcpy(cstart + zcode_len, cksum_data + cksum0_len, cksum1_len); + *length_adjust = zcode_len - cksum_len + (cksum0_len + cksum1_len); + } + free(cksumbuf.data); + return result; +} + +Code_t +Z_ExtractEncCksum(krb5_keyblock *keyblock, + krb5_enctype *enctype, + krb5_cksumtype *cksumtype) +{ + *enctype = Z_enctype(keyblock); + return Z_krb5_lookup_cksumtype(*enctype, cksumtype); +} +#endif + +#ifdef HAVE_KRB5 +/* returns 0 if invalid or losing, 1 if valid, *sigh* */ +int +Z_krb5_verify_cksum(krb5_keyblock *keyblock, + krb5_data *cksumbuf, + krb5_cksumtype cksumtype, + krb5_keyusage cksumusage, + unsigned char *asn1_data, + int asn1_len) +{ + krb5_error_code result; +#ifndef HAVE_KRB5_CRYPTO_INIT + krb5_checksum checksum; + krb5_boolean valid; +#else + krb5_crypto cryptctx; + Checksum checksum; +#endif + + memset(&checksum, 0, sizeof(checksum)); +#ifndef HAVE_KRB5_CRYPTO_INIT + /* Verify the checksum -- MIT crypto API */ + checksum.length = asn1_len; + checksum.contents = asn1_data; + checksum.checksum_type = cksumtype; + result = krb5_c_verify_checksum(Z_krb5_ctx, + keyblock, cksumusage, + cksumbuf, &checksum, &valid); + if (!result && valid) + return 1; + else + return 0; +#else + checksum.checksum.length = asn1_len; + checksum.checksum.data = asn1_data; + checksum.cksumtype = cksumtype; + + result = krb5_crypto_init(Z_krb5_ctx, keyblock, keyblock->keytype, &cryptctx); + if (result) + return 0; + + /* HOLDING: cryptctx */ + result = krb5_verify_checksum(Z_krb5_ctx, cryptctx, cksumusage, + cksumbuf->data, cksumbuf->length, + &checksum); + krb5_crypto_destroy(Z_krb5_ctx, cryptctx); + if (result) + return 0; + else + return 1; +#endif +} +#endif diff --git a/lib/charset.c b/lib/charset.c new file mode 100644 index 0000000..14aec28 --- /dev/null +++ b/lib/charset.c @@ -0,0 +1,139 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains source for the ZGetCharset function. + * + * Created by: Karl Ramm + * + * $Id$ + * + * Copyright (c) 2009 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef lint +static const char rcsid_charset_c[] = "$Id$"; +#endif /* lint */ + +#include + +#include +#include +#include +#include +#include +#include + +const char * +ZGetCharsetString(char *charset) +{ + char *p; + static int once = 1; + + if (charset == NULL) + charset = getenv("ZEPHYR_CHARSET"); + + if (charset == NULL) { + if (once) { + setlocale(LC_ALL, ""); + once = 0; + } + charset = nl_langinfo(CODESET); + } + + if (charset == NULL) + return ZCHARSET_UNKNOWN; + + charset = strdup(charset); + + for (p = charset; *p; p++) + *p = toupper(*p); + + return charset; +} + +unsigned short +ZGetCharset(char *charset) +{ + short retval; + + charset = (char *)ZGetCharsetString(charset); + if (!strcmp(charset, "NONE") || !strcmp(charset, "UNKNOWN")) + retval = ZCHARSET_UNKNOWN; + else if (!strcmp(charset, "ANSI_X3.4-1968")) + retval = ZCHARSET_ISO_8859_1; /* A hack. */ + else if (!strcmp(charset, "ISO-8859-1")) + retval = ZCHARSET_ISO_8859_1; + else if (!strcmp(charset, "UTF-8")) + retval = ZCHARSET_UTF_8; + else + retval = ZCHARSET_UNKNOWN; + + free(charset); + return retval; +} + +const char * +ZCharsetToString(unsigned short charset) +{ + if (charset == ZCHARSET_UNKNOWN) + return "UNKNOWN"; + else if (charset == ZCHARSET_ISO_8859_1) + return "ISO-8859-1"; + else if (charset == ZCHARSET_UTF_8) + return "UTF-8"; + return "UNKNOWN"; +} + +Code_t +ZTransliterate(char *in, int inlen, char *inset, char *outset, char **out, int *outlen) +{ + iconv_t ih; + char *outset_t, *inp, *outp; + int retval; + size_t size, inleft, outleft; + + *out = NULL; + *outlen = 0; + + outset_t = malloc(strlen(outset) + 11); + if (outset_t == NULL) + return errno; + sprintf(outset_t, "%s//TRANSLIT", outset); + + ih = iconv_open(outset_t, inset); + + free(outset_t); + + if (ih == (iconv_t)-1) + return errno; + + size = inlen; /* doubling this should be enough, but.. */ + do { + size = size * 2; + + *out = malloc(size); + if (*out == NULL) { + iconv_close(ih); + return errno; + } + + inleft = inlen; + outleft = size; + + inp = in; + outp = *out; + + retval = iconv(ih, &inp, &inleft, &outp, &outleft); + if (retval < 0) + free(*out); + } while (retval < 0 && errno == E2BIG); + + iconv_close(ih); + + if (retval < 0) + return errno; + + *outlen = size - outleft; + + return ZERR_NONE; +} diff --git a/lib/mit-copyright.h b/lib/mit-copyright.h new file mode 100644 index 0000000..73059b3 --- /dev/null +++ b/lib/mit-copyright.h @@ -0,0 +1,24 @@ +/* + +Copyright 1987,1988 by the Massachusetts Institute of Technology + +All rights reserved. + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the name of the Massachusetts +Institute of Technology (M.I.T.) not be used in advertising or publicity +pertaining to distribution of the software without specific, written +prior permission. + +M.I.T. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING +ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL +M.I.T. BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR +ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS +SOFTWARE. + +*/ diff --git a/lib/quad_cksum.c b/lib/quad_cksum.c new file mode 100644 index 0000000..3e5d377 --- /dev/null +++ b/lib/quad_cksum.c @@ -0,0 +1,196 @@ +/* Lifted from the krb5 1.6 source tree and hacked slightly to fit in here + Karl Ramm 12/21/08 */ +/* + * lib/des425/quad_cksum.c + * + * Copyright 1985, 1986, 1987, 1988,1990 by the Massachusetts Institute + * of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. Furthermore if you modify this software you must label + * your software as modified software and not distribute it in such a + * fashion that it might be confused with the original M.I.T. software. + * M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * This routine does not implement: + * + * + * Quadratic Congruential Manipulation Dectection Code + * + * ref: "Message Authentication" + * R.R. Jueneman, S. M. Matyas, C.H. Meyer + * IEEE Communications Magazine, + * Sept 1985 Vol 23 No 9 p 29-40 + * + * This routine, part of the Athena DES library built for the Kerberos + * authentication system, calculates a manipulation detection code for + * a message. It is a much faster alternative to the DES-checksum + * method. No guarantees are offered for its security. + * + * Implementation for 4.2bsd + * by S.P. Miller Project Athena/MIT + */ + +/* + * Algorithm (per paper): + * define: + * message to be composed of n m-bit blocks X1,...,Xn + * optional secret seed S in block X1 + * MDC in block Xn+1 + * prime modulus N + * accumulator Z + * initial (secret) value of accumulator C + * N, C, and S are known at both ends + * C and , optionally, S, are hidden from the end users + * then + * (read array references as subscripts over time) + * Z[0] = c; + * for i = 1...n + * Z[i] = (Z[i+1] + X[i])**2 modulo N + * X[n+1] = Z[n] = MDC + * + * Then pick + * N = 2**31 -1 + * m = 16 + * iterate 4 times over plaintext, also use Zn + * from iteration j as seed for iteration j+1, + * total MDC is then a 128 bit array of the four + * Zn; + * + * return the last Zn and optionally, all + * four as output args. + * + * Modifications: + * To inhibit brute force searches of the seed space, this + * implementation is modified to have + * Z = 64 bit accumulator + * C = 64 bit C seed + * N = 2**63 - 1 + * S = S seed is not implemented here + * arithmetic is not quite real double integer precision, since we + * cant get at the carry or high order results from multiply, + * but nontheless is 64 bit arithmetic. + */ +/* + * This code purports to implement the above algorithm, but fails. + * + * First of all, there was an implicit mod 2**32 being done on the + * machines where this was developed because of their word sizes, and + * for compabitility this has to be done on machines with 64-bit + * words, so we make it explicit. + * + * Second, in the squaring operation, I really doubt the carry-over + * from the low 31-bit half of the accumulator is being done right, + * and using a modulus of 0x7fffffff on the low half of the + * accumulator seems completely wrong. And I challenge anyone to + * explain where the number 83653421 comes from. + * + * --Ken Raeburn 2001-04-06 + */ + + +/* System include files */ +#include +#include +#include + +#include + +/* Definitions for byte swapping */ + +/* vax byte order is LSB first. This is not performance critical, and + is far more readable this way. */ +#define four_bytes_vax_to_nets(x) ((((((x[3]<<8)|x[2])<<8)|x[1])<<8)|x[0]) +#define vaxtohl(x) four_bytes_vax_to_nets(((const unsigned char *)(x))) +#define two_bytes_vax_to_nets(x) ((x[1]<<8)|x[0]) +#define vaxtohs(x) two_bytes_vax_to_nets(((const unsigned char *)(x))) + +/*** Routines ***************************************************** */ +#ifdef HAVE_KRB5 +unsigned long +z_quad_cksum(const unsigned char *in, /* input block */ + uint32_t *out, /* optional longer output */ + long length, /* original length in bytes */ + int out_count, /* number of iterations */ + unsigned char *c_seed /* secret seed, 8 bytes */ + ) +{ + + /* + * this routine both returns the low order of the final (last in + * time) 32bits of the checksum, and if "out" is not a null + * pointer, a longer version, up to entire 32 bytes of the + * checksum is written unto the address pointed to. + */ + + register uint32_t z; + register uint32_t z2; + register uint32_t x; + register uint32_t x2; + const unsigned char *p; + register int32_t len; + register int i; + + /* use all 8 bytes of seed */ + + z = vaxtohl(c_seed); + z2 = vaxtohl((const char *)c_seed+4); + if (out == NULL) + out_count = 1; /* default */ + + /* This is repeated n times!! */ + for (i = 1; i <=4 && i<= out_count; i++) { + len = length; + p = in; + while (len) { + /* + * X = Z + Input ... sort of. Carry out from low half + * isn't done, so we're using all 32 bits of x now. + */ + if (len > 1) { + x = (z + vaxtohs(p)); + p += 2; + len -= 2; + } + else { + x = (z + *(const unsigned char *)p++); + len = 0; + } + x2 = z2; + /* + * I think this is supposed to be a squaring operation. + * What it really is, I haven't figured out yet. + * + * Explicit mod 2**32 is for backwards compatibility. Why + * mod 0x7fffffff and not 0x80000000 on the low half of + * the (supposed) accumulator? And where does the number + * 83653421 come from?? + */ + z = (((x * x) + (x2 * x2)) & 0xffffffff) % 0x7fffffff; + z2 = ((x * (x2+83653421)) & 0xffffffff) % 0x7fffffff; /* modulo */ + } + + if (out != NULL) { + *out++ = z; + *out++ = z2; + } + } + /* return final z value as 32 bit version of checksum */ + return z; +} +#endif diff --git a/lib/smwgc.c b/lib/smwgc.c new file mode 100644 index 0000000..2289654 --- /dev/null +++ b/lib/smwgc.c @@ -0,0 +1,64 @@ +/* Copyright (c) 1988 by the Massachusetts Institute of Technology. + * All Rights Reserved. + */ +#include + +main() +{ + FILE *fp; + char buf[512],*ptr; + int auth,retval; + u_short port; + ZNotice_t notice; + ZSubscription_t sub; + struct sockaddr_in from; + + if ((retval = ZInitialize()) != ZERR_NONE) { + com_err("foo",retval,"initing"); + exit(1); + } + + port = 0; + if ((retval = ZOpenPort(&port)) != ZERR_NONE) { + com_err("foo",retval,"opening port"); + exit(1); + } + printf("Using port %d\n",(int)port); + sprintf(buf,"/tmp/wg.%d",getuid()); + fp = fopen(buf,"w"); + if (!fp) { + com_err("foo",errno,"opening file"); + exit(1); + } + fprintf(fp,"%d\n",(int)port); + fclose(fp); + + printf("All ready...\n"); + + sub.class = "MESSAGE"; + sub.classinst = "PERSONAL"; + sub.recipient = ZGetSender(); + + if ((retval = ZSubscribeTo(&sub,1,port)) != ZERR_NONE) { + com_err("foo",retval,"subscribing"); + exit(1); + } + for (;;) { + if ((retval = ZReceiveNotice(¬ice,&from)) != ZERR_NONE) { + com_err("foo",retval,"receiving packet"); + continue; + } + auth = ZCheckAuthentication(¬ice,&from); + printf("Class = %s Instance = %s Sender = %s\nTime = %s Auth = %d\n", + notice.z_class,notice.z_class_inst,notice.z_sender, + ctime(¬ice.z_time.tv_sec),auth); + printf("Len = %d\n",notice.z_message_len); +/* ptr = notice.z_message; + for (;ptrz_uid directly + notice1 = ZNotice_t() + zbuf = c_char_p(0) + zbuflen = c_int(0) + st = self._libzephyr.ZFormatNotice(notice1, zbuf, zbuflen, ZNOAUTH) + assert st == 0, "ZFormatNotice notice1 failed" + + notice2 = ZNotice_t() + zbuf = c_char_p(0) + zbuflen = c_int(0) + st = self._libzephyr.ZFormatNotice(notice2, zbuf, zbuflen, ZNOAUTH) + assert st == 0, "ZFormatNotice notice2 failed" + + assert not self._libzephyr.ZCompareUID(notice1.z_uid, notice2.z_uid), "distinct notices don't compare as distinct" + # ctypes_pprint(notice1.z_uid) + + def test_zauthtype(self): + """Make sure Zauthtype is an acceptable value""" + assert self._libzephyr.Zauthtype in (0, 4, 5) + + def test_z_expand_realm(self): + """test ZExpandRealm""" + if self._libzephyr.Zauthtype: + assert self._libzephyr.ZExpandRealm("") == "" + assert self._libzephyr.ZExpandRealm("localhost") == "" + assert self._libzephyr.ZExpandRealm("bitsy.mit.edu") == "ATHENA.MIT.EDU" + else: + assert self._libzephyr.ZExpandRealm("") == "" + assert self._libzephyr.ZExpandRealm("localhost") == socket.getfqdn("localhost").upper() + assert self._libzephyr.ZExpandRealm("bitsy.mit.edu") == "BITSY.MIT.EDU" + +def find_buildpath(): + parser = optparse.OptionParser(usage=__doc__, + version = "%%prog %s" % __version__) + parser.add_option("--builddir", default="..", + help="where to find the top of the build tree") + parser.add_option("--verbose", "-v", action="store_true", + help="pass through for doctest.testfile") + opts, args = parser.parse_args() + assert not args, "no args yet" + + return os.path.join(opts.builddir, "lib") + +def getsockname(fd): + """wrapped C lib getsocketname (works on raw fd)""" + libc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("c")) + + call_getsockname = libc.getsockname + call_getsockname.argtypes = [ + c_int, # int s + POINTER(sockaddr), # struct sockaddr *name + POINTER(c_int), # socklen_t *namelen + ] + name = sockaddr(0) + namelen = c_int(sizeof(name)) + ret = call_getsockname(fd, name, namelen) + if ret == 0: + return name + # we can't get at errno until python 2.6... + print ret + raise EnvironmentError("getsockname failed") + + +if __name__ == "__main__": + tester = ZephyrTestSuite(builddir=find_buildpath()) + tester.setup() + failures = tester.run() + tester.cleanup() + for failure, exc in failures: + print "FAIL:", failure, str(exc) diff --git a/lib/zephyr_tests.txt b/lib/zephyr_tests.txt new file mode 100644 index 0000000..7e66dbc --- /dev/null +++ b/lib/zephyr_tests.txt @@ -0,0 +1,362 @@ +Zephyr Library Tests + +This file is a collection of doctests for the zephyr library. +Minimum coverage goal is "every non-static function, and every data +structure that shows up in those function prototypes." + +This file is also a test of the practicality of rich doctests as API +documentation. It will start out as a bunch of snippets, and later be +edited to use actual chapters and appendices - narrative structure +beyond "here's a test! here's another test!" At that point we'll also +pick a formatting language (probably ReStructured Text but for now, we +need no more than whitespace separated paragraphs to be +comprehensible.) + +Generic library setup that should be moved into zephyr_tests.py: + + >>> import os, socket + >>> import zephyr_tests + >>> buildpath = zephyr_tests.find_buildpath() + >>> libzephyr_path = zephyr_tests.find_libzephyr() + >>> _z = zephyr_tests.libZephyr(libzephyr_path) + +ZInit() got run by libZephyr, internally. Make sure other things +actually got set up: + + >>> assert _z.ZGetFD() == -1 + >>> Zauthtype = _z.Zauthtype + >>> assert Zauthtype in (0, 4, 5) + >>> realm = _z.ZGetRealm() + >>> assert realm + >>> if Zauthtype: assert realm != 'local-realm' + >>> if not Zauthtype: assert realm == 'local-realm' + >>> assert _z.ZGetSender() + >>> assert "@" in _z.ZGetSender() + +ZNotice_t structure pseudo-round-trip (needs a lot more explicit +settings and assertions to be a real round-trip test...) + + >>> notice = zephyr_tests.ZNotice_t() + >>> from ctypes import sizeof + >>> assert sizeof(notice) > 150 + >>> from ctypes import c_char_p, c_int + >>> zbuf = c_char_p(0) + >>> zbuflen = c_int(0) + >>> st = _z.ZFormatNotice(notice, zbuf, zbuflen, zephyr_tests.ZNOAUTH) + >>> assert st == 0 + >>> assert zbuf.value.startswith("ZEPH") + >>> new_notice = zephyr_tests.ZNotice_t() + >>> st = _z.ZParseNotice(zbuf, zbuflen, new_notice) + >>> assert st == 0 + >>> assert new_notice.z_version.startswith("ZEPH") + +Should we check for ZEPH0.2 now, or leave that open? + + >>> notice = zephyr_tests.ZNotice_t() + >>> notice.z_kind = zephyr_tests.ZNotice_Kind_t.UNSAFE + >>> notice.z_class = c_char_p("testclass") + >>> notice.z_class_inst = c_char_p("testinstance") + >>> notice.z_opcode = c_char_p("TESTOPCODE") + >>> notice.z_sender = c_char_p("someone") + >>> notice.z_recipient = c_char_p("someone_else") + >>> notice.z_message = c_char_p("short message body") + >>> notice.z_message_len = c_int(len("short message body")) + >>> zbuf = c_char_p(0) + >>> zbuflen = c_int(0) + >>> st = _z.ZFormatNotice(notice, zbuf, zbuflen, zephyr_tests.ZNOAUTH) + >>> assert st == 0 + >>> assert zbuf.value.startswith("ZEPH") + >>> new_notice = zephyr_tests.ZNotice_t() + >>> st = _z.ZParseNotice(zbuf, zbuflen, new_notice) + >>> assert st == 0 + >>> assert new_notice.z_version.startswith("ZEPH") + >>> new_notice.z_class + 'testclass' + >>> new_notice.z_class_inst + 'testinstance' + >>> new_notice.z_opcode + 'TESTOPCODE' + >>> new_notice.z_message[:new_notice.z_message_len] + 'short message body' + +Simple test of ZCompareUID: + + >>> uid1 = zephyr_tests.ZUnique_Id_t() + >>> uid2 = zephyr_tests.ZUnique_Id_t() + >>> assert _z.ZCompareUID(uid1, uid2), "null uids don't match" + +There's no ZUnique_Id_t constructor - Z_FormatHeader and +Z_NewFormatHeader initialize notice->z_uid directly, so cheat and use +ZNotice_t as the constructor... + + >>> notice1 = zephyr_tests.ZNotice_t() + >>> zbuf = c_char_p(0) + >>> zbuflen = c_int(0) + >>> st = _z.ZFormatNotice(notice1, zbuf, zbuflen, zephyr_tests.ZNOAUTH) + >>> assert st == 0, "ZFormatNotice notice1 failed" + + >>> notice2 = zephyr_tests.ZNotice_t() + >>> zbuf = c_char_p(0) + >>> zbuflen = c_int(0) + >>> st = _z.ZFormatNotice(notice2, zbuf, zbuflen, zephyr_tests.ZNOAUTH) + >>> assert st == 0, "ZFormatNotice notice1 failed" + + >>> assert not _z.ZCompareUID(notice1.z_uid, notice2.z_uid), "distinct notices don't compare as distinct" + +Trivial test of ZExpandRealm, using terribly well known hostnames: + + >>> assert _z.ZExpandRealm("") == "" + >>> if Zauthtype: assert _z.ZExpandRealm("localhost") == "" + >>> if Zauthtype: assert _z.ZExpandRealm("bitsy.mit.edu") == "ATHENA.MIT.EDU" + >>> if not Zauthtype: assert _z.ZExpandRealm("localhost") == socket.getfqdn("localhost").upper() + >>> if not Zauthtype: assert _z.ZExpandRealm("bitsy.mit.edu") == "BITSY.MIT.EDU" + +ZGetCharsetString is a utility function for clients that need to know the +full name of the output character set, e.g. zwgc. Calling it +with NULL will get it from $ZEPHYR_CHARSET or the locale. +Trivial testing of ZGetCharsetString: + + >>> os.environ['LANG'] = 'C' + >>> assert _z.ZGetCharsetString(None) == 'ANSI_X3.4-1968', "charset is " + _z.ZGetCharsetString(None) + >>> os.environ['ZEPHYR_CHARSET'] = 'ISO-8859-1' + >>> assert _z.ZGetCharsetString(None) == 'ISO-8859-1' + >>> assert _z.ZGetCharsetString('UTF-8') == 'UTF-8' + +ZGetCharset is a utility function for clients that need to know the +registry number of a character set, e.g. zwrite. It gets its defaults from +alal the places that ZGetCharsetString does, because it calls it. +Trivial testing of ZGetCharset: + + >>> assert _z.ZGetCharset(None) == 4 + >>> assert _z.ZGetCharset('NONE') == 0 + >>> assert _z.ZGetCharset('UNKNOWN') == 0 + >>> assert _z.ZGetCharset('ANSI_X3.4-1968') == 4 + >>> assert _z.ZGetCharset('ISO-8859-1') == 4 + >>> assert _z.ZGetCharset('UTF-8') == 106 + >>> assert _z.ZGetCharset('GIANT RUBBER PANTS') == 0 + +ZCharsetToString converts the registry numbers of the "allowed" character +sets into strings. +Trivial testing of ZCharsetToString: + + >>> assert _z.ZCharsetToString(0) == 'UNKNOWN' + >>> assert _z.ZCharsetToString(4) == 'ISO-8859-1' + >>> assert _z.ZCharsetToString(106) == 'UTF-8' + >>> assert _z.ZCharsetToString(1701) == 'UNKNOWN' + +ZTransliterate does character set conversion for display purposes, and when +it works, it sticks a malloc'd buffer in to **bufp. +"Trivial" testing of ZTransliterate: + + >>> from ctypes import c_char_p, c_int, byref, string_at + >>> from errno import EINVAL, EILSEQ + >>> bufp = c_char_p(None) + >>> length = c_int(0) + >>> assert _z.ZTransliterate('test', 4, 'ANSI_X3.4-1968', 'ANSI_X3.4-1968', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 'test' + >>> assert _z.ZTransliterate('test', 4, 'ANSI_X3.4-1968', 'UTF-8', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 'test' + >>> assert _z.ZTransliterate('test', 4, 'ISO-8859-1', 'ANSI_X3.4-1968', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 'test' + >>> assert _z.ZTransliterate('test', 4, 'ISO-8859-1', 'ANSI_X3.4-1968', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 'test' + >>> assert _z.ZTransliterate('t\xebst', 4, 'ISO-8859-1', 'ANSI_X3.4-1968', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 't?st', "transliterated string is " + string_at(bufp, length) + >>> assert _z.ZTransliterate('t\xebst', 4, 'ISO-8859-1', 'UTF-8', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 't\xc3\xabst' + >>> assert _z.ZTransliterate('t\xc3\xabst', 5, 'UTF-8', 'ISO-8859-1', byref(bufp), byref(length)) == 0 + >>> assert string_at(bufp, length) == 't\xebst' + >>> assert _z.ZTransliterate('t\xc3\xabst', 5, 'UTF-8', 'Oh, my bees', byref(bufp), byref(length)) == EINVAL + >>> assert _z.ZTransliterate('t\xc3x\xabst', 5, 'UTF-8', 'ISO-8859-1', byref(bufp), byref(length)) == EILSEQ + +Trivial test of ZOpenPort and ZClosePort: + + >>> from ctypes import c_ushort + >>> port = c_ushort(0) + >>> st = _z.ZOpenPort(port) + >>> assert st == 0 + >>> assert _z.ZGetFD() != -1 + >>> zsock = zephyr_tests.getsockname(_z.ZGetFD()) + >>> assert zsock + >>> from socket import AF_INET + >>> assert zsock.sa_family.value == AF_INET, zsock.sa_family.value + +(Here we're actually using getsockname as an "is that file descriptor + a socket" test; the wrapper is weak in that it can't check for + ENOTSOCK without requiring Python 2.6, so it just throws an exception + on any return of -1. If ctypes.cast worked on sockaddr, we could + also cast it to sockaddr_in and look at the address and port...) + + >>> assert port != 0 + >>> print type(_z.ZGetDestAddr()) + + >>> print _z.ZGetDestAddr().sin_family.pformat() + ['AF_INET(2)'] + >>> print _z.ZGetDestAddr().sin_addr.pformat() + ['127.0.0.1'] + >>> assert _z.ZClosePort() == 0 + >>> assert _z.ZGetFD() == -1 + +ZMakeAscii takes a target buffer and length and an input buffer and +length, and generates the "special" Zephyr encoding. + +TODO: use the "reference" implementation to run a bunch of +random-value comparison tests. + + >>> sample = "test\0message" + >>> ref = zephyr_tests.py_make_ascii(sample) + >>> from ctypes import create_string_buffer + >>> outlen = len(sample) * 6 + >>> outbuf = create_string_buffer(outlen) + >>> st = _z.ZMakeAscii(outbuf, outlen, sample, len(sample)) + >>> assert st == 0 + >>> assert outbuf.value == ref, "%r != %r" % (outbuf.value, ref) + +A few simple string tests: + >>> def zma(sample): + ... outlen = len(sample) * 6 + ... outbuf = create_string_buffer(outlen) + ... st = _z.ZMakeAscii(outbuf, outlen, sample, len(sample)) + ... assert st == 0 + ... return outbuf.value + >>> zma("") + '' + >>> zma("j") + '0x6A' + >>> zma("jK") + '0x6A4B' + >>> zma("jK__\0") + '0x6A4B5F5F 0x00' + +Same thing with ZMakeZcode, a compact binary format that is still NUL-terminated... + + >>> sample = "test\0message" + >>> ref = zephyr_tests.py_make_zcode(sample) + >>> from ctypes import create_string_buffer + >>> outlen = len(sample) * 2 + >>> outbuf = create_string_buffer(outlen) + >>> st = _z.ZMakeZcode(outbuf, outlen, sample, len(sample)) + >>> assert st == 0 + >>> assert outbuf.value == ref, "%r != %r" % (outbuf.value, ref) + + +Queued Packet Tests +=================== + +Eventually we'll want tests that install a realm (or several) and +actually send and receive packets against them, so-called "system +tests". In the meantime, a faster and more local test that +synthesizes packets and feeds them through the queuing mechanism will +get us some more coverage. + + >>> from socket import SOCK_DGRAM, socket, ntohs + >>> port = c_ushort(0) + >>> st = _z.ZOpenPort(port) + >>> port = ntohs(port.value) + >>> assert port + >>> sock = socket(AF_INET, SOCK_DGRAM) + >>> assert sock + >>> assert _z.ZPending() == 0 + +TODO: cook up test-specific notices, but for now we've got some lying +around from above... + + >>> zwhole = string_at(zbuf, size=zbuflen) + >>> wrote = sock.sendto(zwhole, ('127.0.0.1', port)) + >>> assert wrote == zbuflen.value, "%s != %s" % (wrote, zbuflen.value) + >>> zcount = _z.ZPending() + >>> assert zcount == 1 + +Coverage: + +Files complete: + ZOpenPort.c + ZClosePort.c + ZExpnRlm.c + ZCmpUID.c + charset.c + ZGetSender.c (needs richer test) + +Pending: + +ZRequestLocations (ZAsyncLocate.c) +ZParseLocations (ZAsyncLocate.c) +ZCompareALDPred (ZAsyncLocate.c) +ZFreeALD (ZAsyncLocate.c) +ZCheckAuthentication (ZCkAuth.c) +ZCheckIfNotice (ZCkIfNot.c) +ZCheckZcodeAuthentication (ZCkZAut.c) +ZCompareUIDPred (ZCmpUIDP.c) +ZCompareMultiUIDPred (ZCmpUIDP.c) +ZFlushLocations (ZFlsLocs.c) +ZFlushSubscriptions (ZFlsSubs.c) +ZFormatAuthenticNotice (ZFmtAuth.c) +ZFormatAuthenticNoticeV5 (ZFmtAuth.c) +ZFormatNoticeList (ZFmtList.c) +ZFormatNotice (ZFmtNotice.c) +ZNewFormatNotice (ZFmtNotice.c) +ZFormatRawNotice (ZFmtRaw.c) +ZFormatRawNoticeList (ZFmtRawLst.c) +ZFormatSmallRawNoticeList (ZFmtSmRLst.c) +ZFormatSmallRawNotice (ZFmtSmRaw.c) +ZNewFormatSmallRawNotice (ZFmtSmRaw.c) +ZFreeNotice (ZFreeNot.c) +ZGetLocations (ZGetLocs.c) +ZGetSubscriptions (ZGetSubs.c) +ZGetWGPort (ZGetWGPort.c) +ZIfNotice (ZIfNotice.c) +ZGetRealm (ZInit.c) +ZQLength (ZInit.c) +ZInitLocationInfo (ZLocations.c) +ZSetLocation (ZLocations.c) +ZUnsetLocation (ZLocations.c) +ZFlushMyLocations (ZLocations.c) +ZParseExposureLevel (ZLocations.c) +Z_SendLocation (ZLocations.c) +ZMakeAscii32 (ZMakeAscii.c) +ZMakeAscii16 (ZMakeAscii.c) +ZMakeZcode32 (ZMakeZcode.c) +ZMakeZcode (ZMakeZcode.c) +ZResetAuthentication (ZMkAuth.c) +ZMakeAuthentication (ZMkAuth.c) +ZMakeZcodeAuthentication (ZMkAuth.c) +ZMakeZcodeRealmAuthentication (ZMkAuth.c) +ZGetCreds (ZMkAuth.c) +ZGetCredsRealm (ZMkAuth.c) +ZLocateUser (ZNewLocU.c) +ZParseNotice (ZParseNot.c) +ZPeekIfNotice (ZPeekIfNot.c) +ZPeekNotice (ZPeekNot.c) +ZPeekPacket (ZPeekPkt.c) +ZPending (ZPending.c) +ZReadAscii (ZReadAscii.c) +ZReadAscii32 (ZReadAscii.c) +ZReadAscii16 (ZReadAscii.c) +ZReadZcode (ZReadZcode.c) +ZReceiveNotice (ZRecvNot.c) +ZReceivePacket (ZRecvPkt.c) +ZRetrieveSubscriptions (ZRetSubs.c) +ZRetrieveDefaultSubscriptions (ZRetSubs.c) +ZSendList (ZSendList.c) +ZSrvSendList (ZSendList.c) +ZSendNotice (ZSendNot.c) +ZSrvSendNotice (ZSendNot.c) +ZSendPacket (ZSendPkt.c) +ZSendRawList (ZSendRLst.c) +ZSrvSendRawList (ZSendRLst.c) +ZSendRawNotice (ZSendRaw.c) +ZSetDestAddr (ZSetDest.c) +ZSetFD (ZSetFD.c) +ZSetServerState (ZSetSrv.c) +ZPunt (ZSubs.c) +ZSubscribeTo (ZSubs.c) +ZSubscribeToSansDefaults (ZSubs.c) +ZUnsubscribeTo (ZSubs.c) +ZCancelSubscriptions (ZSubs.c) +ZGetVariable (ZVariables.c) +ZSetVariable (ZVariables.c) +ZUnsetVariable (ZVariables.c) +Z_WaitForNotice (ZWait4Not.c) +ZhmStat (ZhmStat.c) + +(...continue with Zinternal.c...) diff --git a/new_vers.sh b/new_vers.sh new file mode 100755 index 0000000..af0f403 --- /dev/null +++ b/new_vers.sh @@ -0,0 +1,11 @@ +#!/bin/sh +# +top_srcdir=${1:-`pwd`} + +u=${USER-the_zephyr_builder} +h=`hostname` +t=`date` +v=`sh ${top_srcdir}/get_vers.sh ${top_srcdir}` + +umask 002 +/bin/echo "#define ZEPHYR_VERSION_STRING \"${v} (${t}) ${u}@${h}\"" > h/zephyr_version.h diff --git a/python/zephyr_ctypes.py b/python/zephyr_ctypes.py new file mode 100755 index 0000000..9825ada --- /dev/null +++ b/python/zephyr_ctypes.py @@ -0,0 +1,486 @@ +#!/usr/bin/python + +"""rough bindings for libzephyr""" + +import socket +import struct +import ctypes +import ctypes.util +import time +import sys +from ctypes import c_int, c_uint, c_ushort, c_char, c_ubyte +from ctypes import c_uint16, c_uint32 +from ctypes import POINTER, c_void_p, c_char_p +from ctypes import Structure, Union, sizeof + +__revision__ = "$Id$" +try: + __version__ = "%s/%s" % (__revision__.split()[3], __revision__.split()[2]) +except IndexError: + __version__ = "unknown" + +def print_line_or_lines(results, indent): + """short values on same line, multi-line on later ones...""" + if len(results) == 1: + print results[0] + else: + print + for result in results: + print indent + result + +def ctypes_pprint(cstruct, indent=""): + """pretty print a ctypes Structure or Union""" + + for field_name, field_ctype in cstruct._fields_: + field_value = getattr(cstruct, field_name) + print indent + field_name, + next_indent = indent + " " + pprint_name = "pprint_%s" % field_name + pformat_name = "pformat_%s" % field_name + if hasattr(cstruct, pprint_name): + # no longer used + getattr(cstruct, pprint_name)(next_indent) + elif hasattr(cstruct, pformat_name): + # counted-array and other common cases + print_line_or_lines(getattr(cstruct, pformat_name)(), next_indent) + elif hasattr(field_value, "pformat"): + # common for small compound types + print_line_or_lines(field_value.pformat(), next_indent) + elif hasattr(field_value, "pprint"): + # useful for Union selectors + field_value.pprint(next_indent) + elif hasattr(field_value, "_fields_"): + # generic recursion + print + ctypes_pprint(field_value, next_indent) + else: + # generic simple (or unknown/uninteresting) value + print field_value + +class Enum(c_int): + def pformat(self): + try: + return ["%s(%d)" % (self._values_[self.value], self.value)] + except IndexError: + return ["unknown enum value(%d)" % (self.value)] + +def populate_enum(cls): + """make members for each of the enum values""" + for value, tag in enumerate(cls._values_): + setattr(cls, tag, cls(value)) + +# not really an enum, but we get a richer effect by treating it as one +class Enum_u16(c_uint16): + def pformat(self): + try: + return ["%s(%d)" % (self._values_[self.value], self.value)] + except IndexError: + return ["unknown enum value(%d)" % (self.value)] + +class Enum_u8(c_ubyte): + def pformat(self): + try: + return ["%s(%d)" % (self._values_[self.value], self.value)] + except IndexError: + return ["unknown enum value(%d)" % (self.value)] + +# POSIX socket types... +class in_addr(Structure): + _fields_ = [ + ("s_addr", c_uint32), + ] + def pformat(self): + return [socket.inet_ntoa(struct.pack("= 0: + sa_has_len = True +elif sys.platform.startswith("linux"): + sa_has_len = False +else: + # ?? + sa_has_len = False + +if sa_has_len: + af_base_type = Enum_u8 +else: + af_base_type = Enum_u16 + +class AF_(af_base_type): + _socket_af = dict([(v,n) for n,v in socket.__dict__.items() if n.startswith("AF_")]) + _values_ = [_socket_af.get(k, "unknown address family") for k in range(min(_socket_af), max(_socket_af)+1)] + +populate_enum(AF_) + +def maybe_add_len_field(len_name, other_fields): + if sa_has_len: + return [(len_name, c_ubyte)] + other_fields + else: + return other_fields + +class sockaddr(Structure): + _fields_ = maybe_add_len_field("sa_len", [ + ("sa_family", AF_), + ("sa_data", c_char * 14), + ]) + +class sockaddr_in(Structure): + _fields_ = maybe_add_len_field("sin_len", [ + ("sin_family", AF_), + ("sin_port", c_uint16), + ("sin_addr", in_addr), + # hack from linux - do we actually need it? + ("sin_zero", c_ubyte * (sizeof(sockaddr)-sizeof(c_uint16)-sizeof(c_uint16)-sizeof(in_addr))), + ]) + def pformat_sin_zero(self): + return ["[ignored]"] + +# RFC2553... +class sockaddr_in6(Structure): + _fields_ = maybe_add_len_field("sin6_len", [ + ("sin6_family", AF_), + ("sin6_port", c_uint16), + ("sin6_flowinfo", c_uint32), + ("sin6_addr", in6_addr), + ("sin6_scope_id", c_uint32), + ]) + +# zephyr/zephyr.h +#define Z_MAXOTHERFIELDS 10 /* Max unknown fields in ZNotice_t */ +Z_MAXOTHERFIELDS = 10 +#define ZAUTH (ZMakeAuthentication) +#define ZCAUTH (ZMakeZcodeAuthentication) +#define ZNOAUTH ((Z_AuthProc)0) +ZNOAUTH = 0 + +# typedef enum { +# UNSAFE, UNACKED, ACKED, HMACK, HMCTL, SERVACK, SERVNAK, CLIENTACK, STAT +# } ZNotice_Kind_t; +# extern const char *ZNoticeKinds[9]; + +class ZNotice_Kind_t(Enum): + _values_ = [ + "UNSAFE", "UNACKED", "ACKED", "HMACK", "HMCTL", "SERVACK", "SERVNAK", "CLIENTACK", "STAT", + ] +populate_enum(ZNotice_Kind_t) + +def pformat_timeval(tv_sec, tv_usec): + """format timeval parts as seconds and human-readable time""" + try: + timestr = time.ctime(tv_sec) + except ValueError: + timestr = "invalid unix time" + if tv_usec >= 1000000 or tv_usec < 0: + # invalid usec, still treat as numbers + return ["%dsec, %dusec (bad) (%s)" % (tv_sec, tv_usec, timestr)] + return ["%d.%06dsec (%s)" % (tv_sec, tv_usec, timestr)] + +# struct _ZTimeval { +class _ZTimeval(Structure): + _fields_ = [ +# int tv_sec; + ("tv_sec", c_int), +# int tv_usec; + ("tv_usec", c_int), +# }; + ] + def pformat(self): + return pformat_timeval(self.tv_sec, self.tv_usec) + + +class _ZTimeval_Net(_ZTimeval): + """When _ZTimeval is used in a ZUnique_Id_t, the time parts are + stored in network byte order. Handle this by faking up a different type.""" + def pformat(self): + return pformat_timeval(socket.ntohl(self.tv_sec & 0xffffffff), socket.ntohl(self.tv_usec & 0xffffffff)) + +# typedef struct _ZUnique_Id_t { +class ZUnique_Id_t(Structure): + _fields_ = [ + # struct in_addr zuid_addr; + ("zuid_addr", in_addr), + # struct _ZTimeval tv; + ("tv", _ZTimeval_Net), + # } ZUnique_Id_t; + ] + +# union { +class _U_z_sender_sockaddr(Union): + _fields_ = [ + # struct sockaddr sa; + ("sa", sockaddr), + # struct sockaddr_in ip4; + ("ip4", sockaddr_in), + # struct sockaddr_in6 ip6; + ("ip6", sockaddr_in6), + # } z_sender_sockaddr; + ] + def pprint(self, indent): + print + if self.sa.sa_family.value == socket.AF_INET: + ctypes_pprint(self.ip4, indent + ".ip4:") + elif self.sa.sa_family.value == socket.AF_INET6: + ctypes_pprint(self.ip6, indent + ".ip6:") + else: + ctypes_pprint(self.sa, indent + ".sa:") + +# typedef struct _ZNotice_t { +class ZNotice_t(Structure): + _fields_ = [ + # char *z_packet; + ("z_packet", c_char_p), + # char *z_version; + ("z_version", c_char_p), + # ZNotice_Kind_t z_kind; + ("z_kind", ZNotice_Kind_t), + # ZUnique_Id_t z_uid; + ("z_uid", ZUnique_Id_t), + # union { + # struct sockaddr sa; + # struct sockaddr_in ip4; + # struct sockaddr_in6 ip6; + # } z_sender_sockaddr; + ("z_sender_sockaddr", _U_z_sender_sockaddr), + + # /* heavily deprecated: */ + # #define z_sender_addr z_sender_sockaddr.ip4.sin_addr + # /* probably a bad idea?: */ + # struct _ZTimeval z_time; + ("z_time", _ZTimeval), + # unsigned short z_port; + ("z_port", c_ushort), + # unsigned short z_charset; + ("z_charset", c_ushort), + # int z_auth; + ("z_auth", c_int), + # int z_checked_auth; + # TODO: fake enum, for display + ("z_checked_auth", c_int), + # int z_authent_len; + ("z_authent_len", c_int), + # char *z_ascii_authent; + ("z_ascii_authent", c_char_p), + # char *z_class; + ("z_class", c_char_p), + # char *z_class_inst; + ("z_class_inst", c_char_p), + # char *z_opcode; + ("z_opcode", c_char_p), + # char *z_sender; + ("z_sender", c_char_p), + # char *z_recipient; + ("z_recipient", c_char_p), + # char *z_default_format; + ("z_default_format", c_char_p), + # char *z_multinotice; + ("z_multinotice", c_char_p), + # ZUnique_Id_t z_multiuid; + ("z_multiuid", ZUnique_Id_t), + # ZChecksum_t z_checksum; + ("z_checksum", c_uint), + # char *z_ascii_checksum; + ("z_ascii_checksum", c_char_p), + # int z_num_other_fields; + ("z_num_other_fields", c_int), + # char *z_other_fields[Z_MAXOTHERFIELDS]; + ("z_other_fields", c_char_p * Z_MAXOTHERFIELDS), + # caddr_t z_message; + ("z_message", c_char_p), # not 1980 + # int z_message_len; + ("z_message_len", c_int), + # int z_num_hdr_fields; + ("z_num_hdr_fields", c_int), + # char **z_hdr_fields; + ("z_hdr_fields", POINTER(c_char_p)), + # } ZNotice_t; + ] + def pformat_z_other_fields(self): + return ["%d: %s" % (n, self.z_other_fields[n]) + for n in range(Z_MAXOTHERFIELDS)] + def pformat_z_hdr_fields(self): + if not self.z_hdr_fields: + return ["NULL"] + return ["%d: %s" % (n, self.z_hdr_fields[n]) + for n in range(self.z_num_hdr_fields)] + +class libZephyr(object): + """wrappers for functions in libZephyr""" + testable_funcs = [ + "ZInitialize", + "ZGetFD", + "ZGetRealm", + "ZGetSender", + "Z_FormatRawHeader", + "ZParseNotice", + "ZFormatNotice", + "ZCompareUID", + "ZExpandRealm", + "ZGetCharsetString", + "ZGetCharset", + "ZCharsetToString", + "ZTransliterate", + "ZOpenPort", + "ZClosePort", + "ZMakeAscii", + "ZMakeZcode", + "ZGetDestAddr", + "ZSetFD", + "ZPending", + ] + def __init__(self, library_path=None): + """connect to the library and build the wrappers""" + if not library_path: + library_path = ctypes.util.find_library("zephyr") + self._lib = ctypes.cdll.LoadLibrary(library_path) + + # grab the Zauthtype variable + self.Zauthtype = ctypes.c_int.in_dll(self._lib, 'Zauthtype').value + + # generic bindings? + for funcname in self.testable_funcs: + setattr(self, funcname, getattr(self._lib, funcname)) + + # TODO: fix return types, caller types in a more generic way later + # (perhaps by parsing the headers or code) + # perhaps metaprogramming or decorators... + self.ZGetRealm.restype = ctypes.c_char_p + self.ZGetSender.restype = ctypes.c_char_p + + # Code_t + # Z_FormatRawHeader(ZNotice_t *notice, + # char *buffer, + # int buffer_len, + # int *len, + # char **cstart, + # char **cend) + # This stuffs a notice into a buffer; cstart/cend point into the checksum in buffer + self.Z_FormatRawHeader.argtypes = [ + c_void_p, # *notice + c_char_p, # *buffer + c_int, # buffer_len + POINTER(c_int), # *len + POINTER(c_char_p), # **cstart + POINTER(c_char_p), # **cend + ] + + # Code_t + # ZParseNotice(char *buffer, + # int len, + # ZNotice_t *notice) + self.ZParseNotice.argtypes = [ + c_char_p, # *buffer + c_int, # len + POINTER(ZNotice_t), # *notice + ] + + # Code_t + # ZFormatNotice(register ZNotice_t *notice, + # char **buffer, + # int *ret_len, + # Z_AuthProc cert_routine) + self.ZFormatNotice.argtypes = [ + POINTER(ZNotice_t), # *notice + POINTER(c_char_p), # **buffer + POINTER(c_int), # *ret_len + c_void_p, # cert_routine + ] + + # int + # ZCompareUID(ZUnique_Id_t *uid1, + # ZUnique_Id_t *uid2) + self.ZCompareUID.argtypes = [ + POINTER(ZUnique_Id_t), # *uid1 + POINTER(ZUnique_Id_t), # *uid2 + ] + + # char * + # ZExpandRealm(realm) + # char *realm; # mmm 80's + self.ZExpandRealm.restype = c_char_p + self.ZExpandRealm.argtypes = [ + c_char_p, # realm + ] + + # unsigned short + # ZGetCharset(char *charset) + self.ZGetCharset.restype = c_ushort + self.ZGetCharset.argtypes = [ + c_char_p, # charset + ] + + # const char * + # ZCharsetToString(unsigned short charset) + self.ZCharsetToString.restype = c_char_p + self.ZCharsetToString.argtypes = [ + c_ushort, # charset + ] + + # Code_t + # ZTransliterate(char *in, + # int inlen, + # char *inset, + # char *outset, + # char **out, + # int *outlen) + self.ZTransliterate.argtypes = [ + c_char_p, # in + c_int, # inlnet, + c_char_p, # inset + c_char_p, # outset + POINTER(c_char_p), # out + POINTER(c_int), # outlen + ] + + # Code_t ZOpenPort(u_short *port) + self.ZOpenPort.argtypes = [ + POINTER(c_ushort), # port + ] + + # const char * + # ZGetCharsetString(char *charset) + self.ZGetCharsetString.restype = c_char_p + self.ZGetCharsetString.argtypes = [ + c_char_p, # charset + ] + + # Code_t + # ZMakeAscii(register char *ptr, + # int len, + # unsigned char *field, + # int num) + self.ZMakeAscii.argtypes = [ + c_char_p, # ptr + c_int, # len + c_char_p, # field; c_uchar_p? + c_int, # num + ] + + # Code_t + # ZMakeZcode(register char *ptr, + # int len, + # unsigned char *field, + # int num) + self.ZMakeZcode.argtypes = [ + c_char_p, # ptr + c_int, # len + c_char_p, # field; c_uchar_p? + c_int, # num + ] + + # struct sockaddr_in ZGetDestAddr (void) { + self.ZGetDestAddr.restype = sockaddr_in + + # library-specific setup... + self.ZInitialize() diff --git a/release b/release new file mode 100755 index 0000000..a56c131 --- /dev/null +++ b/release @@ -0,0 +1,38 @@ +#!/bin/sh -ex + +VERSION=$1 +if test -z "$VERSION"; then + echo $0: usage: $0 version + exit 1 +fi + +if test -n "$(git status --porcelain)"; then + echo $0: git status is wordy, you probably want to stash and note your branch + exit 2 +fi +dch -b -v 1:${VERSION}-trunk release $VERSION +dch -r '' +git add debian/changelog +git commit -m "release $VERSION" +TAGNAME=$(echo $VERSION | sed -e 's/~/%7E/') # sigh +git tag $TAGNAME -m "release $VERSION" +git checkout --detach +git clean -fxd +git rm .gitignore +git rm -r debian +git rm release +echo $VERSION > VERSION +sed -e "s/@VERSION@/$VERSION/" README.in > README +git rm README.in +sed -i -e "s/__DEV__/$VERSION/" configure.ac +libtoolize -ic +autoreconf +rm -rf autom4te.cache +git add -A +#git commit -m "release $VERSION" +TREE=$(git write-tree) +COMMIT=$(echo release artifact for $VERSION | git commit-tree $TREE -p HEAD -p remotes/origin/release/artifact) +git tag release/$TAGNAME -m "release $VERSION processed for git archive" $COMMIT +git push origin $TAGNAME release/$TAGNAME $COMMIT:release/artifact +git reset --hard master +git checkout master diff --git a/server/Makefile.in b/server/Makefile.in new file mode 100644 index 0000000..a2434f8 --- /dev/null +++ b/server/Makefile.in @@ -0,0 +1,89 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +top_builddir=.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +editman = sed \ + -e 's|@datadir[@]|${datadir}|g' \ + -e 's|@sysconfdir[@]|${sysconfdir}|g' \ + -e 's|@sbindir[@]|${sbindir}|g' \ + -e 's|@lsbindir[@]|${lsbindir}|g' + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -DSYSCONFDIR=\"${sysconfdir}\" -I${top_srcdir}/h \ + -I${BUILDTOP}/h -I. ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err @ARES_LIBS@ +HESIOD_LIBS=@HESIOD_LIBS@ + +NMOBJS= zsrv_err.o access.o acl_files.o bdump.o class.o client.o common.o \ + dispatch.o kstuff.o global.o server.o subscr.o timer.o uloc.o \ + zstring.o realm.o version.o utf8proc.o + +OBJS= main.o $(NMOBJS) + +TESTOBJS = test_server.o $(NMOBJS) + +all: zephyrd zephyrd.8 test_server + +zephyrd: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} ${HESIOD_LIBS} + +test_server: $(TESTOBJS) + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${TESTOBJS} ${LIBS} ${HESIOD_LIBS} + +zsrv_err.h: zsrv_err.c +zsrv_err.c: zsrv_err.et + compile_et ${srcdir}/zsrv_err.et + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +zephyrd.8: ${srcdir}/zephyrd.8.in Makefile + ${editman} ${srcdir}/$@.in > $@.tmp + mv $@.tmp $@ + +check: test_server + ./test_server + +# No dependency on zephyrd, to avoid rebuilding version.o. +install: zephyrd.8 zephyrd + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zephyrd \ + ${DESTDIR}${sbindir} + ${INSTALL} -m 644 zephyrd.8 ${DESTDIR}${mandir}/man8 + ${INSTALL} -m 644 ${srcdir}/default.subscriptions \ + ${DESTDIR}${sysconfdir}/zephyr + +clean: + ${LIBTOOL} --mode=clean rm -f zephyrd test_server + rm -f ${OBJS} zsrv_err.[ch] + rm -f zephyrd.8 + +${OBJS} ${TESTOBJS}: zserver.h zsrv_err.h timer.h zsrv_conf.h zstring.h access.h acl.h +${OBJS} ${TESTOBJS}: ${top_srcdir}/h/internal.h ${top_srcdir}/h/sysdep.h +${OBJS} ${TESTOBJS}: ${BUILDTOP}/h/config.h ${BUILDTOP}/h/zephyr/zephyr.h +${OBJS} ${TESTOBJS}: ${BUILDTOP}/h/zephyr/zephyr_err.h +version.o: ${BUILDTOP}/h/zephyr_version.h + +.PHONY: all check install clean + diff --git a/server/access.c b/server/access.c new file mode 100644 index 0000000..0f38be5 --- /dev/null +++ b/server/access.c @@ -0,0 +1,251 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for dealing with acl's. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" + +#if !defined (lint) && !defined (SABER) +static const char rcsid_access_c[] = + "$Id$"; +#endif + +/* + * + * External routines: + * + * int access_check(sender, who, acl, accesstype) + * char *sender; + * struct sockaddr_in *who; + * Acl *acl; + * Access accesstype; + * + * int opstaff_check(sender) + * char *sender; + * + * void access_init(); + * + * void access_reinit(); + */ + +/* + * Each restricted class has four ACL's associated with it, + * governing subscriptions, transmission, and instance restrictions. + * This module provides the 'glue' between the standard Athena ACL + * routines and the support needed by the Zephyr server. + */ + +/* + * Our private types for the acl_types field in the Acl structure. + * -TYT 8/14/90 + */ +#define ACL_XMT 1 +#define ACL_SUB 2 +#define ACL_IWS 4 +#define ACL_IUI 8 + +static void check_acl(Acl *acl); +static void check_acl_type(Acl *acl, Access accesstype, int typeflag); +static void access_setup(int first); + +/* + * check access. return 1 if ok, 0 if not ok. + */ + +int +access_check(char *sender, + struct sockaddr_in *who, + Acl *acl, + Access accesstype) +{ + char buf[1024]; /* holds the real acl name */ + char *prefix; + int flag; + int retval; + + switch (accesstype) { + case TRANSMIT: + prefix = "xmt"; + flag = ACL_XMT; + break; + case SUBSCRIBE: + prefix = "sub"; + flag = ACL_SUB; + break; + case INSTWILD: + prefix = "iws"; + flag = ACL_IWS; + break; + case INSTUID: + prefix = "iui"; + flag = ACL_IUI; + break; + default: + syslog(LOG_ERR, "unknown access type %d", (int) accesstype); + return 0; + } + if (!(acl->acl_types & flag)) /* no acl ==> no restriction */ + return 1; + snprintf(buf, sizeof buf, "%s/%s-%s.acl", acl_dir, prefix, acl->acl_filename); + /* + * If we can't load it (because it probably doesn't exist), + * we deny access. + */ + retval = acl_load(buf); + if (retval < 0) { + syslog(LOG_DEBUG, "Error in acl_load of %s for %s", + buf, sender ? sender : "unauth client"); + return 0; + } + return acl_check(buf, sender, who); +} + +int +opstaff_check(char *sender) +{ + char buf[1024]; /* holds the real acl name */ + int retval; + + snprintf(buf, sizeof buf, "%s/opstaff.acl", acl_dir); + /* + * If we can't load it (because it probably doesn't exist), + * we deny access. + */ + retval = acl_load(buf); + if (retval < 0) { + syslog(LOG_DEBUG, "Error in acl_load of %s for %s", + buf, sender ? sender : "unauth client"); + return 0; + } + return acl_check(buf, sender, NULL); +} + +static void +check_acl(Acl *acl) +{ + acl->acl_types = 0; + check_acl_type(acl, TRANSMIT, ACL_XMT); + check_acl_type(acl, SUBSCRIBE, ACL_SUB); + check_acl_type(acl, INSTWILD, ACL_IWS); + check_acl_type(acl, INSTUID, ACL_IUI); +} + +static void +check_acl_type(Acl *acl, + Access accesstype, + int typeflag) +{ + char buf[1024]; /* holds the real acl name */ + char *prefix; + + switch (accesstype) { + case TRANSMIT: + prefix = "xmt"; + break; + case SUBSCRIBE: + prefix = "sub"; + break; + case INSTWILD: + prefix = "iws"; + break; + case INSTUID: + prefix = "iui"; + break; + default: + syslog(LOG_ERR, "unknown access type %d", (int) accesstype); + return; + } + snprintf(buf, sizeof buf, "%s/%s-%s.acl", acl_dir, prefix, acl->acl_filename); + if (!access(buf, F_OK)) + acl->acl_types |= typeflag; +} + + +/* + * Re-init code written by TYT, 8/14/90. + * + * General plan of action; we reread the registry list, and add any + * new restricted classes. If any restricted classes disappear (this + * should be rarely) the Acl structure is not deallocated; rather, + * the acl_types field will be left at zero, since there will be no + * acl files for the (non-)restricted class. + */ +static void +access_setup(int first) +{ + char buf[1024]; + char class_name[512]; /* assume class names <= 511 bytes */ + FILE *registry; + Acl *acl; + int len; + char *colon_idx; + Code_t retval = 0; + + snprintf(buf, sizeof buf, "%s/%s", acl_dir, ZEPHYR_CLASS_REGISTRY); + registry = fopen(buf, "r"); + if (!registry) { + syslog(LOG_ERR, "no registry available, all classes are free"); + return; + } + while (fgets(class_name, 512, registry)) { + colon_idx = strchr(class_name, ':'); + if (colon_idx != NULL) + *colon_idx = '\0'; + else if ((len = strlen(class_name)) != 0) + class_name[len - 1] = '\0'; + acl = 0; + if (!first) { + String *z; + + z = make_string(class_name,1); + acl = class_get_acl(z); + free_string(z); + } + if (!acl) { + acl = (Acl *) malloc(sizeof(Acl)); + if (!acl) { + syslog(LOG_ERR, "no mem acl alloc"); + abort(); + } + acl->acl_filename = strsave(class_name); + check_acl(acl); + + if (!first) { + /* Try to restrict already existing class */ + retval = class_restrict(class_name, acl); + if (retval == ZSRV_NOCLASS) + retval = class_setup_restricted(class_name, acl); + } else { + retval = class_setup_restricted(class_name, acl); + } + } + if (retval) { + syslog(LOG_ERR, "can't restrict %s: %s", + class_name, error_message(retval)); + continue; + } + zdbug((LOG_DEBUG, "restricted %s", class_name)); + } + fclose(registry); +} + +void +access_init(void) +{ + access_setup(1); +} + +void +access_reinit(void) +{ + acl_cache_reset(); + access_setup(0); +} diff --git a/server/access.h b/server/access.h new file mode 100644 index 0000000..910770f --- /dev/null +++ b/server/access.h @@ -0,0 +1,38 @@ +/* + * This file is part of the Project Athena Zephyr Notification System. + * + * It contains declarations for use in the server, relating to access + * control. + * + * Created by Ken Raeburn. + * + * $Id$ + * + * Copyright (c) 1990 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#include "acl.h" +#include "zstring.h" + +typedef enum _Access { + TRANSMIT, /* use transmission acl */ + SUBSCRIBE, /* use subscription acl */ + INSTWILD, /* use instance wildcard acl */ + INSTUID /* use instance UID identity acl */ +} Access; + +typedef struct _Acl { + char *acl_filename; + int acl_types; /* Internal; access fields present. */ +} Acl; + +/* found in access.c */ +void access_init(void); +void access_reinit(void); + +/* found in acl_files.c */ +int acl_load(char *); diff --git a/server/acl.h b/server/acl.h new file mode 100644 index 0000000..84c5a70 --- /dev/null +++ b/server/acl.h @@ -0,0 +1,25 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains definitions for the ACL library + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#ifndef __ACL__ +#define __ACL__ + +int acl_add(char *, char *); +int acl_check(char *, char *, struct sockaddr_in *); +int acl_delete(char *, char *); +int acl_initialize(char *, int); +void acl_cache_reset(void); + +#endif /* __ACL__ */ + diff --git a/server/acl_files.c b/server/acl_files.c new file mode 100644 index 0000000..9f67fd7 --- /dev/null +++ b/server/acl_files.c @@ -0,0 +1,375 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for maintaining Access Control Lists. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +/* Define this if you really want the ACL-writing code included. */ + +/* + * Stolen from lib/acl_files.c because acl_load needs to be externally + * declared and not statically declared. + */ + +#include +#include "zserver.h" +#include + +#ifndef SABER +#ifndef lint +static const char rcsid_acl_files_c[] = "$Id$"; +#endif /* lint */ +#endif /* SABER */ + +/*** Routines for manipulating access control list files ***/ + +#define REALM_SEP '@' +#define ESCAPE '\\' + +#define CACHED_ACLS 256 /* How many acls to cache */ +#define ACL_LEN 256 /* Twice a reasonable acl length */ + +/* Eliminate all whitespace character in buf */ +/* Modifies its argument */ +static void +nuke_whitespace(char *buf) +{ + char *pin, *pout; + + for (pin = pout = buf; *pin != '\0'; pin++) + if (!isspace(*pin)) *pout++ = *pin; + *pout = '\0'; /* Terminate the string */ +} + +struct host_ace { + struct host_ace *next; + unsigned long addr, mask; +}; + +static int +add_host(struct host_ace **list, + char *buf) +{ + struct host_ace *e; + struct in_addr addr; + unsigned long mask = 0; + long i; + char *m, *x; + + m = strchr(buf, '/'); + if (m) { + *(m++) = 0; + if (!*m) + return EINVAL; + i = strtol(m, &x, 10); + if (*x || i < 0 || i > 32) + return EINVAL; + while (i--) + mask = (mask >> 1) | 0x80000000; + } else { + mask = 0xffffffff; + } + + if (!inet_aton(buf, &addr)) + return EINVAL; + + e = (struct host_ace *)malloc(sizeof(struct host_ace)); + if (e == NULL) + return errno; + memset(e, 0, sizeof(struct host_ace)); + e->addr = addr.s_addr; + e->mask = htonl(mask); + e->next = *list; + *list = e; + + return 0; +} + +static void +destroy_hosts(struct host_ace **list) +{ + struct host_ace *e; + + while ((e = *list)) { + *list = e->next; + free(e); + } +} + +static char * +split_name(char *princ) { + int i; + int len = strlen(princ); + + for (i = 0; i < len && princ[i] != REALM_SEP; i++) + if (princ[i] == ESCAPE && (i + 1) < len) + i++; + if (i != len) { /* yay found an @ */ + princ[i] = 0; + return &princ[i + 1]; + } + return &princ[i]; /* failure, just return a pointer empty string */ +} + +struct user_ace { + struct user_ace *next; + char *princ; + char *realm; +}; + +static int +add_user(struct user_ace **list, char *princ) { + struct user_ace *e; + char *realm = split_name(princ); + + e = (struct user_ace *)malloc(sizeof(struct user_ace)); + if (e == NULL) + return errno; + memset(e, 0, sizeof(struct user_ace)); + + if (!strcmp(princ, "*.*")) /* #ifdef KRB4_COMPAT */ + e->princ = strdup("*"); + else /* #endif */ + e->princ = strdup(princ); + if (e->princ == NULL) { + free(e); + return errno; + } + + e->realm = strdup(realm); + if (e->realm == NULL) { + free(e->princ); + free(e); + return errno; + } + e->next = *list; + *list = e; + + return 0; +} + +static void +destroy_user(struct user_ace **list) { + struct user_ace *e; + while ((e = *list)) { + *list = e->next; + free(e->princ); + free(e->realm); + free(e); + } +} + +static int +check_user(struct user_ace *list, char *princ, char *realm) { + struct user_ace *e; + + e = list; + while (e) { + if (fnmatch(e->princ, princ, 0) == 0 + && fnmatch(e->realm, realm, 0) == 0) + return 1; + e = e->next; + } + + return 0; +} + +struct acl { + String *filename; /* Name of acl file */ + int loaded; + struct user_ace *acl; /* Positive acl entries */ + struct user_ace *negacl; /* Negative acl entries */ + struct host_ace *hosts; /* Positive host entries */ + struct host_ace *neghosts; /* Negative host entries */ +}; + +static struct acl acl_cache[CACHED_ACLS]; + +static int acl_cache_count = 0; +static int acl_cache_next = 0; + +/* wipe an entry in the acl cache */ +static void +destroy_acl(int i) { + if (acl_cache[i].filename) + free_string(acl_cache[i].filename); + if (acl_cache[i].acl) + destroy_user(&acl_cache[i].acl); + if (acl_cache[i].negacl) + destroy_user(&acl_cache[i].negacl); + if (acl_cache[i].hosts) + destroy_hosts(&acl_cache[i].hosts); + if (acl_cache[i].neghosts) + destroy_hosts(&acl_cache[i].neghosts); + acl_cache[i].filename = NULL; + acl_cache[i].acl = (struct user_ace *) 0; + acl_cache[i].negacl = (struct user_ace *) 0; + acl_cache[i].hosts = (struct host_ace *) 0; + acl_cache[i].neghosts = (struct host_ace *) 0; + acl_cache[i].loaded = 0; +} + +/* Returns < 0 if unsuccessful in loading acl */ +/* Returns index into acl_cache otherwise */ +/* Note that if acl is already loaded, this is just a lookup */ +int acl_load(char *name) +{ + int i; + FILE *f; + char buf[BUFSIZ]; + int ret = 0; + String *interned_name; + + syslog(LOG_DEBUG, "acl_load(%s)", name); + /* See if it's there already */ + interned_name = make_string(name, 0); + for (i = 0; i < acl_cache_count; i++) { + if (acl_cache[i].filename == interned_name) + goto got_it; + } + + /* It isn't, load it in */ + /* maybe there's still room */ + if (acl_cache_count < CACHED_ACLS) { + i = acl_cache_count++; + } else { + /* No room, clean one out */ + i = acl_cache_next; + acl_cache_next = (acl_cache_next + 1) % CACHED_ACLS; + destroy_acl(i); + } + + /* Set up the acl */ + acl_cache[i].filename = interned_name; + /* Force reload */ + acl_cache[i].loaded = 0; + + got_it: + /* + * See if we need to reload the ACL + */ + if (!acl_cache[i].loaded) { + syslog(LOG_DEBUG, "acl_load(%s) actually loading", name); + /* Gotta reload */ + if ((f = fopen(name, "r")) == NULL) { + syslog(LOG_ERR, "Error loading acl file %s: %m", name); + return -errno; + } + if (acl_cache[i].acl) + destroy_user(&acl_cache[i].acl); + if (acl_cache[i].negacl) + destroy_user(&acl_cache[i].negacl); + acl_cache[i].acl = (struct user_ace *)0; + acl_cache[i].negacl = (struct user_ace *)0; + while(fgets(buf, sizeof(buf), f) != NULL && ret == 0) { + nuke_whitespace(buf); + if (!buf[0]) + continue; + if (buf[0] == '!' && buf[1] == '@') + ret = add_host(&acl_cache[i].neghosts, buf + 2); + else if (buf[0] == '@') + ret = add_host(&acl_cache[i].hosts, buf + 1); + else if (buf[0] == '!') + ret = add_user(&acl_cache[i].negacl, buf + 1); + else + ret = add_user(&acl_cache[i].acl, buf); + } + fclose(f); + if (ret) { + destroy_acl(i); + return -ret; + } + acl_cache[i].loaded = 1; + } + return i; +} + +/* + * This destroys all cached ACL's so that new ones will be loaded in + * the next time they are requested. + */ +void +acl_cache_reset(void) +{ + int i; + + syslog(LOG_DEBUG, "acl_cache_reset()"); + for (i = 0; i < acl_cache_count; i++) + destroy_acl(i); + acl_cache_count = 0; + acl_cache_next = 0; +} + +/* Returns nonzero if it can be determined that acl contains principal */ +/* Principal is not canonicalized, and no wildcarding is done */ +/* If neg is nonzero, we look for negative entries */ +static int +acl_match(char *acl, char *princ, char *realm, int neg) +{ + int idx; + + if ((idx = acl_load(acl)) < 0) + return 0; + if (neg) + return check_user(acl_cache[idx].negacl, princ, realm); + else + return check_user(acl_cache[idx].acl, princ, realm); +} + +/* Returns nonzero if it can be determined that acl contains who */ +/* If neg is nonzero, we look for negative entries */ +static int +acl_host_match(char *acl, + unsigned long who, + int neg) +{ + int idx; + struct host_ace *e; + + if ((idx = acl_load(acl)) < 0) + return 0; + e = neg ? acl_cache[idx].neghosts : acl_cache[idx].hosts; + while (e) { + if ((e->addr & e->mask) == (who & e->mask)) + return 1; + e = e->next; + } + return 0; +} + +/* Returns nonzero if it can be determined that acl contains principal */ +/* Recognizes wildcards in acl. */ +/* Also checks for IP address entries and applies negative ACL's */ +int +acl_check(char *acl, char *princ, struct sockaddr_in *who) +{ + char *realm; + char *name; + int result = 0; + + if (princ) { + name = strdup(princ); + realm = split_name(name); + + if (acl_match(acl, name, realm, 1)) + return 0; + if (acl_match(acl, name, realm, 0)) + result = 1; + free(name); + } + + if (who) { + if (acl_host_match(acl, who->sin_addr.s_addr, 1)) + return 0; + if (acl_host_match(acl, who->sin_addr.s_addr, 0)) + result = 1; + } + + return result; +} diff --git a/server/bdump.c b/server/bdump.c new file mode 100644 index 0000000..344adcf --- /dev/null +++ b/server/bdump.c @@ -0,0 +1,1702 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for dumping server state between servers. + * + * Created by: John T. Kohl + * + * $Source$ + * $Id$ + * $Author$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include + +#ifndef lint +static const char rcsid_bdump_c[] = "$Id$"; +#endif /* lint */ + +#ifndef MIN +#define MIN(x, y) ((x) < (y) ? (x) : (y)) +#endif + +/* + * External functions are: + * + * void bdump_offer(who) + * strut sockaddr_in *who; + * + * void bdump_send() + * + * void bdump_get(notice, auth, who, server) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * Server *server; + * + * Code_t bdump_send_list_tcp(kind, port, class, inst, opcode, + * sender, recip, lyst, num) + * ZNotice_Kind_t kind; + * u_short port; + * char *class, *inst, *opcode, *sender, *recip; + * char *lyst[]; + * int num; + */ + +static void close_bdump(void* arg); +static Code_t bdump_send_loop(Server *server); +static Code_t bdump_recv_loop(Server *server); +static void bdump_get_v12(ZNotice_t *, int, struct sockaddr_in *, + Server *); +static Code_t get_packet(char **packet, int *len, int *retlen); +static Code_t extract_sin(ZNotice_t *notice, struct sockaddr_in *target); +static Code_t send_done(void); +static Code_t send_list(ZNotice_Kind_t kind, int port, char *class_name, + char *inst, char *opcode, char *sender, + char *recip, char **lyst, int num); +static Code_t send_normal_tcp(ZNotice_Kind_t kind, int port, + char *class_name, + char *inst, char *opcode, char *sender, + char *recip, char *message, int len); +static int net_read(FILE *f, char *buf, int len); +static int net_write(FILE *f, char *buf, int len); +static int setup_file_pointers(void); +static void shutdown_file_pointers(void); +static void cleanup(Server *server); +static Code_t transmit_tcp(char *pack, int packlen); + +#ifdef HAVE_KRB5 +static int des_service_decrypt(unsigned char *in, unsigned char *out); +#endif +#ifdef HAVE_KRB5 +static long ticket5_time; +#define TKT5LIFETIME 8*60*60 +#define tkt5_lifetime(val) (val) +#endif + +#ifdef HAVE_KRB4 +static long ticket_time; + +#define TKTLIFETIME 120 +#define tkt_lifetime(val) ((long) val * 5L * 60L) + +#endif /* HAVE_KRB4 */ + +#if defined(HAVE_KRB4) +extern C_Block serv_key; +extern Sched serv_ksched; +#endif +#if defined(HAVE_KRB5) && !defined(HAVE_KRB4) +krb5_keyblock *server_key; +#endif + +static Timer *bdump_timer; +static int live_socket = -1; +static FILE *input, *output; +static struct sockaddr_in bdump_sin; +#ifdef HAVE_KRB5 +static krb5_auth_context bdump_ac; +#endif +static Z_AuthProc bdump_auth_proc; + +int bdumping; +int bdump_concurrent; + +/* + * Functions for performing a brain dump between servers. + */ + +/* + * offer the brain dump to another server + */ + +void +bdump_offer(struct sockaddr_in *who) +{ + Code_t retval; + char buf[512], *addr, *lyst[2]; +#if !defined(HAVE_KRB4) && !defined(HAVE_KRB5) + int bdump_port = IPPORT_RESERVED - 1; +#endif /* !HAVE_KRB4 */ + + zdbug((LOG_DEBUG, "bdump_offer")); + +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + /* + * when using kerberos server-server authentication, we can + * use any random local address + */ + bdump_socket = socket(AF_INET, SOCK_STREAM, 0); + if (bdump_socket < 0) { + syslog(LOG_ERR,"bdump_offer: socket: %m"); + bdump_socket = -1; + return; + } + memset(&bdump_sin, 0, sizeof(bdump_sin)); + /* a port field of 0 makes the UNIX + * kernel choose an appropriate port/address pair */ + + bdump_sin.sin_port = 0; + bdump_sin.sin_addr = my_addr; + bdump_sin.sin_family = AF_INET; + retval = bind(bdump_socket, (struct sockaddr *) &bdump_sin, + sizeof(bdump_sin)); + if (retval < 0) { + syslog(LOG_ERR, "bdump_offer: bind: %m"); + close(bdump_socket); + bdump_socket = -1; + return; + } + if (!bdump_sin.sin_port) { + unsigned int len = sizeof(bdump_sin); + + if (getsockname(bdump_socket, + (struct sockaddr *) &bdump_sin, &len) < 0) { + syslog(LOG_ERR, "bdump_offer: getsockname: %m"); + close(bdump_socket); + bdump_socket = -1; + return; + } + } +#else /* !HAVE_KRB4 */ + /* + * when not using HAVE_KRB4, we can't use any old port, we use + * Internet reserved ports instead (rresvport) + */ + bdump_socket = rresvport(&bdump_port); + if (bdump_socket < 0) { + syslog(LOG_ERR,"bdump_offer: socket: %m"); + bdump_socket = -1; + return; + } + memset(&bdump_sin, 0, sizeof(bdump_sin)); + bdump_sin.sin_port = htons((unsigned short) bdump_port); + bdump_sin.sin_addr = my_addr; + bdump_sin.sin_family = AF_INET; +#endif /* HAVE_KRB4 */ + + listen(bdump_socket, 1); + + bdump_timer = timer_set_rel(20L, close_bdump, NULL); + FD_SET(bdump_socket, &interesting); + nfds = max(bdump_socket, srv_socket) + 1; + + addr = inet_ntoa(bdump_sin.sin_addr); + sprintf(buf, "%d", ntohs(bdump_sin.sin_port)); + lyst[0] = addr; + lyst[1] = buf; + + retval = ZSetDestAddr(who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_offer: ZSetDestAddr: %s", + error_message(retval)); + return; + } + + /* myname is the hostname */ + /* the class instance is the version number, here it is */ + /* bdump_version, which is set in global.c */ + send_list(ACKED, srv_addr.sin_port, ZEPHYR_ADMIN_CLASS, bdump_version, + ADMIN_BDUMP, myname, "", lyst, 2); + + zdbug((LOG_DEBUG,"bdump_offer: address is %s/%d\n", + inet_ntoa(bdump_sin.sin_addr), + ntohs(bdump_sin.sin_port))); + return; +} + +/* + * Accept a connection, and send the brain dump to the other server + */ + +void +bdump_send(void) +{ + struct sockaddr_in from; + Server *server; + Code_t retval; + unsigned int fromlen = sizeof(from); + int on = 1; +#ifdef _POSIX_VERSION + struct sigaction action; +#endif +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + char *data = NULL; + int len = 0; + int proto = 0; +#endif +#ifdef HAVE_KRB4 + KTEXT_ST ticket; + AUTH_DAT kdata; + /* may be moved into kstuff.c */ + char instance [INST_SZ]; +#endif +#ifdef HAVE_KRB5 + /* may be moved into kstuff.c */ + krb5_principal principal; + krb5_data k5data; + krb5_keytab kt; +#endif +#if !defined(HAVE_KRB4) && !defined(HAVE_KRB5) + unsigned short fromport; +#endif /* HAVE_KRB4 */ + + zdbug((LOG_DEBUG, "bdump_send")); + + /* accept the connection, and send the brain dump */ + live_socket = accept(bdump_socket, (struct sockaddr *) &from, &fromlen); + if (live_socket < 0) { + syslog(LOG_ERR,"bdump_send: accept: %m"); + return; + } + if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *) &on, + sizeof(on)) < 0) + syslog(LOG_WARNING, "bdump_send: setsockopt (SO_KEEPALIVE): %m"); + +#if !defined(HAVE_KRB4) && !defined(HAVE_KRB5) + fromport = ntohs(from.sin_port); +#endif + +#ifdef _POSIX_VERSION + sigemptyset(&action.sa_mask); + action.sa_flags = 0; + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); + +#else + signal(SIGPIPE, SIG_IGN); /* so we can detect failures */ +#endif + + from.sin_port = srv_addr.sin_port; /* we don't care what port + * it came from, and we need to + * fake out server_which_server() */ + server = server_which_server(&from); + if (!server) { + syslog(LOG_ERR, "bdump_send: unknown server?"); + server = limbo_server; + } + + zdbug((LOG_INFO, "bdump_send: connection from %s/%d", + inet_ntoa(from.sin_addr), ntohs(from.sin_port))); + + bdumping = 1; + server->dumping = 1; + bdump_auth_proc = ZNOAUTH; + + if (bdump_socket >= 0) { + /* shut down the listening socket and the timer. */ + FD_CLR(bdump_socket, &interesting); + close(bdump_socket); + nfds = srv_socket + 1; + bdump_socket = -1; + timer_reset(bdump_timer); + } + + /* Now begin the brain dump. */ +#if defined(HAVE_KRB5) || defined(HAVE_KRB4) + retval = ReadKerberosData(live_socket, &len, &data, &proto); + + if (retval != 0) { + syslog(LOG_ERR, "bdump_send: ReadKerberosData: %s", + error_message(retval)); + cleanup(server); + return; + } + + syslog(LOG_DEBUG, "bdump_send: got %d bytes of authenticator for protocol %d", len, proto); + + if (get_tgt()) { + syslog(LOG_ERR, "bdump_send: get_tgt failed"); + cleanup(server); + return; + } + + switch(proto) { +#ifdef HAVE_KRB5 + case 5: + /* "server" side */ + retval = krb5_build_principal(Z_krb5_ctx, &principal, + strlen(ZGetRealm()), + ZGetRealm(), + SERVER_KRB5_SERVICE, SERVER_INSTANCE, + NULL); + if (retval) { + syslog(LOG_ERR, "bdump_send: krb5_build_principal: %s", + error_message(retval)); + cleanup(server); + return; + } + + + retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac); + if (retval) { + syslog(LOG_ERR, "bdump_send: krb5_auth_con_init: %s", + error_message(retval)); + cleanup(server); + return; + } + + retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, + KRB5_AUTH_CONTEXT_DO_SEQUENCE); + if (retval) { + syslog(LOG_ERR, "bdump_send: krb5_auth_con_setflags: %s", + error_message(retval)); + cleanup(server); + return; + } + + retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket, + KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR); + if (retval) { + syslog(LOG_ERR, "bdump_send: krb5_auth_con_genaddrs: %s", error_message(retval)); + cleanup(server); + return; + } + + /* Get the "client" krb_ap_req */ + + memset((char *)&k5data, 0, sizeof(krb5_data)); + k5data.length = len; + k5data.data = data; + + /* resolve keytab */ + retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt); + if (retval) { + syslog(LOG_ERR, "bdump_send: cannot resolve keytab: %s", + error_message(retval)); + krb5_kt_close(Z_krb5_ctx, kt); + cleanup(server); + return; + } + + retval = krb5_rd_req(Z_krb5_ctx, &bdump_ac, &k5data, principal, kt, NULL, NULL); + krb5_free_principal(Z_krb5_ctx, principal); + krb5_kt_close(Z_krb5_ctx, kt); + free(k5data.data); + memset((char *)&k5data, 0, sizeof(krb5_data)); + if (retval) { + syslog(LOG_ERR, "bdump_send: mutual authentication failed: %s", + error_message(retval)); + cleanup(server); + return; + } + + /* Now send back our auth packet */ + + retval = krb5_mk_rep(Z_krb5_ctx, bdump_ac, &k5data); + if (retval) { + syslog(LOG_ERR, "bdump_send: krb5_mk_rep: %s", error_message(retval)); + cleanup(server); + return; + } + retval = SendKrb5Data(live_socket, &k5data); + if (retval) { + syslog(LOG_ERR, "bdump_send: cannot send authenticator: %s", + error_message(retval)); + krb5_free_data_contents(Z_krb5_ctx, &k5data); + cleanup(server); + return; + } + krb5_free_data_contents(Z_krb5_ctx, &k5data); + break; +#endif /* HAVE_KRB5 */ +#ifdef HAVE_KRB4 + case 4: + bdump_auth_proc = Z_FormatAuthHeaderWithASCIIAddress; + /* here to krb_rd_req from GetKerberosData candidate for refactoring + back into kstuff.c */ + (void) strcpy(instance, "*"); /* let Kerberos fill it in */ + + ticket.length = len; + memcpy(&ticket.dat, data, MIN(len, (int)sizeof(ticket.dat))); + retval = krb_rd_req(&ticket, SERVER_SERVICE, instance, + from.sin_addr.s_addr, &kdata, srvtab_file); + /* + retval = GetKerberosData(live_socket, from.sin_addr, &kdata, + SERVER_SERVICE, srvtab_file); + */ + if (retval != KSUCCESS) { + syslog(LOG_ERR, "bdump_send: getkdata: %s", + error_message(retval)); + cleanup(server); + return; + } + if (strcmp(kdata.pname, SERVER_SERVICE) || + strcmp(kdata.pinst, SERVER_INSTANCE) || + strcmp(kdata.prealm, ZGetRealm())) { + syslog(LOG_ERR, "bdump_send: peer not zephyr: %s.%s@%s", + kdata.pname, kdata.pinst, kdata.prealm); + cleanup(server); + return; + } + /* authenticate back */ + retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE, + SERVER_INSTANCE); + if (retval != 0) { + syslog(LOG_ERR,"bdump_send: SendKerberosData: %s", + error_message (retval)); + cleanup(server); + return; + } + break; +#endif /* HAVE_KRB4 */ + } +#else /* HAVE_KRB4 || HAVE_KRB5 */ + if (fromport > IPPORT_RESERVED || fromport < IPPORT_RESERVED / 2) { + syslog(LOG_ERR, "bdump_send: bad port from peer: %d", fromport); + cleanup(server); + return; + } +#endif /* HAVE_KRB4 || HAVE_KRB5 */ + retval = setup_file_pointers(); + if (retval != 0) { + syslog (LOG_WARNING, "bdump_send: can't set up file pointers: %s", + error_message(retval)); + cleanup(server); + return; + } + retval = bdump_send_loop(server); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_send: bdump_send_loop failed: %s", + error_message(retval)); + cleanup(server); + return; + } + retval = bdump_recv_loop(server); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_send: bdump_recv_loop failed: %s", + error_message(retval)); + cleanup(server); + return; + } + + zdbug((LOG_DEBUG, "bdump_send: finished")); + + if (server != limbo_server) { + /* set this guy to be up, and schedule a hello */ + server->state = SERV_UP; + timer_reset(server->timer); + server->timer = timer_set_rel(0L, server_timo, server); + } + + shutdown_file_pointers(); + +#ifdef _POSIX_VERSION + action.sa_handler = SIG_DFL; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_DFL); +#endif + bdumping = 0; + server->dumping = 0; + /* Now that we are finished dumping, send all the queued packets */ + server_send_queue(server); + return; +} + +/*ARGSUSED*/ +static void +bdump_get_v12 (ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + struct sockaddr_in from; + Code_t retval; + int on = 1; +#ifdef _POSIX_VERSION + struct sigaction action; +#endif +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) +#ifdef HAVE_KRB5 + krb5_creds creds; + krb5_creds *credsp; + krb5_principal principal; + krb5_data data; + krb5_ap_rep_enc_part *rep; +#endif +#ifdef HAVE_KRB4 + KTEXT_ST ticket; + AUTH_DAT kdata; +#endif +#else /* !HAVE_KRB4 && !HAVE_KRB5 */ + int reserved_port = IPPORT_RESERVED - 1; +#endif /* !HAVE_KRB4 && !HAVE_KRB5 */ + + bdumping = 1; + server->dumping = 1; + bdump_auth_proc = ZNOAUTH; + +#ifdef _POSIX_VERSION + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_IGN); /* so we can detect problems */ +#endif /* _POSIX_VRESION */ + + if (bdump_socket >= 0) { + /* We cannot go get a brain dump when someone may + potentially be connecting to us (if that other + server is the server to whom we are connecting, + we will deadlock. so we shut down the listening + socket and the timer. */ + FD_CLR(bdump_socket, &interesting); + close(bdump_socket); + nfds = srv_socket+1; + bdump_socket = -1; + timer_reset(bdump_timer); + } + + retval = extract_sin(notice, &from); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_get: sin: %s", error_message(retval)); +#ifdef _POSIX_VERSION + action.sa_handler = SIG_DFL; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_DFL); +#endif + bdumping = 0; + server->dumping = 0; + return; + } +#if !defined(HAVE_KRB4) && !defined(HAVE_KRB5) + if (ntohs(from.sin_port) > IPPORT_RESERVED || + ntohs(from.sin_port) < IPPORT_RESERVED / 2) { + syslog(LOG_ERR, "bdump_get: port not reserved: %d", + ntohs(from.sin_port)); + cleanup(server); + return; + } + live_socket = rresvport(&reserved_port); +#else /* !HAVE_KRB4 && !HAVE_KRB5 */ + live_socket = socket(AF_INET, SOCK_STREAM, 0); +#endif /* !HAVE_KRB4 && !HAVE_KRB5 */ + if (live_socket < 0) { + syslog(LOG_ERR, "bdump_get: socket: %m"); + cleanup(server); + return; + } + if (connect(live_socket, (struct sockaddr *) &from, sizeof(from))) { + syslog(LOG_ERR, "bdump_get: connect: %m"); + cleanup(server); + return; + } + if (setsockopt(live_socket, SOL_SOCKET, SO_KEEPALIVE, (char *)&on, + sizeof(on)) < 0) + syslog(LOG_WARNING, "bdump_get: setsockopt (SO_KEEPALIVE): %m"); + + zdbug((LOG_DEBUG, "bdump_get: connected")); + + /* Now begin the brain dump. */ +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + if (get_tgt()) { + syslog(LOG_ERR, "bdump_get: get_tgt failed"); + cleanup(server); + return; + } + switch(bdump_auth_proto) { +#ifdef HAVE_KRB5 + case 5: /* "client" side */ + memset((char *)&creds, 0, sizeof(creds)); + + retval = krb5_build_principal(Z_krb5_ctx, &principal, + strlen(ZGetRealm()), + ZGetRealm(), + SERVER_KRB5_SERVICE, SERVER_INSTANCE, + NULL); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_build_principal: %s", + error_message(retval)); + cleanup(server); + return; + } + + retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.server); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_copy_principal (server): %s", + error_message(retval)); + krb5_free_principal(Z_krb5_ctx, principal); + cleanup(server); + return; + } + + retval = krb5_copy_principal(Z_krb5_ctx, principal, &creds.client); + krb5_free_principal(Z_krb5_ctx, principal); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_copy_principal (client): %s", + error_message(retval)); + krb5_free_cred_contents(Z_krb5_ctx, &creds); + cleanup(server); + return; + } + + retval = krb5_get_credentials(Z_krb5_ctx, 0, Z_krb5_ccache, + &creds, &credsp); + krb5_free_cred_contents(Z_krb5_ctx, &creds); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_get_credentials: %s", error_message(retval)); + cleanup(server); + return; + } + + retval = krb5_auth_con_init(Z_krb5_ctx, &bdump_ac); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_auth_con_init: %s", error_message(retval)); + krb5_free_creds(Z_krb5_ctx, credsp); + cleanup(server); + return; + } + + retval = krb5_auth_con_setflags(Z_krb5_ctx, bdump_ac, KRB5_AUTH_CONTEXT_DO_SEQUENCE); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_auth_con_setflags: %s", error_message(retval)); + krb5_free_creds(Z_krb5_ctx, credsp); + cleanup(server); + return; + } + + retval = krb5_auth_con_genaddrs(Z_krb5_ctx, bdump_ac, live_socket, + KRB5_AUTH_CONTEXT_GENERATE_LOCAL_FULL_ADDR|KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_auth_con_genaddrs: %s", error_message(retval)); + krb5_free_creds(Z_krb5_ctx, credsp); + cleanup(server); + return; + } + + memset((char *)&data, 0, sizeof(krb5_data)); + retval = krb5_mk_req_extended(Z_krb5_ctx, &bdump_ac, AP_OPTS_MUTUAL_REQUIRED|AP_OPTS_USE_SUBKEY, + NULL, credsp, &data); + if (retval) { + syslog(LOG_ERR, "bdump_get: krb5_mk_req_ext: %s", error_message(retval)); + krb5_free_creds(Z_krb5_ctx, credsp); + cleanup(server); + return; + } + retval = SendKrb5Data(live_socket, &data); + krb5_free_creds(Z_krb5_ctx, credsp); + if (retval) { + syslog(LOG_ERR, "bdump_get: cannot send authenticator: %s", + error_message(retval)); + krb5_free_data_contents(Z_krb5_ctx, &data); + cleanup(server); + return; + } + krb5_free_data_contents(Z_krb5_ctx, &data); + memset((char *)&data, 0, sizeof(krb5_data)); + retval = GetKrb5Data(live_socket, &data); + if (retval) { + syslog(LOG_ERR, "bdump_get: cannot get auth response: %s", + error_message(retval)); + cleanup(server); + return; + } + retval = krb5_rd_rep(Z_krb5_ctx, bdump_ac, &data, &rep); + free(data.data); + memset((char *)&data, 0, sizeof(krb5_data)); + if (retval) { + syslog(LOG_ERR, "bdump_get: mutual authentication failed: %s", + error_message(retval)); + cleanup(server); + return; + } + break; +#endif +#ifdef HAVE_KRB4 + case 4: + bdump_auth_proc = Z_FormatAuthHeaderWithASCIIAddress; + /* send an authenticator */ + retval = SendKerberosData(live_socket, &ticket, SERVER_SERVICE, + SERVER_INSTANCE); + if (retval != 0) { + syslog(LOG_ERR,"bdump_get: %s", error_message(retval)); + cleanup(server); + return; + } + zdbug((LOG_DEBUG, "bdump_get: SendKerberosData ok")); + + /* get his authenticator */ + retval = GetKerberosData(live_socket, from.sin_addr, &kdata, + SERVER_SERVICE, srvtab_file); + if (retval != KSUCCESS) { + syslog(LOG_ERR, "bdump_get getkdata: %s",error_message(retval)); + cleanup(server); + return; + } + + if (strcmp(kdata.pname, SERVER_SERVICE) || + strcmp(kdata.pinst, SERVER_INSTANCE) || + strcmp(kdata.prealm, ZGetRealm())) { + syslog(LOG_ERR, "bdump_get: peer not zephyr in lrealm: %s.%s@%s", + kdata.pname, kdata.pinst,kdata.prealm); + cleanup(server); + return; + } + break; +#endif /* HAVE_KRB4 */ + } +#endif /* defined(HAVE_KRB4) || defined(HAVE_KRB5) */ + retval = setup_file_pointers(); + if (retval != 0) { + syslog(LOG_WARNING, "bdump_get: can't set up file pointers: %s", + error_message (retval)); + cleanup(server); + return; + } + retval = bdump_recv_loop(server); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_get: bdump_recv_loop failed: %s", + error_message(retval)); + cleanup(server); + return; + } + zdbug((LOG_DEBUG,"bdump_get: gbdl ok")); + retval = bdump_send_loop(server); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_send_loop failed: %s", + error_message(retval)); + cleanup(server); + return; + } + + zdbug((LOG_DEBUG, "bdump_get: gbd finished")); + + /* set this guy to be up, and schedule a hello */ + server->state = SERV_UP; + timer_reset(server->timer); + server->timer = timer_set_rel(0L, server_timo, server); + + + zdbug((LOG_DEBUG,"cleanup gbd")); + + shutdown_file_pointers(); +#ifdef _POSIX_VERSION + action.sa_handler = SIG_DFL; + sigaction(SIGPIPE, &action, NULL); +#else + signal(SIGPIPE, SIG_DFL); +#endif + bdumping = 0; + server->dumping = 0; + /* Now that we are finished dumping, send all the queued packets */ + server_send_queue(server); + + return; +} + +void +bdump_get(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + void (*proc)(ZNotice_t *, int, struct sockaddr_in *, Server *); + + proc = NULL; + + if (zdebug) { + syslog(LOG_DEBUG, "bdump_get: bdump v%s avail %s", + notice->z_class_inst, inet_ntoa(who->sin_addr)); + } + + if (strcmp (notice->z_class_inst, "1.2") == 0) + proc = bdump_get_v12; + + if (proc) { + (*proc)(notice, auth, who, server); + } else { + syslog(LOG_WARNING, + "bdump_get: Incompatible bdump version '%s' from %s", + notice->z_class_inst, + inet_ntoa(who->sin_addr)); + } +} + +/* + * Send off a packet via tcp + */ +static Code_t +transmit_tcp(char *pack, int packlen) +{ + Code_t retval = ZERR_NONE; + u_short length; + int count; +#ifdef HAVE_KRB5 + krb5_data indata, outmsg; +#endif + /* output and bdump_ac are globals */ + + if (packlen > Z_MAXPKTLEN) { + syslog(LOG_ERR, "transmit_tcp: packet is too large (%d bytes)", packlen); + return ZERR_PKTLEN; + } + +#ifdef HAVE_KRB5 + if (bdump_ac) { + indata.length = packlen; + indata.data = pack; + memset(&outmsg, 0, sizeof(krb5_data)); + + retval = krb5_mk_priv(Z_krb5_ctx, bdump_ac, &indata, &outmsg, NULL); + + if (retval != ZERR_NONE) + goto cleanup; + + packlen = outmsg.length; + pack = outmsg.data; + } +#endif + length = htons((unsigned short) packlen); + + count = net_write(output, (char *) &length, sizeof(length)); + if (count != sizeof(length)) { + if (count < 0) { + syslog(LOG_WARNING, "transmit_tcp: writing length: %m"); + retval = errno; + } else { + syslog(LOG_WARNING, "transmit_tcp: writing length: %lu vs %d", + (unsigned long)sizeof(length), count); + retval = ZSRV_LEN; + } + goto cleanup; + } + count = net_write(output, pack, packlen); + if (count != packlen) { + if (count < 0) { + syslog(LOG_WARNING, "transmit_tcp: writing data: %m"); + retval = errno; + } else { + syslog(LOG_WARNING, "transmit_tcp: writing data: %d vs %d", packlen, count); + retval = ZSRV_LEN; + } + goto cleanup; + } + + cleanup: +#ifdef HAVE_KRB5 + if (bdump_ac) + krb5_free_data_contents(Z_krb5_ctx, &outmsg); +#endif + + return retval; +} + +/* + * Send a list off as the specified notice + */ + +Code_t +bdump_send_list_tcp(ZNotice_Kind_t kind, + struct sockaddr_in *addr, + char *class_name, + char *inst, + char *opcode, + char *sender, + char *recip, + char **lyst, + int num) +{ + ZNotice_t notice; + char *pack; + int packlen; + Code_t retval; + + memset (¬ice, 0, sizeof(notice)); + + notice.z_kind = kind; + + notice.z_port = addr->sin_port; + notice.z_class = class_name; + notice.z_class_inst = inst; + notice.z_opcode = opcode; + notice.z_sender = sender; + notice.z_recipient = recip; + notice.z_default_format = ""; + notice.z_num_other_fields = 0; + if (addr) + notice.z_sender_sockaddr.ip4 = *addr; /*XXX*/ + + retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, + bdump_auth_proc); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_send_list_tcp: ZFormatNotice: %s", error_message(retval)); + return retval; + } + + retval = transmit_tcp(pack, packlen); + free(pack); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "bdump_send_list_tcp: transmit_tcp: %s", error_message(retval)); + + return retval; +} + +static void +shutdown_file_pointers(void) +{ + if (input) { + fclose(input); + input = 0; + } + if (output) { + fclose(output); + output = 0; + } + if (live_socket >= 0) { + close(live_socket); + live_socket = -1; +#ifdef HAVE_KRB5 + if (bdump_ac) + krb5_auth_con_free(Z_krb5_ctx, bdump_ac); + bdump_ac = NULL; +#endif + } +} + +static void +cleanup(Server *server) +{ +#ifdef _POSIX_VERSION + struct sigaction action; +#endif + + zdbug((LOG_DEBUG, "bdump cleanup")); + + if (server != limbo_server) { + if (server->state != SERV_STARTING) + server->state = SERV_DEAD; + timer_reset(server->timer); + server->timer = timer_set_rel(server->timeout, server_timo, server); + } + shutdown_file_pointers (); +#ifdef _POSIX_VERSION + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + action.sa_handler = SIG_DFL; + sigaction(SIGPIPE,&action, NULL); +#else + signal(SIGPIPE, SIG_DFL); +#endif /* _POSIX_VERSION */ + bdumping = 0; + server->dumping = 0; +} + +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + +int got_des = 0; + +#ifndef HAVE_KRB4 +unsigned int enctypes[] = {ENCTYPE_DES_CBC_CRC, + ENCTYPE_DES_CBC_MD4, + ENCTYPE_DES_CBC_MD5, +#ifdef ENCTYPE_DES_CBC_RAW + ENCTYPE_DES_CBC_RAW, +#endif + 0}; +#endif + + +int +get_tgt(void) +{ + int retval = 0; +#ifndef HAVE_KRB4 + int i; + krb5_keytab_entry kt_ent; +#endif +#ifdef HAVE_KRB4 + /* MIT Kerberos 4 get_svc_in_tkt() requires instance to be writable and + * at least INST_SZ bytes long. */ + static char buf[INST_SZ + 1] = SERVER_INSTANCE; + + /* have they expired ? */ + if (ticket_time < NOW - tkt_lifetime(TKTLIFETIME) + (15L * 60L)) { + /* +15 for leeway */ + + zdbug((LOG_DEBUG,"get new tickets: %d %d %d", ticket_time, NOW, + NOW - tkt_lifetime(TKTLIFETIME) + 15L)); + + dest_tkt(); + + retval = krb_get_svc_in_tkt(SERVER_SERVICE, buf, (char *)ZGetRealm(), + "krbtgt", (char *)ZGetRealm(), + TKTLIFETIME, srvtab_file); + if (retval != KSUCCESS) { + syslog(LOG_ERR,"get_tgt: krb_get_svc_in_tkt: %s", + error_message(retval)); + ticket_time = 0; + return(1); + } else { + ticket_time = NOW; + } + + retval = read_service_key(SERVER_SERVICE, SERVER_INSTANCE, + (char *)ZGetRealm(), 0 /*kvno*/, + srvtab_file, (char *)serv_key); + if (retval != KSUCCESS) { + syslog(LOG_ERR, "get_tgt: read_service_key: %s", + error_message(retval)); + return 1; + } + des_key_sched(serv_key, serv_ksched.s); + got_des = 1; + } +#endif +#ifdef HAVE_KRB5 + /* XXX */ + if (ticket5_time < NOW - tkt5_lifetime(TKT5LIFETIME) + (15L * 60L)) { + krb5_keytab kt; + krb5_get_init_creds_opt opt; + krb5_creds cred; + krb5_principal principal; + + memset(&cred, 0, sizeof(cred)); + + retval = krb5_build_principal(Z_krb5_ctx, &principal, + strlen(ZGetRealm()), + ZGetRealm(), + SERVER_KRB5_SERVICE, SERVER_INSTANCE, + NULL); + if (retval) { + syslog(LOG_ERR, "get_tgt: krb5_build_principal: %s", + error_message(retval)); + return 1; + } + + krb5_get_init_creds_opt_init (&opt); + krb5_get_init_creds_opt_set_tkt_life (&opt, TKT5LIFETIME); + + retval = krb5_kt_resolve(Z_krb5_ctx, keytab_file, &kt); + if (retval) { + syslog(LOG_ERR, "get_tgt: krb5_kt_resolve: %s", + error_message(retval)); + krb5_free_principal(Z_krb5_ctx, principal); + return 1; + } + + retval = krb5_get_init_creds_keytab (Z_krb5_ctx, + &cred, + principal, + kt, + 0, + NULL, + &opt); + if (retval) { + syslog(LOG_ERR, "get_tgt: krb5_get_init_creds_keytab: %s", + error_message(retval)); + krb5_free_principal(Z_krb5_ctx, principal); + krb5_kt_close(Z_krb5_ctx, kt); + return 1; + } + +#ifndef HAVE_KRB4 + for (i = 0; enctypes[i]; i++) { + retval = krb5_kt_get_entry(Z_krb5_ctx, kt, principal, + 0, enctypes[i], &kt_ent); + if (!retval) + break; + } + if (!retval) { +#ifdef HAVE_KRB5_CRYPTO_INIT + retval = krb5_copy_keyblock(Z_krb5_ctx, &kt_ent.keyblock, + &server_key); +#else + retval = krb5_copy_keyblock(Z_krb5_ctx, &kt_ent.key, &server_key); +#endif + if (retval) { + syslog(LOG_ERR, "get_tgt: krb5_copy_keyblock: %s", + error_message(retval)); + krb5_free_principal(Z_krb5_ctx, principal); + krb5_kt_close(Z_krb5_ctx, kt); + return 1; + } + + got_des = 1; + } +#endif /* HAVE_KRB4 */ + krb5_free_principal(Z_krb5_ctx, principal); + krb5_kt_close(Z_krb5_ctx, kt); + + retval = krb5_cc_initialize (Z_krb5_ctx, Z_krb5_ccache, cred.client); + if (retval) { + syslog(LOG_ERR, "get_tgt: krb5_cc_initialize: %s", + error_message(retval)); + return 1; + } + + retval = krb5_cc_store_cred (Z_krb5_ctx, Z_krb5_ccache, &cred); + if (retval) { + syslog(LOG_ERR, "get_tgt: krb5_cc_store_cred: %s", + error_message(retval)); + return 1; + } + + ticket5_time = NOW; + + krb5_free_cred_contents (Z_krb5_ctx, &cred); + } +#endif + return 0; +} +#endif /* HAVE_KRB4 */ + +/* + * The braindump offer wasn't taken, so we retract it. + */ + +/*ARGSUSED*/ +static void +close_bdump(void *arg) +{ + if (bdump_socket >= 0) { + FD_CLR(bdump_socket, &interesting); + close(bdump_socket); + nfds = srv_socket + 1; + bdump_socket = -1; + + zdbug((LOG_DEBUG, "bdump not used")); + } else { + zdbug((LOG_DEBUG, "bdump not open")); + } + return; +} + +/* + * Start receiving instruction notices from the brain dump socket + */ + +static Code_t +bdump_recv_loop(Server *server) +{ + ZNotice_t notice; + char *packet = NULL; + int len; + int pblen = Z_MAXPKTLEN; + Code_t retval; + Client *client = NULL; + struct sockaddr_in who; +#ifdef HAVE_KRB5 + uint32_t client_enctype; + uint32_t client_keysize; + unsigned char buf[512]; + int blen; +#endif +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + char *cp; +#ifndef HAVE_KRB4 + unsigned char cblock[8]; +#else + C_Block cblock; +#endif +#endif + ZRealm *realm = NULL; + + zdbug((LOG_DEBUG, "bdump_recv_loop")); + + packet = malloc(Z_MAXPKTLEN); + + if (packet == NULL) + return ENOMEM; + + /* do the inverse of bdump_send_loop, registering stuff on the fly */ + while (1) { + if (packets_waiting()) { + /* A non-braindump packet is waiting; handle it. */ + bdumping = 0; + bdump_concurrent = 1; + handle_packet(); + bdump_concurrent = 0; + bdumping = 1; + } + len = sizeof(packet); + retval = get_packet(&packet, &pblen, &len); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_recv_loop: get_packet failed: %s", error_message(retval)); + free(packet); + return retval; + } + +#if HAVE_KRB5 + if (bdump_ac) { + krb5_data in, out; + in.length = len; + in.data = packet; + memset(&out, 0, sizeof(krb5_data)); + retval = krb5_rd_priv(Z_krb5_ctx, bdump_ac, &in, &out, NULL); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_recv_loop: krb5_rd_priv failed: %s", error_message(retval)); + free(packet); + return retval; + } + memcpy(packet, out.data, out.length); + len = out.length; + krb5_free_data_contents(Z_krb5_ctx, &out); + } +#endif + + retval = ZParseNotice(packet, len, ¬ice); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_recv_loop: ZParseNotice failed: %s", error_message(retval)); + free(packet); + return retval; + } +#if defined (DEBUG) + if (zdebug) { + syslog(LOG_DEBUG, "bdump_recv_loop: %s '%s' '%s' '%s' '%s' '%s'", + ZNoticeKinds[(int) notice.z_kind], notice.z_class, + notice.z_class_inst, notice.z_opcode, notice.z_sender, + notice.z_recipient); + } +#endif /* DEBUG */ + who.sin_family = AF_INET; /*XXX*/ + who.sin_addr.s_addr = notice.z_sender_sockaddr.ip4.sin_addr.s_addr; + who.sin_port = notice.z_port; + + if (strcmp(notice.z_opcode, ADMIN_DONE) == 0) { + /* end of brain dump */ + free(packet); + return ZERR_NONE; + } else if (strcmp(notice.z_opcode, ADMIN_NEWREALM) == 0) { + /* get a realm from the message */ + realm = realm_get_realm_by_name(notice.z_message); + if (!realm) { + syslog(LOG_ERR, "bdump_recv_loop: realm_get_realm_by_name failed: no realm %s", + notice.z_message); + } + } else if (strcmp(notice.z_class, LOGIN_CLASS) == 0) { + /* 1 = tell it we are authentic */ + retval = ulogin_dispatch(¬ice, 1, &who, server); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "bdump_recv_loop: ulogin_dispatch failed: %s", + error_message(retval)); + free(packet); + return retval; + } + } else if (strcmp(notice.z_opcode, ADMIN_NEWCLT) == 0) { + /* a new client */ + notice.z_port = htons((u_short) atoi(notice.z_message)); + retval = client_register(¬ice, &who.sin_addr, &client, 0); + if (retval != ZERR_NONE) { + syslog(LOG_ERR,"bdump_recv_loop: client_register failed: %s", error_message(retval)); + free(packet); + return retval; + } +#ifdef HAVE_KRB5 + client->session_keyblock = NULL; + if (*notice.z_class_inst) { + /* check out this session key I found */ + cp = notice.z_message + strlen(notice.z_message) + 1; + if (*cp == '0' && got_des) { + /* ****ing netascii; this is an encrypted DES keyblock + XXX this code should be conditionalized for server + transitions */ + retval = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC, + sizeof(cblock), + &client->session_keyblock); + if (retval) { + syslog(LOG_ERR, "bdump_recv_loop: failed to allocate DES keyblock: %s", + error_message(retval)); + free(packet); + return retval; + } + retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(cblock)); + if (retval != ZERR_NONE) { + syslog(LOG_ERR,"bdump_recv_loop: bad cblock read: %s (%s)", + error_message(retval), cp); + } else { + retval = des_service_decrypt(cblock, Z_keydata(client->session_keyblock)); + if (retval) { + syslog(LOG_ERR, "bdump_recv_loop: failed to decyrpt DES session key: %s", + error_message(retval)); + free(packet); + return retval; + } + } + } else if (*cp == 'Z') { + /* Zcode! Long live the new flesh! */ + retval = ZReadZcode((unsigned char *)cp, buf, sizeof(buf), &blen); + if (retval != ZERR_NONE) { + syslog(LOG_ERR,"bdump_recv_loop: bad keyblock read: %s (%s)", + error_message(retval), cp); + } else { + memcpy(&client_enctype, &buf[0], sizeof(uint32_t)); + memcpy(&client_keysize, &buf[4], sizeof(uint32_t)); + retval = Z_krb5_init_keyblock(Z_krb5_ctx, + ntohl(client_enctype), + ntohl(client_keysize), + &client->session_keyblock); + if (retval) { + syslog(LOG_ERR, "bdump_recv_loop: failed to allocate keyblock: %s", + error_message(retval)); + free(packet); + return retval; + } + memcpy(Z_keydata(client->session_keyblock), &buf[8], + Z_keylen(client->session_keyblock)); + } + } + } +#else +#ifdef HAVE_KRB4 + memset(client->session_key, 0, sizeof(C_Block)); + if (*notice.z_class_inst) { + /* a C_Block is there */ + cp = notice.z_message + strlen(notice.z_message) + 1; + retval = ZReadAscii(cp, strlen(cp), cblock, sizeof(C_Block)); + if (retval != ZERR_NONE) { + syslog(LOG_ERR,"bdump_recv_loop: bad cblock read: %s (%s)", + error_message(retval), cp); + } else { + des_ecb_encrypt((des_cblock *)cblock, + (des_cblock *)client->session_key, + serv_ksched.s, DES_DECRYPT); + } + } +#endif /* HAVE_KRB4 */ +#endif + } else if (strcmp(notice.z_opcode, CLIENT_SUBSCRIBE) == 0) { + /* a subscription packet */ + if (!client) { + syslog(LOG_ERR, "bdump_recv_loop: no client"); + free(packet); + return ZSRV_NOCLT; + } + retval = subscr_subscribe(client, ¬ice, server); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_recv_loop: subscr_subscribe failed: %s", + error_message(retval)); + free(packet); + return retval; + } + } else if (strcmp(notice.z_opcode, REALM_SUBSCRIBE) == 0) { + /* add a subscription for a realm */ + if (realm) { + retval = subscr_realm(realm, ¬ice); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "bdump_recv_loop: subscr_realm failed: %s", + error_message(retval)); + free(packet); + return retval; + } + } /* else */ + /* Other side tried to send us subs for a realm we didn't + know about, and so we drop them silently */ + + } else { + syslog(LOG_ERR, "bdump_recv_loop: bad opcode %s",notice.z_opcode); + free(packet); + return ZSRV_UNKNOWNOPCODE; + } + } +} + +/* + * Send all the state to the peer. + */ + +static Code_t +bdump_send_loop(Server *server) +{ + Code_t retval; + + zdbug((LOG_DEBUG, "bdump send loop")); + + retval = uloc_send_locations(); + if (retval != ZERR_NONE) + return retval; + retval = client_send_clients(); + if (retval != ZERR_NONE) + return retval; + retval = realm_send_realms(); + if (retval != ZERR_NONE) + return retval; + return send_done(); +} + +/* + * Send a sync indicating end of this host + */ + +static Code_t +send_done(void) +{ + Code_t retval; + + zdbug((LOG_DEBUG, "send_done")); + + retval = send_normal_tcp(SERVACK, bdump_sin.sin_port, ZEPHYR_ADMIN_CLASS, + "", ADMIN_DONE, myname, "", NULL, 0); + return retval; +} + + +/* + * Send a list off as the specified notice + */ + +static Code_t +send_list(ZNotice_Kind_t kind, + int port, + char *class_name, + char *inst, + char *opcode, + char *sender, + char *recip, + char **lyst, + int num) +{ + ZNotice_t notice; + char *pack; + int packlen; + Code_t retval; + + memset (¬ice, 0, sizeof(notice)); + + notice.z_kind = kind; + notice.z_port = port; + notice.z_class = class_name; + notice.z_class_inst = inst; + notice.z_opcode = opcode; + notice.z_sender = sender; + notice.z_recipient = recip; + notice.z_default_format = ""; + notice.z_num_other_fields = 0; + + retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, ZNOAUTH); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "sl format: %s", error_message(retval)); + return retval; + } + + retval = ZSendPacket(pack, packlen, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "sl xmit: %s", error_message(retval)); + free(pack); + return retval; +} + +/* + * Send a message off as the specified notice, via TCP + */ + +static Code_t +send_normal_tcp(ZNotice_Kind_t kind, + int port, + char *class_name, + char *inst, + char *opcode, + char *sender, + char *recip, + char *message, + int len) +{ + ZNotice_t notice; + char *pack; + int packlen; + Code_t retval; + + memset (¬ice, 0, sizeof(notice)); + + notice.z_kind = kind; + notice.z_port = port; + notice.z_class = class_name; + notice.z_class_inst = inst; + notice.z_opcode = opcode; + notice.z_sender = sender; + notice.z_recipient = recip; + notice.z_default_format = ""; + notice.z_message = message; + notice.z_message_len = len; + notice.z_num_other_fields = 0; + + retval = ZFormatNotice(¬ice, &pack, &packlen, bdump_auth_proc); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "send_normal_tcp: ZFormatNotice: %s", error_message(retval)); + return retval; + } + + retval = transmit_tcp(pack, packlen); + free(pack); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "send_normal_tcp: transmit_tcp: %s", error_message(retval)); + + return retval; +} + +/* + * get a packet from the TCP socket + * return 0 if successful, error code else + */ + +static Code_t +get_packet(char **packet, int *buflen, int *retlen) +{ + unsigned short length; + int result; + char *p; + + result = net_read(input, (char *) &length, sizeof(unsigned short)); + if (result < (int)sizeof(short)) { + if (result < 0) { + return errno; + } else { + syslog(LOG_ERR, "get_packet: received length: %d vs %lu (%m)", + result, (unsigned long)sizeof(short)); + return ZSRV_LEN; + } + } + + length = ntohs(length); + if (*buflen < length) { + p = realloc(*packet, length); + if (p == NULL) { + syslog(LOG_ERR, "get_packet: failed to expand buffer to %d bytes from %d", + *buflen, length); + return ZSRV_BUFSHORT; + } + syslog(LOG_DEBUG, "get_packet: expanded buffer from %d bytes to %d", + *buflen, length); + *buflen = length; + *packet = p; + } + result = net_read(input, *packet, (int) length); + if (result < length) { + if (result < 0) { + return errno; + } else { + syslog(LOG_ERR, "get_pkt: %d vs %d (%m)", result, length); + return ZSRV_LEN; + } + } + *retlen = length; + return ZERR_NONE; +} + +static Code_t +extract_sin(ZNotice_t *notice, struct sockaddr_in *target) +{ + char *cp = notice->z_message; + char *buf; + + buf = cp; + if (!notice->z_message_len || *buf == '\0') { + return ZSRV_PKSHORT; + } + target->sin_addr.s_addr = inet_addr(cp); + + cp += (strlen(cp) + 1); /* past the null */ + if ((cp >= notice->z_message + notice->z_message_len) || (*cp == '\0')) { + return(ZSRV_PKSHORT); + } + target->sin_port = htons((unsigned short)atoi(cp)); + target->sin_family = AF_INET; + return ZERR_NONE; +} + +static int +net_read(FILE *f, char *buf, int len) +{ + int cc, len2 = 0; + + fflush (output); + do { + errno = 0; + cc = fread(buf, 1, len, f); + if (cc == 0) + { + if (feof(f)) + return len2; + if (errno == 0) + errno = EIO; + return -1; + } + buf += cc; + len2 += cc; + len -= cc; + } while (len > 0); + return len2; +} + +static int +net_write(FILE *f, char *buf, int len) +{ + int cc; + int wrlen = len; + do { + cc = fwrite (buf, 1, wrlen, f); + if (cc == 0) + return -1; + buf += cc; + wrlen -= cc; + } while (wrlen > 0); + return len; +} + +static int +setup_file_pointers (void) +{ + int fd; + + input = fdopen (live_socket, "r"); + if (!input) + return errno; + + fd = dup (live_socket); + if (fd < 0) + return errno; + output = fdopen (fd, "w"); + if (!output) + return errno; + + return 0; +} + +#ifdef HAVE_KRB5 +static int des_service_decrypt(unsigned char *in, unsigned char *out) { +#ifndef HAVE_KRB4 + krb5_data dout; +#ifdef HAVE_KRB5_C_DECRYPT + krb5_enc_data din; + + dout.length = 8; + dout.data = (char *)out; /*What*/ + + din.ciphertext.length = 8; + din.ciphertext.data = (char *)in; + din.enctype = Z_enctype(server_key); + +#ifdef HAVE_KRB5_CRYPTO_INIT + return krb5_c_decrypt(Z_krb5_ctx, *server_key, 0, 0, &din, &dout); +#else + return krb5_c_decrypt(Z_krb5_ctx, server_key, 0, 0, &din, &dout); +#endif +#elif defined(HAVE_KRB5_CRYPTO_INIT) + int ret; + krb5_crypto crypto; + + dout.length = 8; + dout.data = out; + + ret = krb5_crypto_init(Z_krb5_ctx, server_key, Z_enctype(server_key), &crypto); + if (ret) + return ret; + + ret = krb5_decrypt_ivec(Z_krb5_ctx, crypto, 0, in, 8, &dout, NULL); + + krb5_crypto_destroy(Z_krb5_ctx, crypto); + + return ret; +#endif +#else + des_ecb_encrypt((C_Block *)in, (C_Block *)out, serv_ksched.s, DES_DECRYPT); + return 0; /* sigh */ +#endif +} +#endif diff --git a/server/class.c b/server/class.c new file mode 100644 index 0000000..2f91934 --- /dev/null +++ b/server/class.c @@ -0,0 +1,392 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for the Zephyr server class manager subsystem. + * + * Created by: John T. Kohl + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" /* includes zephyr/zephyr.h */ +#include + +#if !defined (lint) && !defined (SABER) +static const char rcsid_class_c[] = +"$Id$"; +#endif + +/* + * Class manager subsystem. + * + * + * External functions are: + * + * Code_t triplet_register(client, subs, realm) + * + * Code_t triplet_deregister(client, subs, realm) + * + * Client *triplet_lookup(subs) + * Client *client; + * Destlist *subs; + * + * Acl *class_get_acl(class_name) + * String *class_name; + * + * Code_t class_restrict(class_name, acl) + * char *class_name; + * Acl *acl; + * + * Code_t class_setup_restricted(class_name, acl) + * char *class_name; + * Acl *acl; + * + * and several Destination methods. + */ + +/* + * The data structure used for the class manager is an array of hash buckets + * each containing a pointer to a doubly linked circular list (in the style + * of insque/remque). Each element of this list contains a class.instance + * name (which hashes into the bucket associated with this list) and a + * doubly linked list of clients which are interested in this class. + * The data pointed to by these clients is owned by other modules. Care + * must be taken by the caller not to a free()'d client + * structure. + * + * If any hash bucket is empty, the pointer is null. + * + * The first element in the hash bucket is a special header unused for + * storing classes, and is used for finding the end of the list. + * + * If any list of interested clients is empty, the class name is garbage + * collected, unless the class has been registered as restricted. + */ + +/* Private variables */ +#define EMPTY_CLASS 2000 + +#define ALLOC_OFFSET 8 /* Allocate 32 bytes less than a power of 2. */ +#define ALLOC_INIT 8 /* Initial number of subscriptions. */ + +#define HASHSIZE 1023 +#define HASHVAL(c, i, r) (((c)->hash_val ^ (i)->hash_val ^ (r)->hash_val) \ + % HASHSIZE) +#define DEST_HASHVAL(dest) HASHVAL((dest).classname, (dest).inst, (dest).recip) + +static Triplet *triplet_bucket[HASHSIZE]; /* the hash table of pointers */ + +static Code_t remove_client(Triplet *triplet, Client *client, ZRealm *realm); +static Code_t insert_client(Triplet *triplet, Client *client, ZRealm *realm); +static Triplet *triplet_alloc(String *classname, String *inst, + String *recipient); +static void free_triplet(Triplet *); + +/* public routines */ + +/* + * Determine if two destination triplets are equal. Note the backup + * case-insensitive recipient check in the third term. Recipients are + * not downcased at subscription time (in order to preserve case for, + * say, "zctl ret"), but traditional zephyr server behavior has not + * been case-sensitive in the recipient string. In most cases, a + * failed match will fail on the classname or instance, and a successful + * match will succeed on the (d1->recip == d2->recip) check, so this + * shouldn't affect performance. + */ + +int +ZDest_eq(Destination *d1, + Destination *d2) +{ + return((d1->classname == d2->classname) && + (d1->inst == d2->inst) && + (d1->recip == d2->recip || + strcasecmp(d1->recip->string, d2->recip->string) == 0)); +} + + +/* the client as interested in a triplet */ + +Code_t +triplet_register(Client *client, + Destination *dest, + ZRealm *realm) +{ + Triplet *triplet; + unsigned long hashval; + + hashval = DEST_HASHVAL(*dest); + for (triplet = triplet_bucket[hashval]; triplet; triplet = triplet->next) { + if (ZDest_eq(&triplet->dest, dest)) + return insert_client(triplet, client, realm); + } + + /* Triplet not present in hash table, insert it. */ + triplet = triplet_alloc(dest->classname, dest->inst, dest->recip); + Triplet_insert(&triplet_bucket[hashval], triplet); + return insert_client(triplet, client, realm); +} + +/* dissociate client from the class, garbage collecting if appropriate */ + +Code_t +triplet_deregister(Client *client, + Destination *dest, + ZRealm *realm) +{ + Triplet *triplet; + int retval; + unsigned long hashval; + + hashval = DEST_HASHVAL(*dest); + for (triplet = triplet_bucket[hashval]; triplet; triplet = triplet->next) { + if (ZDest_eq(&triplet->dest, dest)) { + retval = remove_client(triplet, client, realm); + if (retval != ZERR_NONE) + return retval; + if (*triplet->clients == NULL && !triplet->acl) { + Triplet_delete(triplet); + free_triplet(triplet); + return ZSRV_EMPTYCLASS; + } + return ZERR_NONE; + } + } + return(ZSRV_BADASSOC); +} + +/* return a linked list of what clients are interested in this triplet */ + +Client ** +triplet_lookup(Destination *dest) +{ + Triplet *triplet; + unsigned long hashval; + + hashval = DEST_HASHVAL(*dest); + for (triplet = triplet_bucket[hashval]; triplet; triplet = triplet->next) { + if (ZDest_eq(&triplet->dest, dest)) + return triplet->clients; + } + return NULL; +} + +/* + * return the acl structure associated with class, or NULL if there is + * no such acl struct + */ + +Acl * +class_get_acl(String *class_name) +{ + Triplet *triplet; + unsigned long hashval; + + hashval = HASHVAL(class_name, empty, empty); + for (triplet = triplet_bucket[hashval]; triplet; triplet = triplet->next) { + if (triplet->dest.classname == class_name && + triplet->dest.inst == empty && triplet->dest.recip == empty) + return triplet->acl; + } + + /* No acl found, not restricted. */ + return NULL; +} + +/* + * restrict class by associating it with the acl structure acl. + * return ZERR_NONE if no error, or ZSRV_NOCLASS if there is no such + * class, or ZSRV_CLASSRESTRICTED if it is already restricted. + */ + +Code_t +class_restrict(char *class_name, + Acl *acl) +{ + Triplet *triplet; + String *d; + unsigned long hashval; + + d = make_string(class_name,1); + hashval = HASHVAL(d, empty, empty); + for (triplet = triplet_bucket[hashval]; triplet; triplet = triplet->next) { + if (triplet->dest.classname == d && triplet->dest.inst == empty && + triplet->dest.recip == empty) { + if (triplet->acl) + return ZSRV_CLASSRESTRICTED; + triplet->acl = acl; + free_string(d); + return ZERR_NONE; + } + } + + free_string(d); + return ZSRV_NOCLASS; +} + +/* + * restrict class by registering it and associating it with the acl + * structure acl. return ZERR_NONE if no error, or ZSRV_CLASSXISTS + * if the class is already registered, or ENOMEM in case of malloc failure. + */ + +Code_t +class_setup_restricted(char *class_name, + Acl *acl) +{ + Triplet *triplet; + String *d; + unsigned long hashval; + + d = make_string(class_name,1); + hashval = HASHVAL(d, empty, empty); + for (triplet = triplet_bucket[hashval]; triplet; triplet = triplet->next) { + if (triplet->dest.classname == d && triplet->dest.inst == empty && + triplet->dest.recip == d) { + free_string(d); + return ZSRV_CLASSXISTS; + } + } + + /* Triplet not present in hash table, insert it. */ + triplet = triplet_alloc(d, empty, empty); + free_string(d); + if (!triplet) + return ENOMEM; + triplet->acl = acl; + Triplet_insert(&triplet_bucket[hashval], triplet); + return ZERR_NONE; +} + +/* private routines */ + +/* allocate space for a class structure */ + +static Triplet * +triplet_alloc(String *classname, + String *inst, + String *recipient) +{ + Triplet *triplet; + + triplet = (Triplet *) malloc(sizeof(Triplet)); + if (!triplet) + return NULL; + + triplet->dest.classname = dup_string(classname); + triplet->dest.inst = dup_string(inst); + triplet->dest.recip = dup_string(recipient); + triplet->clients = NULL; + triplet->acl = NULL; + + return triplet; +} + +/* insert a client into the list associated with the class *ptr */ + +static Code_t +insert_client(Triplet *triplet, + Client *client, + ZRealm *realm) +{ + Client **clientp, **newclients; + int new_size; + + if (triplet->clients) { + /* Avoid duplication. */ + for (clientp = triplet->clients; *clientp; clientp++) { + if (*clientp == client || (realm && (*clientp)->realm == realm)) + return ZSRV_CLASSXISTS; + } + + if (clientp + 1 - triplet->clients >= triplet->clients_size) { + new_size = triplet->clients_size * 2 + ALLOC_OFFSET; + newclients = (Client **) realloc(triplet->clients, + new_size * sizeof(Client *)); + if (newclients == NULL) + return ENOMEM; + clientp = newclients + (clientp - triplet->clients); + triplet->clients = newclients; + triplet->clients_size = new_size; + } + } else { + /* Allocate an initial list of client pointers. */ + triplet->clients = (Client **) malloc(ALLOC_INIT * sizeof(Client *)); + if (triplet->clients == NULL) + return ENOMEM; + triplet->clients_size = ALLOC_INIT; + clientp = triplet->clients; + } + + *clientp = client; + clientp[1] = NULL; + return ZERR_NONE; +} + +/* + * remove the client from the list associated with class *ptr, garbage + * collecting if appropriate + */ + +static Code_t +remove_client(Triplet *triplet, + Client *client, + ZRealm *realm) +{ + Client **clientp; + + for (clientp = triplet->clients; *clientp; clientp++) { + if (*clientp == client || (realm && (*clientp)->realm == realm)) { + for (; *clientp; clientp++) + *clientp = clientp[1]; + return ZERR_NONE; + } + } + + return ZSRV_BADASSOC; +} + +static void +free_triplet(Triplet *triplet) +{ + if (triplet->clients) + free(triplet->clients); + free_string(triplet->dest.classname); + free_string(triplet->dest.inst); + free_string(triplet->dest.recip); + free(triplet); +} + +void +triplet_dump_subs(FILE *fp) +{ + int i; + Triplet *triplet; + Client **clientp; + + for (i = 0; i < HASHSIZE; i++) { + for (triplet = triplet_bucket[i]; triplet; triplet = triplet->next) { + fputs("Triplet '", fp); + dump_quote(triplet->dest.classname->string, fp); + fputs("' '", fp); + dump_quote(triplet->dest.inst->string, fp); + fputs("' '", fp); + dump_quote(triplet->dest.recip->string, fp); + fputs("':\n", fp); + if (triplet->clients) { + for (clientp = triplet->clients; *clientp; clientp++) { + fprintf(fp, "\t%s %d (%s)\n", + inet_ntoa((*clientp)->addr.sin_addr), + ntohs((*clientp)->addr.sin_port), + (*clientp)->principal->string); + } + } + } + } +} + diff --git a/server/client.c b/server/client.c new file mode 100644 index 0000000..02e9862 --- /dev/null +++ b/server/client.c @@ -0,0 +1,234 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for the Client Manager subsystem of the Zephyr server. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include + +#if !defined (lint) && !defined (SABER) +static const char rcsid_client_c[] = +"$Id$"; +#endif + +/* + * External functions: + * + * Code_t client_register(notice, who, client, server, wantdefaults) + * ZNotice_t *notice; + * struct sockaddr_in *who; + * Client **client; (RETURN) + * Server *server; + * int wantdefaults; + * + * Code_t client_deregister(client, host, flush) + * Client *client; + * Host *host; + * int flush; + * + * Client *client_find(who, unsigned int port) + * struct in_addr *host; + * unsigned int port; + * + * void client_dump_clients(fp, clist) + * FILE *fp; + * Client *clist; + */ + +/* + * a client: allocate space, find or insert the address in the + * server's list of hosts, initialize and insert the client into + * the host's list of clients. + * + * This routine assumes that the client has not been registered yet. + * The caller should check by calling client_find. + */ + +#define HASHSIZE 1024 +static Client *client_bucket[HASHSIZE]; + +#define INET_HASH(host, port) ((htonl((host)->s_addr) + \ + htons((unsigned short) (port))) % HASHSIZE) + +Code_t +client_register(ZNotice_t *notice, + struct in_addr *host, + Client **client_p, + int wantdefaults) +{ + Client *client; + + /* chain the client's host onto this server's host list */ + + zdbug((LOG_DEBUG, "client_register: adding %s at %s/%d", + notice->z_sender, inet_ntoa(*host), ntohs(notice->z_port))); + + if (!notice->z_port) + return ZSRV_BADSUBPORT; + + *client_p = client = client_find(host, notice->z_port); + if (!client) { + *client_p = client = (Client *) malloc(sizeof(Client)); + if (!client) + return ENOMEM; + memset(&client->addr, 0, sizeof(struct sockaddr_in)); +#ifdef HAVE_KRB5 + client->session_keyblock = NULL; +#else +#ifdef HAVE_KRB4 + memset(&client->session_key, 0, sizeof(client->session_key)); +#endif +#endif + client->last_send = 0; + client->last_ack = NOW; + client->addr.sin_family = AF_INET; + client->addr.sin_addr.s_addr = host->s_addr; + client->addr.sin_port = notice->z_port; + client->subs = NULL; + client->realm = NULL; + client->principal = make_string(notice->z_sender, 0); + Client_insert(&client_bucket[INET_HASH(&client->addr.sin_addr, + notice->z_port)], client); + } + + /* Add default subscriptions only if this is not resulting from a brain + * dump, AND this request wants defaults. */ + if (!bdumping && wantdefaults) + return subscr_def_subs(client); + else + return ZERR_NONE; +} + +/* + * Deregister the client, freeing resources. + * Remove any packets in the nack queue, release subscriptions, release + * locations, and dequeue him from the host. + */ + +void +client_deregister(Client *client, + int flush) +{ + Client_delete(client); + nack_release(client); + subscr_cancel_client(client); + free_string(client->principal); +#ifdef HAVE_KRB5 + if (client->session_keyblock) + krb5_free_keyblock(Z_krb5_ctx, client->session_keyblock); +#endif + if (flush) + uloc_flush_client(&client->addr); + free(client); +} + +void +client_flush_host(struct in_addr *host) +{ + int i; + Client *client, *next; + + for (i = 0; i < HASHSIZE; i++) { + for (client = client_bucket[i]; client; client = next) { + next = client->next; + if (client->addr.sin_addr.s_addr == host->s_addr) + client_deregister(client, 1); + } + } + uloc_hflush(host); +} + +/* Unlike client_flush_host, this flushes only subs, not locations */ +void +client_flush_princ(char *target) +{ + int i; + Client *client, *next; + String *principal = make_string(target, 0); + + for (i = 0; i < HASHSIZE; i++) { + for (client = client_bucket[i]; client; client = next) { + next = client->next; + if (client->principal == principal) + client_deregister(client, 0); + } + } + free_string(principal); +} + +Code_t +client_send_clients(void) +{ + int i; + Client *client; + Code_t retval; + + for (i = 0; i < HASHSIZE; i++) { + /* Allow packets to be processed between rows of the hash table. */ + if (packets_waiting()) { + bdumping = 0; + bdump_concurrent = 1; + handle_packet(); + bdump_concurrent = 0; + bdumping = 1; + } + for (client = client_bucket[i]; client; client = client->next) { + if (client->subs) { + retval = subscr_send_subs(client); + if (retval != ZERR_NONE) + return retval; + } + } + } + return ZERR_NONE; +} + +/* + * dump info about clients in this clist onto the fp. + * assumed to be called with SIGFPE blocked + * (true if called from signal handler) + */ + +void +client_dump_clients(FILE *fp) +{ + Client *client; + int i; + + for (i = 0; i < HASHSIZE; i++) { + for (client = client_bucket[i]; client; client = client->next) { + fprintf(fp, "%s/%d (%s):\n", inet_ntoa(client->addr.sin_addr), + ntohs(client->addr.sin_port), client->principal->string); + subscr_dump_subs(fp, client->subs); + } + } +} + +/* + * find a client by host and port + */ + +Client * +client_find(struct in_addr *host, + unsigned int port) +{ + Client *client; + long hashval; + + hashval = INET_HASH(host, port); + for (client = client_bucket[hashval]; client; client = client->next) { + if (client->addr.sin_addr.s_addr == host->s_addr + && client->addr.sin_port == port) + return client; + } + return NULL; +} + diff --git a/server/common.c b/server/common.c new file mode 100644 index 0000000..1666ec4 --- /dev/null +++ b/server/common.c @@ -0,0 +1,130 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for general use within the Zephyr server. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_common_c[] = + "$Id$"; +#endif /* SABER */ +#endif /* lint */ + +/* common routines for the server */ + +/* copy a string into a newly allocated area */ + +char * +strsave (const char *sp) +{ + char *ret; + + ret = strdup(sp); + if (!ret) { + syslog(LOG_CRIT, "no mem strdup'ing"); + abort(); + } + return ret; +} + +/* The "& 0x5f" provides case-insensitivity for ASCII. */ + +unsigned long +hash(const char *string) +{ + unsigned long hval = 0; + char cp; + + while (1) { + cp = *string++; + if (!cp) + break; + hval += cp & 0x5f; + + cp = *string++; + if (!cp) + break; + hval += (cp & 0x5f) * (3 + (1 << 16)); + + cp = *string++; + if (!cp) + break; + hval += (cp & 0x5f) * (1 + (1 << 8)); + + cp = *string++; + if (!cp) + break; + hval += (cp & 0x5f) * (1 + (1 << 12)); + + cp = *string++; + if (!cp) + break; + hval += (cp & 0x5f) * (1 + (1 << 4)); + + hval += ((long) hval) >> 18; + } + + hval &= 0x7fffffff; + return hval; +} + +/* Output a name, replacing newlines with \n and single quotes with \q. */ +void +dump_quote(char *p, FILE *fp) +{ + for (; *p; p++) { + if (*p == '\'') { + putc('\\', fp); + putc('q', fp); + } else if (*p == '\n') { + putc('\\', fp); + putc('n', fp); + } else { + putc(*p, fp); + } + } +} + +/* Pull the address out of the packet for dispatching. Doesn't do anything + * special, and will need to change signatures when ipv6 support happens. But + * it'll be in one place.... + */ +void +notice_extract_address(ZNotice_t *notice, struct sockaddr_in *addr) +{ + /* + * We get the address out of the uid rather than the + * Hopefully by the time a server will actually be speaking ipv6, it won't have + * to worry about talking to other <3.0 realms + */ + memset(addr, 0, sizeof(*addr)); + addr->sin_addr.s_addr = notice->z_uid.zuid_addr.s_addr; + addr->sin_port = notice->z_port; + addr->sin_family = AF_INET; +} + + +int +packets_waiting(void) +{ + fd_set readable, initial; + struct timeval tv; + + if (msgs_queued()) + return 1; + FD_ZERO(&initial); + FD_SET(srv_socket, &initial); + readable = initial; + tv.tv_sec = tv.tv_usec = 0; + return (select(srv_socket + 1, &readable, NULL, NULL, &tv) > 0); +} diff --git a/server/default.subscriptions b/server/default.subscriptions new file mode 100644 index 0000000..2ef3863 --- /dev/null +++ b/server/default.subscriptions @@ -0,0 +1,3 @@ +operations,message,* +message,personal,%me% +message,urgent,%me% diff --git a/server/dispatch.c b/server/dispatch.c new file mode 100644 index 0000000..ea95d3a --- /dev/null +++ b/server/dispatch.c @@ -0,0 +1,1239 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for dispatching a notice. + * + * Created by: John T. Kohl + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include + +#ifndef lint +#ifndef SABER +static const char rcsid_dispatch_c[] = +"$Id$"; +#endif +#endif + +enum { + NACKTAB_HASHSIZE = 1023 +}; +inline static unsigned int +nacktab_hashval(struct sockaddr_in sa, ZUnique_Id_t uid) { + return (sa.sin_addr.s_addr ^ + sa.sin_port ^ + uid.zuid_addr.s_addr ^ + uid.tv.tv_sec ^ + uid.tv.tv_usec) % NACKTAB_HASHSIZE; +} + +#define HOSTS_SIZE_INIT 256 + +/* + * + * External Routines: + * + * void dispatch(notice, auth, who) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * + * void clt_ack(notice, who, sent) + * ZNotice_t *notice; + * struct sockaddr_in *who; + * Sent_type sent; + * + * void nack_release(client) + * Client *client; + * + * void sendit(notice, auth, who, external) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * int external; + * + * void xmit(notice, dest, auth, client) + * ZNotice_t *notice; + * struct sockaddr_in *dest; + * int auth; + * Client *client; + */ + + +String *class_control, *class_admin, *class_hm, *class_ulogin, *class_ulocate; + +int rexmit_times[] = REXMIT_TIMES; + +static void nack_cancel(ZNotice_t *, struct sockaddr_in *); +static void dispatch(ZNotice_t *, int, struct sockaddr_in *, int); +static int send_to_dest(ZNotice_t *, int, Destination *dest, int, int); +static void hostm_deathgram(struct sockaddr_in *, Server *); +static char *hm_recipient(void); + +Statistic realm_notices = {0, "inter-realm notices"}; +Statistic interserver_notices = {0, "inter-server notices"}; +Statistic hm_packets = {0, "hostmanager packets"}; +Statistic control_notices = {0, "client control notices"}; +Statistic message_notices = {0, "message notices"}; +Statistic login_notices = {0, "login notices"}; +Statistic i_s_ctls = {0, "inter-server control notices"}; +Statistic i_s_logins = {0, "inter-server login notices"}; +Statistic i_s_admins = {0, "inter-server admin notices"}; +Statistic i_s_locates = {0, "inter-server locate notices"}; +Statistic locate_notices = {0, "locate notices"}; +Statistic admin_notices = {0, "admin notices"}; + +static Unacked *nacktab[NACKTAB_HASHSIZE]; +static struct in_addr *hosts; +static int hosts_size = 0, num_hosts = 0; + +#ifdef DEBUG +static void +dump_stats (void *arg) +{ + syslog(LOG_INFO, "stats: %s: %d", hm_packets.str, hm_packets.val); + syslog(LOG_INFO, "stats: %s: %d", control_notices.str, + control_notices.val); + syslog(LOG_INFO, "stats: %s: %d", message_notices.str, + message_notices.val); + syslog(LOG_INFO, "stats: %s: %d", login_notices.str, login_notices.val); + syslog(LOG_INFO, "stats: %s: %d", locate_notices.str, locate_notices.val); + syslog(LOG_INFO, "stats: %s: %d", admin_notices.str, admin_notices.val); + syslog(LOG_INFO, "stats: %s: %d", realm_notices.str, realm_notices.val); + syslog(LOG_INFO, "stats: %s: %d", interserver_notices.str, + interserver_notices.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_ctls.str, i_s_ctls.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_logins.str, i_s_logins.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_admins.str, i_s_admins.val); + syslog(LOG_INFO, "stats: %s: %d", i_s_locates.str, i_s_locates.val); + + /* log stuff once an hour */ + timer_set_rel ((long) 6*60*60, dump_stats, arg); +} +#endif + +/* + * Handle an input packet. + * Warning: this function may be called from within a brain dump. + */ + +void +handle_packet(void) +{ + Code_t status; + ZPacket_t input_packet; /* from the network */ + ZNotice_t new_notice; /* parsed from input_packet */ + int input_len; /* len of packet */ + struct sockaddr_in input_sin; /* Zconstructed for authent */ + struct sockaddr_in whoisit; /* for holding peer's address */ + int authentic; /* authentic flag */ + Pending *pending; /* pending packet */ + int from_server; /* packet is from another server */ + ZRealm *realm; /* foreign realm ptr */ + struct sockaddr_in *whence; /* pointer to actual origin */ +#ifdef DEBUG + static int first_time = 1; +#endif + +#ifdef DEBUG + /* Dump statistics five minutes after startup */ + if (first_time) { + first_time = 0; + timer_set_rel(5*60, dump_stats, NULL); + } +#endif + /* handle traffic */ + + if (otherservers[me_server_idx].queue) { + /* something here for me; take care of it */ + zdbug((LOG_DEBUG, "internal queue process")); + + pending = server_dequeue(me_server); + + status = ZParseNotice(pending->packet, pending->len, &new_notice); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "bad notice parse (%s): %s", + inet_ntoa(pending->who.sin_addr), error_message(status)); + } else { + dispatch(&new_notice, pending->auth, &pending->who, 1); + } + server_pending_free(pending); + return; + } + + /* + * nothing in internal queue, go to the external library + * queue/socket + */ + status = ZReceivePacket(input_packet, &input_len, &whoisit); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "bad packet receive: %s from %s", + error_message(status), inet_ntoa(whoisit.sin_addr)); + return; + } + npackets++; + status = ZParseNotice(input_packet, input_len, &new_notice); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "bad notice parse (%s): %s", + inet_ntoa(whoisit.sin_addr), error_message(status)); + return; + } + + if (server_which_server(&whoisit)) { + /* we need to parse twice--once to get + the source addr, second to check + authentication */ + notice_extract_address(&new_notice, &input_sin); + /* Should check to see if packet is from another realm's server, + or a client */ + from_server = 1; + whence = &input_sin; + } else { + from_server = 0; + whence = &whoisit; + } + + /* Don't bother checking authentication on client ACKs */ + if (new_notice.z_kind == CLIENTACK) { + nack_cancel(&new_notice, &whoisit); + return; + } + + /* Clients don't check auth of acks, nor do we make it so they + can in general, so this is safe. */ + if (new_notice.z_kind == SERVACK || new_notice.z_kind == SERVNAK) { + authentic = ZAUTH_YES; + } else { + realm = realm_which_realm(whence); + authentic = ZCheckSrvAuthentication(&new_notice, whence, realm ? realm->name : NULL); + } + + message_notices.val++; + dispatch(&new_notice, authentic, &whoisit, from_server); + return; +} +/* + * Dispatch a notice. + */ + +static void +dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + int from_server) +{ + Code_t status; + String *notice_class; + int authflag; + ZRealm *realm; + char *cp; + + authflag = (auth == ZAUTH_YES); + + if ((int) notice->z_kind < (int) UNSAFE || + (int) notice->z_kind > (int) CLIENTACK) { + syslog(LOG_NOTICE, "bad notice kind 0x%x from %s", notice->z_kind, + inet_ntoa(who->sin_addr)); + return; + } + + if (notice->z_kind == CLIENTACK) { + nack_cancel(notice, who); + return; + } + + notice_class = make_string(notice->z_class,1); + + if (from_server) { + interserver_notices.val++; + status = server_dispatch(notice, authflag, who); + } else if (class_is_hm(notice_class)) { + hm_packets.val++; + status = hostm_dispatch(notice, authflag, who, me_server); + } else if (realm_which_realm(who) && !(class_is_admin(notice_class))) { + realm_notices.val++; + status = realm_dispatch(notice, authflag, who, me_server); + } else if (class_is_control(notice_class)) { + control_notices.val++; + status = control_dispatch(notice, authflag, who, me_server); + } else if (class_is_ulogin(notice_class)) { + login_notices.val++; + status = ulogin_dispatch(notice, authflag, who, me_server); + } else if (class_is_ulocate(notice_class)) { + locate_notices.val++; + status = ulocate_dispatch(notice, authflag, who, me_server); + } else if (class_is_admin(notice_class)) { + admin_notices.val++; + status = server_adispatch(notice, authflag, who, me_server); + } else { + if (!realm_bound_for_realm(ZGetRealm(), notice->z_recipient)) { + cp = strchr(notice->z_recipient, '@'); + if (!cp || + !(realm = realm_get_realm_by_name(cp + 1))) { + /* Foreign user, local realm */ + sendit(notice, authflag, who, 0); + } else + realm_handoff(notice, authflag, who, realm, 1); + } else { + if (notice->z_recipient[0] == '@') + notice->z_recipient = ""; + sendit(notice, authflag, who, 1); + } + free_string(notice_class); + return; + } + + if (status == ZSRV_REQUEUE) + server_self_queue(notice, authflag, who); + free_string(notice_class); +} + +/* + * Send a notice off to those clients who have subscribed to it. + */ + +void +sendit(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + int external) +{ + static int send_counter = 0; + char recipbuf[MAX_PRINCIPAL_SIZE], *recipp, *acl_sender; + int any = 0; + Acl *acl; + Destination dest; + String *class; + + class = make_string(notice->z_class, 1); + if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient)) { + ZRealm *rlm; + + acl = class_get_acl(class); + if (acl != NULL) { + acl_sender = auth ? notice->z_sender : 0; + /* if from foreign realm server, disallow if not realm of sender */ + rlm = realm_which_realm(who); + if (rlm) { + if (!realm_sender_in_realm(rlm->name, notice->z_sender)) { + syslog(LOG_WARNING, "sendit auth not verifiable %s (%s) from %s", + notice->z_class, rlm->name, notice->z_sender); + clt_ack(notice, who, AUTH_FAILED); + free_string(class); + return; + } + } + /* if not auth to transmit, fail */ + if (!access_check(acl_sender, who, acl, TRANSMIT)) { + syslog(LOG_WARNING, "sendit unauthorized %s from %s%s", + notice->z_class, notice->z_sender, auth ? "" : " (unauth)"); + clt_ack(notice, who, AUTH_FAILED); + free_string(class); + return; + } + /* sender != inst and not auth to send to others --> fail */ + if (strcmp(notice->z_sender, notice->z_class_inst) != 0 && + !access_check(acl_sender, who, acl, INSTUID)) { + syslog(LOG_WARNING, "sendit unauth uid %s%s %s.%s", + notice->z_sender, auth ? "" : " (unauth)", + notice->z_class, notice->z_class_inst); + clt_ack(notice, who, AUTH_FAILED); + free_string(class); + return; + } + } + } + + /* Increment the send counter, used to prevent duplicate sends to + * clients. On the off-chance that we wrap around to 0, skip over + * it to prevent missing clients which have never had a packet + * sent to them. */ + send_counter++; + if (send_counter == 0) + send_counter = 1; + + /* Send to clients subscribed to the triplet itself. */ + dest.classname = class; + dest.inst = make_string(notice->z_class_inst, 1); + if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient) && + *notice->z_recipient == '@') + dest.recip = make_string("", 0); + else { + strncpy(recipbuf, notice->z_recipient, sizeof(recipbuf)); + recipp = strrchr(recipbuf, '@'); + if (recipp) + /* XXX if realm_expand_realm doesn't find a match + * it returns what's passed into it, causing an overlapping + * copy, the results of which are undefined. + */ + strncpy(recipp + 1, realm_expand_realm(recipp + 1), + sizeof(recipbuf) - (recipp - recipbuf) - 1); + dest.recip = make_string(recipbuf, 0); + } + + if (send_to_dest(notice, auth, &dest, send_counter, external)) + any = 1; + + /* Send to clients subscribed to the triplet with the instance + * substituted with the wildcard instance. */ + free_string(dest.inst); + dest.inst = wildcard_instance; + if (send_to_dest(notice, auth, &dest, send_counter, external)) + any = 1; + + free_string(class); + free_string(dest.recip); + if (any) + ack(notice, who); + else + nack(notice, who); +} + +/* + * Send to each client in the list. Avoid duplicates by setting + * last_send on each client to send_counter, a nonce which is updated + * by sendit() above. + */ + +static int +send_to_dest(ZNotice_t *notice, + int auth, + Destination *dest, + int send_counter, + int external) +{ + Client **clientp; + int any = 0; + + clientp = triplet_lookup(dest); + if (!clientp) + return 0; + + for (; *clientp; clientp++) { + if ((*clientp)->last_send == send_counter) + continue; + (*clientp)->last_send = send_counter; + if ((*clientp)->realm) { + if (external) { + realm_handoff(notice, auth, &clientp[0]->addr, clientp[0]->realm, + 1); + any = 1; + } + } else { + xmit(notice, &((*clientp)->addr), auth, *clientp); + any = 1; + } + } + + return any; +} + +/* + * Release anything destined for the client in the not-yet-acked table. + */ + +void +nack_release(Client *client) +{ + int i; + Unacked *nacked, *next; + + for (i = 0; i < NACKTAB_HASHSIZE; i++) { + for (nacked = nacktab[i]; nacked; nacked = next) { + next = nacked->next; + if (nacked->client == client) { + timer_reset(nacked->timer); + Unacked_delete(nacked); + free(nacked->packet); + free(nacked); + } + } + } +} + +/* + * Send one packet of a fragmented message to a client. After transmitting, + * put it onto the not ack'ed list. + */ + +/* the arguments must be the same as the arguments to Z_XmitFragment */ +/*ARGSUSED*/ +Code_t +xmit_frag(ZNotice_t *notice, + char *buf, + int len, + int waitforack) +{ + struct sockaddr_in sin; + char *savebuf; + Unacked *nacked; + Code_t retval; + int sendfail = 0; + + retval = ZSendPacket(buf, len, 0); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "xmit_frag send: %s", error_message(retval)); + if (retval != EAGAIN && retval != ENOBUFS) + return retval; + sendfail = 1; + } + + /* now we've sent it, mark it as not ack'ed */ + nacked = (Unacked *) malloc(sizeof(Unacked)); + if (!nacked) { + /* no space: just punt */ + syslog(LOG_WARNING, "xmit_frag nack malloc"); + return ENOMEM; + } + + savebuf = (char *) malloc(len); + if (!savebuf) { + /* no space: just punt */ + syslog(LOG_WARNING, "xmit_frag pack malloc"); + free(nacked); + return ENOMEM; + } + + memcpy(savebuf, buf, len); + + sin = ZGetDestAddr(); + nacked->client = NULL; + nacked->rexmits = (sendfail) ? -1 : 0; + nacked->packet = savebuf; + nacked->dest.addr = sin; + nacked->packsz = len; + nacked->uid = notice->z_uid; + nacked->timer = timer_set_rel(rexmit_times[0], rexmit, nacked); + Unacked_insert(&nacktab[nacktab_hashval(sin, nacked->uid)], nacked); + return(ZERR_NONE); +} + + +/* + * Send the notice to the client. After transmitting, put it onto the + * not ack'ed list. + */ + +void +xmit(ZNotice_t *notice, + struct sockaddr_in *dest, + int auth, + Client *client) +{ + char *noticepack; + Unacked *nacked; + int packlen, sendfail = 0; + Code_t retval; + + noticepack = (char *) malloc(sizeof(ZPacket_t)); + if (!noticepack) { + syslog(LOG_ERR, "xmit malloc"); + return; /* DON'T put on nack list */ + } + + packlen = sizeof(ZPacket_t); + + if (auth && client) { + /* we are distributing authentic and we have a pointer to auth info */ +#if defined(HAVE_KRB5) + retval = ZFormatAuthenticNoticeV5(notice, noticepack, packlen, + &packlen, client->session_keyblock); +#elif defined(HAVE_KRB4) + retval = ZFormatAuthenticNotice(notice, noticepack, packlen, + &packlen, client->session_key); +#else /* !HAVE_KRB4 */ + notice->z_auth = 1; + retval = ZFormatSmallRawNotice(notice, noticepack, &packlen); +#endif /* HAVE_KRB4 */ + if (retval != ZERR_NONE) + syslog(LOG_ERR, "xmit auth/raw format: %s", error_message(retval)); + } else { + notice->z_auth = 0; + notice->z_authent_len = 0; + notice->z_ascii_authent = (char *)""; + retval = ZFormatSmallRawNotice(notice, noticepack, &packlen); + /* This code is needed because a Zephyr can "grow" when a remote + * realm name is inserted into the Zephyr before being resent out + * locally. It essentially matches the code in realm.c to do the + * same thing with authentic Zephyrs. + */ + if (retval == ZERR_PKTLEN) { + char multi[64]; + int hdrlen, message_len; + ZPacket_t the_packet; + char *buffer = (char *)&the_packet; + ZNotice_t partnotice = *notice; + int offset = 0; + int fragsize = 0; + int origoffset = 0; + int origlen = notice->z_message_len; + + free(noticepack); + + retval = ZSetDestAddr(dest); + if (retval) { + syslog(LOG_WARNING, "xmit: ZSetDestAddr: %s", error_message(retval)); + return; + } + + partnotice.z_auth = 0; + partnotice.z_authent_len = 0; + partnotice.z_ascii_authent = (char *)""; + + retval = Z_FormatRawHeader(&partnotice, buffer, sizeof(ZPacket_t), + &hdrlen, NULL, NULL); + if (retval) { + syslog(LOG_ERR, "xmit unauth refrag: Z_FormatRawHeader: %s", + error_message(retval)); + return; + } + + if (notice->z_multinotice && strcmp(notice->z_multinotice, "")) { + if (sscanf(notice->z_multinotice, "%d/%d", + &origoffset, &origlen) != 2) { + syslog(LOG_WARNING, + "xmit unauth refrag: multinotice parse failed"); + return; + } + } + + fragsize = Z_MAXPKTLEN - hdrlen - Z_FRAGFUDGE; + + if (fragsize < 0) { + syslog(LOG_ERR, + "xmit unauth refrag: negative fragsize, dropping packet"); + return; + } + + while (offset < notice->z_message_len || !notice->z_message_len) { + (void) sprintf(multi, "%d/%d", offset+origoffset, origlen); + partnotice.z_multinotice = multi; + if (offset > 0) { + (void) Z_gettimeofday(&partnotice.z_uid.tv, (struct timezone *)0); + partnotice.z_uid.tv.tv_sec = htonl((u_long) + partnotice.z_uid.tv.tv_sec); + partnotice.z_uid.tv.tv_usec = htonl((u_long) + partnotice.z_uid.tv.tv_usec); + (void) memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, + sizeof(__My_addr)); + partnotice.z_sender_sockaddr.ip4.sin_family = AF_INET; /* XXX */ + (void) memcpy((char *)&partnotice.z_sender_sockaddr.ip4.sin_addr, + &__My_addr, sizeof(__My_addr)); + } + partnotice.z_message = notice->z_message + offset; + message_len = min(notice->z_message_len-offset, fragsize); + partnotice.z_message_len = message_len; + + retval = Z_FormatRawHeader(&partnotice, buffer, sizeof(ZPacket_t), + &hdrlen, NULL, NULL); + if (retval) { + syslog(LOG_WARNING, "xmit unauth refrag: Z_FormatRawHeader: %s", + error_message(retval)); + return; + } + + (void) memcpy(buffer + hdrlen, partnotice.z_message, + partnotice.z_message_len); + + xmit_frag(&partnotice, buffer, hdrlen + partnotice.z_message_len, 0); + + offset += fragsize; + + if (!notice->z_message_len) + break; + } + return; + } + /* End of refrag code */ + + if (retval) + syslog(LOG_ERR, "xmit unauth: ZFormatSmallRawNotice: %s", + error_message(retval)); + } + if (!retval) { + retval = ZSetDestAddr(dest); + if (retval) + syslog(LOG_WARNING, "xmit: ZSetDestAddr: %s", error_message(retval)); + } + if (!retval) { + retval = ZSendPacket(noticepack, packlen, 0); + if (retval) { + syslog(LOG_WARNING, "xmit: ZSendPacket: (%s/%d) %s", + inet_ntoa(dest->sin_addr), ntohs(dest->sin_port), + error_message(retval)); + if (retval == EAGAIN || retval == ENOBUFS) { + retval = ZERR_NONE; + sendfail = 1; + } + } + } + + /* now we've sent it, mark it as not ack'ed */ + if (!retval) { + nacked = (Unacked *) malloc(sizeof(Unacked)); + if (!nacked) { + /* no space: just punt */ + syslog(LOG_WARNING, "xmit nack malloc"); + retval = ENOMEM; + } + } + + if (!retval) { + nacked->client = client; + nacked->rexmits = (sendfail) ? -1 : 0; + nacked->packet = noticepack; + nacked->dest.addr = *dest; + nacked->packsz = packlen; + nacked->uid = notice->z_uid; + nacked->timer = timer_set_rel(rexmit_times[0], rexmit, nacked); + Unacked_insert(&nacktab[nacktab_hashval(*dest, nacked->uid)], nacked); + } + if (retval) + free(noticepack); +} + +/* + * Retransmit the packet specified. If we have timed out or retransmitted + * too many times, punt the packet and initiate the host recovery algorithm + * Else, increment the count and re-send the notice packet. + */ + +void +rexmit(void *arg) +{ + Unacked *nacked = (Unacked *) arg; + int retval; + + syslog(LOG_DEBUG, "rexmit %s/%d #%d time %d", + inet_ntoa(nacked->dest.addr.sin_addr), + ntohs(nacked->dest.addr.sin_port), nacked->rexmits + 1, (int)NOW); + + nacked->rexmits++; + if (rexmit_times[nacked->rexmits] == -1) { + if (!nacked->client + || NOW - nacked->client->last_ack >= CLIENT_GIVEUP_MIN) { + /* The client (if there was one) has been unresponsive. + * Give up sending this packet, and kill the client if + * there was one. (Make sure to remove nacked from the + * nack list before calling client_deregister(), which + * scans the nack list.) + */ + Unacked_delete(nacked); + if (nacked->client) { + server_kill_clt(nacked->client); + client_deregister(nacked->client, 1); + } + free(nacked->packet); + free(nacked); + return; + } else { + /* The client has sent us an ack recently. Retry with the maximum + * retransmit time. */ + nacked->rexmits--; + } + } + + /* retransmit the packet */ + retval = ZSetDestAddr(&nacked->dest.addr); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "rexmit set addr: %s", error_message(retval)); + } else { + retval = ZSendPacket(nacked->packet, nacked->packsz, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "rexmit xmit: %s", error_message(retval)); + if (retval == EAGAIN || retval == ENOBUFS) + nacked->rexmits--; + } + + /* reset the timer */ + nacked->timer = timer_set_rel(rexmit_times[nacked->rexmits], rexmit, + nacked); + return; +} + +/* + * Send an acknowledgement to the sending client, by sending back the + * header from the original notice with the z_kind field changed to either + * SERVACK or SERVNAK, and the contents of the message either SENT or + * NOT_SENT, depending on the value of the sent argument. + */ + +void +clt_ack(ZNotice_t *notice, + struct sockaddr_in *who, + Sent_type sent) +{ + ZNotice_t acknotice; + ZPacket_t ackpack; + int packlen; + Code_t retval; + + if (bdumping) { /* don't ack while dumping */ + zdbug((LOG_DEBUG,"bdumping, no ack")); + return; + } + + acknotice = *notice; + + acknotice.z_kind = SERVACK; + switch (sent) { + case SENT: + acknotice.z_message = ZSRVACK_SENT; + break; + case NOT_FOUND: + acknotice.z_message = ZSRVACK_FAIL; + acknotice.z_kind = SERVNAK; + break; + case AUTH_FAILED: + acknotice.z_kind = SERVNAK; + acknotice.z_message = ZSRVACK_NOTSENT; + break; + case NOT_SENT: + acknotice.z_message = ZSRVACK_NOTSENT; + break; + default: + abort (); + } + + acknotice.z_multinotice = ""; + + /* leave room for the trailing null */ + acknotice.z_message_len = strlen(acknotice.z_message) + 1; + + packlen = sizeof(ackpack); + + retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen); + + if (retval == ZERR_HEADERLEN) { + /* Since an ack header can be larger than a message header... (crock) */ + acknotice.z_opcode = ""; + acknotice.z_class = ""; + acknotice.z_class_inst = ""; + acknotice.z_opcode = ""; + acknotice.z_default_format = ""; + + retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen); + } + + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "clt_ack format: %s", error_message(retval)); + return; + } + retval = ZSetDestAddr(who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "clt_ack set addr: %s", error_message(retval)); + return; + } + retval = ZSendPacket(ackpack, packlen, 0); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "clt_ack xmit: %s", error_message(retval)); + return; + } else { + zdbug((LOG_DEBUG, "packet sent")); + } + return; +} + +/* + * An ack has arrived. + * remove the packet matching this notice from the not-yet-acked queue + */ + +static void +nack_cancel(ZNotice_t *notice, + struct sockaddr_in *who) +{ + Unacked *nacked; + int hashval; + + /* search the not-yet-acked table for this packet, and flush it. */ + hashval = nacktab_hashval(*who, notice->z_uid); + for (nacked = nacktab[hashval]; nacked; nacked = nacked->next) { + if (nacked->dest.addr.sin_addr.s_addr == who->sin_addr.s_addr + && nacked->dest.addr.sin_port == who->sin_port + && ZCompareUID(&nacked->uid, ¬ice->z_uid)) { + if (nacked->client) + nacked->client->last_ack = NOW; + timer_reset(nacked->timer); + free(nacked->packet); + Unacked_delete(nacked); + free(nacked); + return; + } + } + + zdbug((LOG_DEBUG,"nack_cancel: nack not found %s:%08X,%08X", + inet_ntoa (notice->z_uid.zuid_addr), + notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); +} + +/* Dispatch an HM_CTL notice. */ + +Code_t +hostm_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + char *opcode = notice->z_opcode; + int i, add_it = 0, remove_it = 0; + + if (notice->z_kind == HMACK) { + /* Ignore. */ + ; + } else if (notice->z_kind != HMCTL) { + clt_ack(notice, who, AUTH_FAILED); + } else if (strcmp(opcode, HM_FLUSH) == 0) { + client_flush_host(&who->sin_addr); + if (server == me_server) + server_forward(notice, auth, who); + } else if (strcmp(opcode, HM_BOOT) == 0) { + client_flush_host(&who->sin_addr); + if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + add_it = 1; + } + } else if (strcmp(opcode, HM_ATTACH) == 0) { + if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + add_it = 1; + } else { + remove_it = 1; + } + } else if (strcmp(opcode, HM_DETACH) == 0) { + remove_it = 1; + } else { + syslog(LOG_WARNING, "hm_dispatch: unknown opcode %s", opcode); + } + + if (add_it) { + for (i = 0; i < num_hosts; i++) { + if (hosts[i].s_addr == who->sin_addr.s_addr) + break; + } + if (i == num_hosts) { + if (hosts_size == 0) { + hosts = (struct in_addr *) malloc(HOSTS_SIZE_INIT * + sizeof(struct in_addr)); + if (!hosts) + return ENOMEM; + hosts_size = HOSTS_SIZE_INIT; + } else if (num_hosts == hosts_size) { + hosts = (struct in_addr *) realloc(hosts, hosts_size * 2 * + sizeof(struct in_addr)); + if (!hosts) + return ENOMEM; + hosts_size *= 2; + } + hosts[num_hosts++] = who->sin_addr; + } + } else if (remove_it) { + for (i = 0; i < num_hosts; i++) { + if (hosts[i].s_addr == who->sin_addr.s_addr) { + memmove(&hosts[i], &hosts[i + 1], num_hosts - (i + 1)); + num_hosts--; + break; + } + } + } + return ZERR_NONE; +} + +/* + * Dispatch a ZEPHYR_CTL notice. + */ + +Code_t +control_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + char *target, *opcode = notice->z_opcode; + Client *client; + Code_t retval; + int wantdefs; + ZRealm *realm; + struct sockaddr_in newwho; + + /* + * ZEPHYR_CTL Opcodes expected are: + * BOOT (inst HM): host has booted; flush data. + * CLIENT_SUBSCRIBE: process with the subscription mananger. + * CLIENT_UNSUBSCRIBE: "" + * CLIENT_CANCELSUB: "" + */ + + zdbug((LOG_DEBUG, "ctl_disp: opc=%s", opcode)); + + notice_extract_address(notice, &newwho); + realm = realm_which_realm(&newwho); + if (realm) + return(realm_control_dispatch(notice, auth, who, server, realm)); + + if (strcasecmp(notice->z_class_inst, ZEPHYR_CTL_HM) == 0) { + return hostm_dispatch(notice, auth, who, server); + } else if (strcmp(opcode, CLIENT_GIMMESUBS) == 0 || + strcmp(opcode, CLIENT_GIMMEDEFS) == 0) { + /* this special case is before the auth check so that + someone who has no subscriptions does NOT get a SERVNAK + but rather an empty list. Note we must therefore + check authentication inside subscr_sendlist */ + ack(notice, who); + subscr_sendlist(notice, auth, who); + return ZERR_NONE; + } else if (!auth) { + syslog(LOG_INFO, "unauthenticated %s message purportedly from %s", + opcode, notice->z_sender); + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + + wantdefs = strcmp(opcode, CLIENT_SUBSCRIBE_NODEFS); + if (!wantdefs || strcmp(opcode, CLIENT_SUBSCRIBE) == 0) { + /* subscription notice */ + retval = client_register(notice, &who->sin_addr, &client, wantdefs); + if (retval != ZERR_NONE) { + syslog(LOG_NOTICE, "subscr %s/%s/%d failed: %s", + notice->z_sender, inet_ntoa(who->sin_addr), + ntohs(notice->z_port), error_message(retval)); + if (server == me_server) { + if (retval == ZSRV_BADSUBPORT) + clt_ack(notice, who, AUTH_FAILED); + else + nack(notice, who); + } + return(ZERR_NONE); + } + if (strcmp(client->principal->string, notice->z_sender) != 0) { + /* you may only subscribe for your own clients */ + syslog(LOG_NOTICE, + "subscr request from %s on port used by %s (%s.%d)", + notice->z_sender, client->principal->string, + inet_ntoa(who->sin_addr), ntohs(notice->z_port)); /* XXX */ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } +#ifdef HAVE_KRB5 + if (client->session_keyblock) { + krb5_free_keyblock_contents(Z_krb5_ctx, client->session_keyblock); + retval = krb5_copy_keyblock_contents(Z_krb5_ctx, ZGetSession(), + client->session_keyblock); + } else { + retval = krb5_copy_keyblock(Z_krb5_ctx, ZGetSession(), + &client->session_keyblock); + } + if (retval) { + syslog(LOG_WARNING, "keyblock copy failed in subscr: %s", + error_message(retval)); + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } +#else +#ifdef HAVE_KRB4 + /* in case it's changed */ + memcpy(client->session_key, ZGetSession(), sizeof(C_Block)); +#endif +#endif + retval = subscr_subscribe(client, notice, server); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "subscr failed: %s", error_message(retval)); + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + } else if (strcmp(opcode, CLIENT_UNSUBSCRIBE) == 0) { + client = client_find(&who->sin_addr, notice->z_port); + if (client != NULL) { + if (strcmp(client->principal->string, notice->z_sender) != 0) { + /* you may only cancel for your own clients */ + syslog(LOG_NOTICE, + "unsubscr request from %s on port used by %s (%s.%d)", + notice->z_sender, client->principal->string, + inet_ntoa(who->sin_addr), ntohs(notice->z_port)); /*XXX*/ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + subscr_cancel(who, notice); + } else { + nack(notice, who); + return ZERR_NONE; + } + } else if (strcmp(opcode, CLIENT_CANCELSUB) == 0) { + /* canceling subscriptions implies I can punt info about this client */ + client = client_find(&who->sin_addr, notice->z_port); + if (client == NULL) { + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + if (strcmp(client->principal->string, notice->z_sender) != 0) { + /* you may only cancel for your own clients */ + syslog(LOG_NOTICE, + "cancel request from %s on port used by %s (%s.%d)", + notice->z_sender, client->principal->string, + inet_ntoa(who->sin_addr), ntohs(notice->z_port)); /* XXX */ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + /* don't flush locations here, let him do it explicitly */ + client_deregister(client, 0); + } else if (strcmp(opcode, CLIENT_FLUSHSUBS) == 0) { + target = notice->z_sender; + if (notice->z_message_len > 0 && *notice->z_message != 0) { + target = notice->z_message; + if (memchr(target, '\0', notice->z_message_len) == NULL) { + syslog(LOG_WARNING, "malformed flushsubs"); + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + if (strcmp(target, notice->z_sender) != 0 && + !opstaff_check(notice->z_sender)) { + syslog(LOG_NOTICE, "unauth flushsubs for %s by %s", + target, notice->z_sender); + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + } + client_flush_princ(target); + } else { + syslog(LOG_WARNING, "unknown ctl opcode %s", opcode); + if (server == me_server) { + if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM) != 0) + nack(notice, who); + } + return ZERR_NONE; + } + + if (server == me_server) { + ack(notice, who); + server_forward(notice, auth, who); + } + return ZERR_NONE; +} + +void +hostm_shutdown(void) +{ + int i, s, newserver; + struct sockaddr_in sin; + + for (i = 0; i < nservers; i++) { + if (i != me_server_idx && otherservers[i].state == SERV_UP) + break; + } + newserver = (i < nservers); + sin.sin_family = AF_INET; + for (i = 0; i < num_hosts; i++) { + sin.sin_addr = hosts[i]; + sin.sin_port = hm_port; + if (newserver) { + while (1) { + s = (random() % (nservers - 1)) + 1; + if (otherservers[s].state == SERV_UP) + break; + } + hostm_deathgram(&sin, &otherservers[s]); + } else { + hostm_deathgram(&sin, NULL); + } + } +} + +void +realm_shutdown(void) +{ + int i, s, newserver; + + for (i = 0; i < nservers; i++) { + if (i != me_server_idx && otherservers[i].state == SERV_UP) + break; + } + zdbug((LOG_DEBUG, "rlm_shutdown")); + + newserver = (i < nservers); + if (newserver) { + while (1) { + s = (random() % (nservers - 1)) + 1; + if (otherservers[s].state == SERV_UP) + break; + } + realm_deathgram(&otherservers[s]); + } else { + realm_deathgram(NULL); + } +} + +static void +hostm_deathgram(struct sockaddr_in *sin, + Server *server) +{ + Code_t retval; + int shutlen; + ZNotice_t shutnotice; + char *shutpack; + + memset (&shutnotice, 0, sizeof(shutnotice)); + + shutnotice.z_kind = HMCTL; + shutnotice.z_port = sin->sin_port; /* we are sending it */ + shutnotice.z_class = HM_CTL_CLASS; + shutnotice.z_class_inst = HM_CTL_SERVER; + shutnotice.z_opcode = SERVER_SHUTDOWN; + shutnotice.z_sender = HM_CTL_SERVER; + shutnotice.z_recipient = hm_recipient(); + shutnotice.z_default_format = ""; + shutnotice.z_num_other_fields = 0; + shutnotice.z_message = (server) ? server->addr_str : NULL; + shutnotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0; + + retval = ZFormatNotice(&shutnotice, &shutpack, &shutlen, ZNOAUTH); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "hm_shut format: %s",error_message(retval)); + return; + } + retval = ZSetDestAddr(sin); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "hm_shut set addr: %s", error_message(retval)); + free(shutpack); + return; + } + retval = ZSendPacket(shutpack, shutlen, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "hm_shut xmit: %s", error_message(retval)); + free(shutpack); +} + +static char * +hm_recipient(void) +{ + static char *recipient; + char *realm; + + if (recipient) + return recipient; + + realm = (char *)ZGetRealm(); + if (!realm) + realm = "???"; + recipient = (char *) malloc(strlen(realm) + 4); + strcpy (recipient, "hm@"); + strcat (recipient, realm); + return recipient; +} diff --git a/server/global.c b/server/global.c new file mode 100644 index 0000000..5199f7b --- /dev/null +++ b/server/global.c @@ -0,0 +1,75 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the global variables used by the server. (moved from main.c) + * + * Created by: Karl Ramm + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include +#include + +int nfds; /* max file descriptor for select() */ +int srv_socket; /* dgram socket for clients + and other servers */ +int bdump_socket = -1; /* brain dump socket fd + (closed most of the time) */ +#ifdef HAVE_ARES +ares_channel achannel; /* C-ARES resolver channel */ +#endif +fd_set interesting; /* the file descrips we are listening + to right now */ +struct sockaddr_in srv_addr; /* address of the socket */ + +Unacked *nacklist = NULL; /* list of packets waiting for ack's */ + +unsigned short hm_port; /* host manager receiver port */ +unsigned short hm_srv_port; /* host manager server sending port */ + +char myname[NS_MAXDNAME]; /* my host name */ + +char list_file[128]; +#ifdef HAVE_KRB5 +char keytab_file[128]; +#endif +#ifdef HAVE_KRB4 +char srvtab_file[128]; +#endif +char acl_dir[128]; +char subs_file[128]; + +int zdebug; +#ifdef DEBUG +int zalone; +#endif + +struct timeval t_local; /* store current time for other uses */ + + +u_long npackets; /* number of packets processed */ +time_t uptime; /* when we started operations */ +struct in_addr my_addr; +char *bdump_version = "1.2"; + +#ifdef HAVE_KRB5 +int bdump_auth_proto = 5; +#else /* HAVE_KRB5 */ +#ifdef HAVE_KRB4 +int bdump_auth_proto = 4; +#else /* HAVE_KRB4 */ +int bdump_auth_proto = 0; +#endif /* HAVE_KRB4 */ +#endif /* HAVE_KRB5 */ + +#ifdef HAVE_KRB5 +krb5_ccache Z_krb5_ccache; +krb5_keyblock *__Zephyr_keyblock; +#else +#ifdef HAVE_KRB4 +C_Block __Zephyr_session; +#endif +#endif diff --git a/server/kstuff.c b/server/kstuff.c new file mode 100644 index 0000000..5e4cf87 --- /dev/null +++ b/server/kstuff.c @@ -0,0 +1,755 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for dealing with Kerberos functions in the server. + * + * Created by: John T Kohl + * + * Copyright (c) 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ +/* + * $Source$ + * $Header$ + */ + +#include "zserver.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_kstuff_c[] = "$Id$"; +#endif +#endif + +#if defined(HAVE_KRB4) && defined(HAVE_KRB5) +static Code_t ZCheckAuthentication4(ZNotice_t *notice, struct sockaddr_in *from); +#endif +#ifdef HAVE_KRB5 +static ZChecksum_t compute_checksum(ZNotice_t *, unsigned char *); +static ZChecksum_t compute_rlm_checksum(ZNotice_t *, unsigned char *); +#endif + +#ifdef HAVE_KRB4 +/* + * GetKerberosData + * + * get ticket from file descriptor and decode it. + * Return KFAILURE if we barf on reading the ticket, else return + * the value of rd_ap_req() applied to the ticket. + */ +int +GetKerberosData(int fd, /* file descr. to read from */ + struct in_addr haddr, /* address of foreign host on fd */ + AUTH_DAT *kdata, /* kerberos data (returned) */ + char *service, /* service principal desired */ + char *srvtab) /* file to get keys from */ +{ + char p[20]; + KTEXT_ST ticket; /* will get Kerberos ticket from client */ + unsigned int i; + char instance[INST_SZ]; + + /* + * Get the Kerberos ticket. The first few characters, terminated + * by a blank, should give us a length; then get than many chars + * which will be the ticket proper. + */ + for (i=0; i<20; i++) { + if (read(fd, &p[i], 1) != 1) { + syslog(LOG_WARNING,"bad read tkt len"); + return(KFAILURE); + } + if (p[i] == ' ') { + p[i] = '\0'; + break; + } + } + ticket.length = atoi(p); + if ((i==20) || (ticket.length<=0) || (ticket.length>MAX_KTXT_LEN)) { + syslog(LOG_WARNING,"bad tkt len %d",ticket.length); + return(KFAILURE); + } + for (i=0; ilength); + size_to_write = strlen (p); + if ((written = write(fd, p, size_to_write)) != size_to_write) + return ((ssize_t)written < 0) ? errno : ZSRV_PKSHORT; + if ((written = write(fd, ticket->dat, ticket->length)) + != ticket->length) + return ((ssize_t)written < 0) ? errno : ZSRV_PKSHORT; + + return 0; +} + +#endif /* HAVE_KRB4 */ + +#if defined(HAVE_KRB5) || defined(HAVE_KRB4) +Code_t +ReadKerberosData(int fd, int *size, char **data, int *proto) { + char p[20]; + int i; + char *dst; + int len = 0; + + for (i=0; i<20; i++) { + if (read(fd, &p[i], 1) != 1) { + p[i] = 0; + syslog(LOG_WARNING,"ReadKerberosData: bad read reply len @%d (got \"%s\"", i, p); + return ZSRV_LEN; + } + if (p[i] == ' ') { + p[i] = '\0'; + break; + } + } + + if (i == 20) { + syslog(LOG_WARNING, "ReadKerberosData: read reply len exceeds buffer"); + return ZSRV_BUFSHORT; + } + + if (!strncmp(p, "V5-", 3) && (len = atoi(p+3)) > 0) + *proto = 5; + else if ((len = atoi(p)) > 0) + *proto = 4; + + if ((*proto < 4) | (*proto > 5)) { + syslog(LOG_WARNING, "ReadKerberosData: error parsing authenticator length (\"%s\")", p); + return ZSRV_LEN; + } + + if (len <= 0) { + syslog(LOG_WARNING, "ReadKerberosData: read reply len = %d", len); + return ZSRV_LEN; + } + + *data = malloc(len); + if (! *data) { + syslog(LOG_WARNING, "ReadKerberosData: failure allocating %d bytes: %m", len); + return errno; + } + + dst=*data; + for (i=0; i < len; i++) { + if (read(fd, dst++, 1) != 1) { + free(*data); + *data = NULL; + *size = 0; + syslog(LOG_WARNING,"ReadKerberosData: bad read reply string"); + return ZSRV_PKSHORT; + } + } + *size = len; + return 0; +} +#endif + +#ifdef HAVE_KRB5 +Code_t +GetKrb5Data(int fd, krb5_data *data) { + char p[20]; + unsigned int i; + char *dst; + + for (i=0; i<20; i++) { + if (read(fd, &p[i], 1) != 1) { + p[i] = 0; + syslog(LOG_WARNING,"bad read reply len @%d (got \"%s\")", i, p); + return ZSRV_LEN; + } + if (p[i] == ' ') { + p[i] = '\0'; + break; + } + } + if (i == 20 || strncmp(p, "V5-", 3) || !atoi(p+3)) { + syslog(LOG_WARNING,"bad reply len"); + return ZSRV_LEN; + } + data->length = atoi(p+3); + data->data = malloc(data->length); + if (! data->data) { + data->length = 0; + return errno; + } + dst=data->data; + for (i=0; i < data->length; i++) { + if (read(fd, dst++, 1) != 1) { + free(data->data); + memset((char *)data, 0, sizeof(krb5_data)); + syslog(LOG_WARNING,"bad read reply string"); + return ZSRV_PKSHORT; + } + } + return 0; +} + +Code_t +SendKrb5Data(int fd, krb5_data *data) { + char p[32]; + size_t written, size_to_write; + sprintf(p, "V5-%lu ", (unsigned long)data->length); + size_to_write = strlen (p); + if (size_to_write != (written = write(fd, p, size_to_write)) || + data->length != (written = write(fd, data->data, data->length))) { + return ((ssize_t)written < 0) ? errno : ZSRV_PKSHORT; + } + return 0; +} +#endif + +Code_t +ZCheckSrvAuthentication(ZNotice_t *notice, + struct sockaddr_in *from, + char *realm) +{ +#ifdef HAVE_KRB5 + unsigned char *authbuf; + krb5_principal princ; + krb5_data packet; + krb5_ticket *tkt; + char *name; + krb5_error_code result; + krb5_principal server; + krb5_keytab keytabid = 0; + krb5_auth_context authctx; + krb5_keyblock *keyblock; + krb5_enctype enctype; + krb5_cksumtype cksumtype; + krb5_data cksumbuf; + int valid; + char *cksum0_base, *cksum1_base = NULL, *cksum2_base; + char *x; + unsigned char *asn1_data, *key_data, *cksum_data; + int asn1_len, key_len, cksum0_len = 0, cksum1_len = 0, cksum2_len = 0; + KRB5_AUTH_CON_FLAGS_TYPE acflags; +#ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER + krb5_authenticator *authenticator; +#define KRB5AUTHENT authenticator +#else + krb5_authenticator authenticator; +#define KRB5AUTHENT &authenticator +#endif + int len; + char *sender; + char rlmprincipal[MAX_PRINCIPAL_SIZE]; + + if (!notice->z_auth) + return ZAUTH_NO; + + /* Check for bogus authentication data length. */ + if (notice->z_authent_len <= 0) { + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: bogus authenticator length"); + return ZAUTH_FAILED; + } + +#ifdef HAVE_KRB4 + if (notice->z_ascii_authent[0] != 'Z' && realm == NULL) + return ZCheckAuthentication4(notice, from); +#endif + + len = strlen(notice->z_ascii_authent)+1; + authbuf = malloc(len); + + /* Read in the authentication data. */ + if (ZReadZcode((unsigned char *)notice->z_ascii_authent, + authbuf, + len, &len) == ZERR_BADFIELD) { + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: ZReadZcode: Improperly formatted field"); + return ZAUTH_FAILED; + } + + if (realm == NULL) { + sender = notice->z_sender; + } else { + (void) snprintf(rlmprincipal, MAX_PRINCIPAL_SIZE, "%s/%s@%s", SERVER_SERVICE, + SERVER_INSTANCE, realm); + sender = rlmprincipal; + } + + packet.length = len; + packet.data = (char *)authbuf; + + result = krb5_kt_resolve(Z_krb5_ctx, + keytab_file, &keytabid); + if (result) { + free(authbuf); + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_kt_resolve: %s", error_message(result)); + return ZAUTH_FAILED; + } + + /* HOLDING: authbuf, keytabid */ + /* Create the auth context */ + result = krb5_auth_con_init(Z_krb5_ctx, &authctx); + if (result) { + krb5_kt_close(Z_krb5_ctx, keytabid); + free(authbuf); + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_init: %s", error_message(result)); + return ZAUTH_FAILED; + } + + /* HOLDING: authbuf, keytabid, authctx */ + result = krb5_auth_con_getflags(Z_krb5_ctx, authctx, &acflags); + if (result) { + krb5_auth_con_free(Z_krb5_ctx, authctx); + krb5_kt_close(Z_krb5_ctx, keytabid); + free(authbuf); + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_getflags: %s", error_message(result)); + return ZAUTH_FAILED; + } + + acflags &= ~KRB5_AUTH_CONTEXT_DO_TIME; + + result = krb5_auth_con_setflags(Z_krb5_ctx, authctx, acflags); + if (result) { + krb5_auth_con_free(Z_krb5_ctx, authctx); + krb5_kt_close(Z_krb5_ctx, keytabid); + free(authbuf); + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_setflags: %s", error_message(result)); + return ZAUTH_FAILED; + } + + result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm), + __Zephyr_realm, SERVER_SERVICE, + SERVER_INSTANCE, NULL); + if (!result) { + result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server, + keytabid, NULL, &tkt); + krb5_free_principal(Z_krb5_ctx, server); + } + krb5_kt_close(Z_krb5_ctx, keytabid); + + /* HOLDING: authbuf, authctx */ + if (result) { + if (result == KRB5KRB_AP_ERR_REPEAT) + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: k5 auth failed: %s", + error_message(result)); + else + syslog(LOG_WARNING,"ZCheckSrvAuthentication: k5 auth failed: %s", + error_message(result)); + free(authbuf); + krb5_auth_con_free(Z_krb5_ctx, authctx); + return ZAUTH_FAILED; + } + + /* HOLDING: authbuf, authctx, tkt */ + + if (tkt == 0 || !Z_tktprincp(tkt)) { + if (tkt) + krb5_free_ticket(Z_krb5_ctx, tkt); + free(authbuf); + krb5_auth_con_free(Z_krb5_ctx, authctx); + syslog(LOG_WARNING, "ZCheckSrvAuthentication: No Ticket"); + return ZAUTH_FAILED; + } + + princ = Z_tktprinc(tkt); + + if (princ == 0) { + krb5_free_ticket(Z_krb5_ctx, tkt); + free(authbuf); + krb5_auth_con_free(Z_krb5_ctx, authctx); + syslog(LOG_WARNING, "ZCheckSrvAuthentication: No... Ticket?"); + return ZAUTH_FAILED; + } + + /* HOLDING: authbuf, authctx, tkt */ + result = krb5_unparse_name(Z_krb5_ctx, princ, &name); + if (result) { + syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_unparse_name failed: %s", + error_message(result)); + free(authbuf); + krb5_auth_con_free(Z_krb5_ctx, authctx); + krb5_free_ticket(Z_krb5_ctx, tkt); + return ZAUTH_FAILED; + } + + krb5_free_ticket(Z_krb5_ctx, tkt); + + /* HOLDING: authbuf, authctx, name */ + if (strcmp(name, sender)) { + syslog(LOG_WARNING, "ZCheckSrvAuthentication: name mismatch: '%s' vs '%s'", + name, sender); + krb5_auth_con_free(Z_krb5_ctx, authctx); +#ifdef HAVE_KRB5_FREE_UNPARSED_NAME + krb5_free_unparsed_name(Z_krb5_ctx, name); +#else + free(name); +#endif + free(authbuf); + return ZAUTH_FAILED; + } +#ifdef HAVE_KRB5_FREE_UNPARSED_NAME + krb5_free_unparsed_name(Z_krb5_ctx, name); +#else + free(name); +#endif + free(authbuf); + + /* HOLDING: authctx */ + /* Get an authenticator so we can get the keyblock */ + result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx, + &authenticator); + if (result) { + krb5_auth_con_free(Z_krb5_ctx, authctx); + syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getauthenticator failed: %s", + error_message(result)); + return ZAUTH_FAILED; + } + + /* HOLDING: authctx, authenticator */ + result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock); + krb5_auth_con_free(Z_krb5_ctx, authctx); + krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT); + if (result) { + syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getkey failed: %s", + error_message(result)); + return (ZAUTH_FAILED); + } + + /* HOLDING: keyblock */ + /* Figure out what checksum type to use */ + key_data = Z_keydata(keyblock); + key_len = Z_keylen(keyblock); + result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype); + if (result) { + krb5_free_keyblock(Z_krb5_ctx, keyblock); + syslog(LOG_WARNING, "ZCheckSrvAuthentication: Z_ExtractEncCksum failed: %s", + error_message(result)); + return (ZAUTH_FAILED); + } + /* HOLDING: keyblock */ + + if (realm == NULL) + ZSetSession(keyblock); + + /* Assemble the things to be checksummed */ + /* first part is from start of packet through z_default_format: + * - z_version + * - z_num_other_fields + * - z_kind + * - z_uid + * - z_port + * - z_auth + * - z_authent_len + * - z_ascii_authent + * - z_class + * - z_class_inst + * - z_opcode + * - z_sender + * - z_recipient + * - z_default_format + */ + cksum0_base = notice->z_packet; + x = notice->z_default_format; + cksum0_len = x + strlen(x) + 1 - cksum0_base; + /* second part is from z_multinotice through other fields: + * - z_multinotice + * - z_multiuid + * - z_sender_(sock)addr + * - z_charset + * - z_other_fields[] + */ + if (notice->z_num_hdr_fields > 15 ) { + cksum1_base = notice->z_multinotice; + if (notice->z_num_other_fields) + x = notice->z_other_fields[notice->z_num_other_fields - 1]; + else { + /* see lib/ZCkZaut.c:ZCheckZcodeAuthentication */ + /* XXXXXXXXXXXXXXXXXXXXXXX */ + if (notice->z_num_hdr_fields > 16) + x = cksum1_base + strlen(cksum1_base) + 1; /* multinotice */ + if (notice->z_num_hdr_fields > 17) + x = x + strlen(x) + 1; /* multiuid */ + if (notice->z_num_hdr_fields > 18) + x = x + strlen(x) + 1; /* sender */ + } + cksum1_len = x + strlen(x) + 1 - cksum1_base; /* charset / extra field */ + } + + /* last part is the message body */ + cksum2_base = notice->z_message; + cksum2_len = notice->z_message_len; + + /*XXX we may wish to ditch this code someday?*/ + if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') && + key_len == 8 && + (enctype == (krb5_enctype)ENCTYPE_DES_CBC_CRC || + enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD4 || + enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD5)) { + /* try old-format checksum (covers cksum0 only) */ + + ZChecksum_t our_checksum; + + if (realm == NULL) + our_checksum = compute_checksum(notice, key_data); + else + our_checksum = compute_rlm_checksum(notice, key_data); + + krb5_free_keyblock(Z_krb5_ctx, keyblock); + + if (our_checksum == notice->z_checksum) { + return ZAUTH_YES; + } else { + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: des quad checksum mismatch"); + return ZAUTH_FAILED; + } + } + + /* HOLDING: keyblock */ + + cksumbuf.length = cksum0_len + cksum1_len + cksum2_len; + cksumbuf.data = malloc(cksumbuf.length); + if (!cksumbuf.data) { + krb5_free_keyblock(Z_krb5_ctx, keyblock); + syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(cksumbuf.data): %m"); + return ZAUTH_FAILED; + } + /* HOLDING: keyblock, cksumbuf.data */ + + cksum_data = (unsigned char *)cksumbuf.data; + memcpy(cksum_data, cksum0_base, cksum0_len); + if (cksum1_len) + memcpy(cksum_data + cksum0_len, cksum1_base, cksum1_len); + memcpy(cksum_data + cksum0_len + cksum1_len, + cksum2_base, cksum2_len); + + /* decode zcoded checksum */ + /* The encoded form is always longer than the original */ + asn1_len = strlen(notice->z_ascii_checksum) + 1; + asn1_data = malloc(asn1_len); + if (!asn1_data) { + krb5_free_keyblock(Z_krb5_ctx, keyblock); + free(cksumbuf.data); + syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(asn1_data): %m"); + return ZAUTH_FAILED; + } + /* HOLDING: keyblock, cksumbuf.data, asn1_data */ + result = ZReadZcode((unsigned char *)notice->z_ascii_checksum, + asn1_data, asn1_len, &asn1_len); + if (result != ZERR_NONE) { + krb5_free_keyblock(Z_krb5_ctx, keyblock); + free(asn1_data); + free(cksumbuf.data); + syslog(LOG_WARNING, "ZCheckSrvAuthentication: ZReadZcode: %s", + error_message(result)); + return ZAUTH_FAILED; + } + /* HOLDING: asn1_data, cksumbuf.data */ + + valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, + Z_KEYUSAGE_CLT_CKSUM, + asn1_data, asn1_len); + + /* XXX compatibility with unreleased interrealm krb5; drop in 3.1 */ + if (!valid && realm) + valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype, + Z_KEYUSAGE_SRV_CKSUM, + asn1_data, asn1_len); + + free(asn1_data); + krb5_free_keyblock(Z_krb5_ctx, keyblock); + free(cksumbuf.data); + + if (valid) { + return ZAUTH_YES; + } else { + syslog(LOG_DEBUG, "ZCheckSrvAuthentication: Z_krb5_verify_cksum: failed"); + return ZAUTH_FAILED; + } +#else + return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO; +#endif +} + +#undef KRB5AUTHENT + +#if defined(HAVE_KRB4) && defined(HAVE_KRB5) +static Code_t +ZCheckAuthentication4(ZNotice_t *notice, + struct sockaddr_in *from) +{ + int result; + char srcprincipal[ANAME_SZ+INST_SZ+REALM_SZ+4]; + KTEXT_ST authent; + AUTH_DAT dat; + ZChecksum_t checksum; + char instance[INST_SZ+1]; + + if (!notice->z_auth) + return ZAUTH_NO; + + /* Check for bogus authentication data length. */ + if (notice->z_authent_len <= 0) + return ZAUTH_FAILED; + + /* Read in the authentication data. */ + if (ZReadAscii(notice->z_ascii_authent, + strlen(notice->z_ascii_authent)+1, + (unsigned char *)authent.dat, + notice->z_authent_len) == ZERR_BADFIELD) { + return ZAUTH_FAILED; + } + authent.length = notice->z_authent_len; + + strcpy(instance, SERVER_INSTANCE); + + /* We don't have the session key cached; do it the long way. */ + result = krb_rd_req(&authent, SERVER_SERVICE, instance, + from->sin_addr.s_addr, &dat, srvtab_file); + if (result == RD_AP_OK) { + ZSetSessionDES(&dat.session); + sprintf(srcprincipal, "%s%s%s@%s", dat.pname, dat.pinst[0] ? "." : "", + dat.pinst, dat.prealm); + if (strcmp(srcprincipal, notice->z_sender)) + return ZAUTH_FAILED; + } else { + return ZAUTH_FAILED; /* didn't decode correctly */ + } + + /* Check the cryptographic checksum. */ + checksum = compute_checksum(notice, dat.session); + + if (checksum != notice->z_checksum) + return ZAUTH_FAILED; + + return ZAUTH_YES; +} +#endif + + +#ifdef HAVE_KRB5 +static ZChecksum_t +compute_checksum(ZNotice_t *notice, + unsigned char *session_key) +{ + ZChecksum_t checksum; + char *cstart, *cend, *hstart = notice->z_packet, *hend = notice->z_message; + + cstart = notice->z_default_format + strlen(notice->z_default_format) + 1; + cend = cstart + strlen(cstart) + 1; + checksum = z_quad_cksum((unsigned char *)hstart, NULL, cstart - hstart, 0, session_key); + checksum ^= z_quad_cksum((unsigned char *)cend, NULL, hend - cend, 0, session_key); + checksum ^= z_quad_cksum((unsigned char *)notice->z_message, NULL, notice->z_message_len, + 0, session_key); + return checksum; +} + +static ZChecksum_t compute_rlm_checksum(ZNotice_t *notice, + unsigned char *session_key) +{ + ZChecksum_t checksum; + char *cstart, *hstart = notice->z_packet; + + cstart = notice->z_default_format + strlen(notice->z_default_format) + 1; + checksum = z_quad_cksum((unsigned char *)hstart, NULL, + cstart - hstart, 0, session_key); + + return checksum; +} +#endif + +#ifdef HAVE_KRB5 +krb5_error_code +Z_krb5_init_keyblock(krb5_context context, + krb5_enctype type, + size_t size, + krb5_keyblock **key) +{ +#ifdef HAVE_KRB5_CREDS_KEYBLOCK_ENCTYPE + return krb5_init_keyblock(context, type, size, key); +#else + krb5_error_code ret; + krb5_keyblock *tmp, tmp_ss; + tmp = &tmp_ss; + + *key = NULL; + Z_enctype(tmp) = type; + Z_keylen(tmp) = size; + Z_keydata(tmp) = malloc(size); + if (!Z_keydata(tmp)) + return ENOMEM; + ret = krb5_copy_keyblock(context, tmp, key); + free(Z_keydata(tmp)); + return ret; +#endif +} + +void +ZSetSession(krb5_keyblock *keyblock) { + krb5_error_code result; + + if (__Zephyr_keyblock) { + krb5_free_keyblock_contents(Z_krb5_ctx, __Zephyr_keyblock); + result = krb5_copy_keyblock_contents(Z_krb5_ctx, keyblock, __Zephyr_keyblock); + } else { + result = krb5_copy_keyblock(Z_krb5_ctx, keyblock, &__Zephyr_keyblock); + } + + if (result) /*XXX we're out of memory? */ + return; +} +#endif +#ifdef HAVE_KRB4 +void +ZSetSessionDES(C_Block *key) { +#ifdef HAVE_KRB5 + Code_t result; + if (__Zephyr_keyblock) { + krb5_free_keyblock(Z_krb5_ctx, __Zephyr_keyblock); + __Zephyr_keyblock=NULL; + } + result = Z_krb5_init_keyblock(Z_krb5_ctx, ENCTYPE_DES_CBC_CRC, + sizeof(C_Block), + &__Zephyr_keyblock); + if (result) /*XXX we're out of memory? */ + return; + + memcpy(Z_keydata(__Zephyr_keyblock), key, sizeof(C_Block)); +#else + memcpy(__Zephyr_session, key, sizeof(C_Block)); +#endif +} +#endif diff --git a/server/main.c b/server/main.c new file mode 100644 index 0000000..0186b17 --- /dev/null +++ b/server/main.c @@ -0,0 +1,705 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the main loop of the Zephyr server + * + * Created by: John T. Kohl + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include +#include + +#ifndef lint +#ifndef SABER +static const char rcsid_main_c[] = + "$Id$"; +#endif +#endif + +/* + * Server loop for Zephyr. + */ + +/* + The Zephyr server maintains several linked lists of information. + + There is an array of servers (otherservers) initialized and maintained + by server_s.c. + + Each server descriptor contains a pointer to a linked list of hosts + which are ``owned'' by that server. The first server is the ``limbo'' + server which owns any host which was formerly owned by a dead server. + + Each of these host list entries has an IP address and a pointer to a + linked list of clients on that host. + + Each client has a sockaddr_in, a list of subscriptions, and possibly + a session key. + + In addition, the class manager has copies of the pointers to the + clients which are registered with a particular class, the + not-yet-acknowledged list has copies of pointers to some clients, + and the hostm manager may have copies of pointers to some clients + (if the client has not acknowledged a packet after a given timeout). +*/ + +static int do_net_setup(void); +static int initialize(void); +static void usage(void); +static void do_reset(void); +static RETSIGTYPE bye(int); +static RETSIGTYPE dbug_on(int); +static RETSIGTYPE dbug_off(int); +static RETSIGTYPE sig_dump_db(int); +static RETSIGTYPE reset(int); +static RETSIGTYPE reap(int); +static void read_from_dump(char *dumpfile); +static void dump_db(void); +static void dump_strings(void); + +#ifndef DEBUG +static void detach(void); +#endif + +static short doreset = 0; /* if it becomes 1, perform + reset functions */ + +static char *programname; /* set to the basename of argv[0] */ + +#ifdef HAVE_KRB5 +static char tkt5_file[256]; +#endif +#ifdef HAVE_KRB4 +static char tkt_file[128]; +#endif + +static int dump_db_flag = 0; +static int dump_strings_flag = 0; + +static int nofork; + +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) +static char my_realm[REALM_SZ]; +#endif + +int +main(int argc, + char **argv) +{ + int nselect; /* #fildes to select on */ + int nfound; /* #fildes ready on select */ + fd_set readable, writable; + struct timeval tv, *tvp; + int init_from_dump = 0; + char *dumpfile; +#ifdef _POSIX_VERSION + struct sigaction action; +#endif + int optchar; /* option processing */ + + sprintf(list_file, "%s/zephyr/%s", SYSCONFDIR, SERVER_LIST_FILE); +#ifdef HAVE_KRB4 + sprintf(srvtab_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_SRVTAB); + strcpy(tkt_file, ZEPHYR_TKFILE); +#endif +#ifdef HAVE_KRB5 + sprintf(keytab_file, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_KEYTAB); + strcpy(tkt5_file, ZEPHYR_TK5FILE); +#endif + sprintf(acl_dir, "%s/zephyr/%s", SYSCONFDIR, ZEPHYR_ACL_DIR); + sprintf(subs_file, "%s/zephyr/%s", SYSCONFDIR, DEFAULT_SUBS_FILE); + + /* set name */ + programname = strrchr(argv[0],'/'); + programname = (programname) ? programname + 1 : argv[0]; + + /* process arguments */ + while ((optchar = getopt(argc, argv, "dsnv4f:k:")) != EOF) { + switch(optchar) { + case 'd': + zdebug = 1; + break; +#ifdef DEBUG + case 's': + zalone = 1; + break; +#endif + case 'n': + nofork = 1; + break; + case 'k': +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + strncpy(my_realm, optarg, REALM_SZ); +#endif + break; + case 'v': + bdump_version = optarg; + break; + case 'f': + init_from_dump = 0; + dumpfile = optarg; + break; + case '4': + bdump_auth_proto = 4; + break; + case '?': + default: + usage(); + /*NOTREACHED*/ + } + } + +#ifdef HAVE_KRB4 + /* if there is no readable srvtab and we are not standalone, there + is no possible way we can succeed, so we exit */ + + if (access(srvtab_file, R_OK) +#ifdef DEBUG + && !zalone +#endif /* DEBUG */ + ) { + fprintf(stderr, "NO ZEPHYR SRVTAB (%s) available; exiting\n", + srvtab_file); + exit(1); + } + /* Use local realm if not specified on command line. */ + if (!*my_realm) { + if (krb_get_lrealm(my_realm, 1) != KSUCCESS) { + fputs("Couldn't get local Kerberos realm; exiting.\n", stderr); + exit(1); + } + } +#endif /* HAVE_KRB4 */ + +#ifndef DEBUG + if (!nofork) + detach(); +#endif /* DEBUG */ + + /* open log */ + OPENLOG(programname, LOG_PID, LOG_LOCAL6); + +#if defined (DEBUG) && 0 + if (zalone) + syslog(LOG_DEBUG, "standalone operation"); +#endif + if (zdebug) + syslog(LOG_DEBUG, "debugging on"); + + /* set up sockets & my_addr and myname, + find other servers and set up server table, initialize queues + for retransmits, initialize error tables, + set up restricted classes */ + + /* Initialize t_local for other uses */ + gettimeofday(&t_local, NULL); + + if (initialize()) + exit(1); + + if (init_from_dump) + read_from_dump(dumpfile); + + /* Seed random number set. */ + srandom(getpid() ^ time(0)); + + /* chdir to somewhere where a core dump will survive */ + if (chdir(TEMP_DIRECTORY) != 0) + syslog(LOG_ERR, "chdir failed (%m) (execution continuing)"); + + FD_ZERO(&interesting); + FD_SET(srv_socket, &interesting); + + nfds = srv_socket + 1; + + +#ifdef _POSIX_VERSION + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + + action.sa_handler = bye; + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + + action.sa_handler = dbug_on; + sigaction(SIGUSR1, &action, NULL); + + action.sa_handler = dbug_off; + sigaction(SIGUSR2, &action, NULL); + + action.sa_handler = reap; + sigaction(SIGCHLD, &action, NULL); + + action.sa_handler = sig_dump_db; + sigaction(SIGFPE, &action, NULL); + + action.sa_handler = reset; + sigaction(SIGHUP, &action, NULL); +#else /* !posix */ + signal(SIGINT, bye); + signal(SIGTERM, bye); + signal(SIGUSR1, dbug_on); + signal(SIGUSR2, dbug_off); + signal(SIGCHLD, reap); + signal(SIGFPE, sig_dump_db); + signal(SIGHUP, reset); +#endif /* _POSIX_VERSION */ + + syslog(LOG_NOTICE, "Ready for action"); + + /* Reinitialize t_local now that initialization is done. */ + gettimeofday(&t_local, NULL); + uptime = NOW; + + for (;;) { + if (doreset) + do_reset(); + + if (dump_db_flag) + dump_db(); + if (dump_strings_flag) + dump_strings(); + + timer_process(); + + readable = interesting; + FD_ZERO(&writable); + tvp = timer_timeout(&tv); +#ifdef HAVE_ARES + nselect = ares_fds(achannel, &readable, &writable); + if (nselect < nfds) + nselect = nfds; + tvp = ares_timeout(achannel, tvp, &tv); +#else + nselect = nfds; +#endif + if (msgs_queued()) { + /* when there is input in the queue, we + artificially set up to pick up the input */ + nfound = 1; + FD_ZERO(&readable); + FD_ZERO(&writable); + } else { + nfound = select(nselect, &readable, &writable, NULL, tvp); + } + + /* Initialize t_local for other uses */ + gettimeofday(&t_local, (struct timezone *)0); + + /* don't flame about EINTR, since a SIGUSR1 or SIGUSR2 + can generate it by interrupting the select */ + if (nfound < 0) { + if (errno != EINTR) + syslog(LOG_WARNING, "select error: %m"); + continue; + } + +#ifdef HAVE_ARES + ares_process(achannel, &readable, &writable); +#endif + + if (nfound == 0) { + /* either we timed out or we were just + polling for input. Either way we want to continue + the loop, and process the next timeout */ + continue; + } else { + if (bdump_socket >= 0 && FD_ISSET(bdump_socket,&readable)) + bdump_send(); + else if (msgs_queued() || FD_ISSET(srv_socket, &readable)) + handle_packet(); + } + } +} + +/* Initialize net stuff. + Set up the server array. + Initialize the packet ack queues to be empty. + Initialize the error tables. + Restrict certain classes. + */ + +static int +initialize(void) +{ + if (do_net_setup()) + return(1); + + server_init(); + +#ifdef HAVE_KRB4 + krb_set_tkt_string(tkt_file); +#endif + realm_init(); + + ZSetServerState(1); + ZInitialize(); /* set up the library */ +#ifdef HAVE_KRB5 + krb5_cc_resolve(Z_krb5_ctx, tkt5_file, &Z_krb5_ccache); +#ifdef HAVE_KRB5_CC_SET_DEFAULT_NAME + krb5_cc_set_default_name(Z_krb5_ctx, tkt5_file); +#else + { + /* Hack to make krb5_cc_default do something reasonable */ + char *env=(char *)malloc(strlen(tkt5_file)+12); + if (!env) return(1); + sprintf(env, "KRB5CCNAME=%s", tkt5_file); + putenv(env); + } +#endif +#endif +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + /* Override what Zinitialize set for ZGetRealm() */ + if (*my_realm) + strcpy(__Zephyr_realm, my_realm); +#endif + + /* set up err table */ +#if defined(__APPLE__) && defined(__MACH__) + add_error_table(&et_zsrv_error_table); +#else + init_zsrv_err_tbl(); +#endif + + ZSetFD(srv_socket); /* set up the socket as the input fildes */ + + /* set up default strings */ + + class_control = make_string(ZEPHYR_CTL_CLASS, 1); + class_admin = make_string(ZEPHYR_ADMIN_CLASS, 1); + class_hm = make_string(HM_CTL_CLASS, 1); + class_ulogin = make_string(LOGIN_CLASS, 1); + class_ulocate = make_string(LOCATE_CLASS, 1); + wildcard_instance = make_string(WILDCARD_INSTANCE, 1); + empty = make_string("", 0); + + /* restrict certain classes */ + access_init(); + return 0; +} + +/* + * Set up the server and client sockets, and initialize my_addr and myname + */ + +static int +do_net_setup(void) +{ + struct servent *sp; + struct hostent *hp; + char hostname[NS_MAXDNAME]; + int flags; +#ifdef HAVE_ARES + int status; +#endif + +#ifdef HAVE_ARES + status = ares_init(&achannel); + if (status != ARES_SUCCESS) { + syslog(LOG_ERR, "resolver init failed: %s", ares_strerror(status)); + return 1; + } +#endif + + if (gethostname(hostname, sizeof(hostname))) { + syslog(LOG_ERR, "no hostname: %m"); + return 1; + } + hp = gethostbyname(hostname); + if (!hp || hp->h_addrtype != AF_INET) { + syslog(LOG_ERR, "no gethostbyname repsonse"); + strncpy(myname, hostname, NS_MAXDNAME); + return 1; + } + strncpy(myname, hp->h_name, NS_MAXDNAME); + memcpy(&my_addr, hp->h_addr_list[0], hp->h_length); + + setservent(1); /* keep file/connection open */ + + memset(&srv_addr, 0, sizeof(srv_addr)); + srv_addr.sin_family = AF_INET; + sp = getservbyname(SERVER_SVCNAME, "udp"); + srv_addr.sin_port = (sp) ? sp->s_port : SERVER_SVC_FALLBACK; + + sp = getservbyname(HM_SVCNAME, "udp"); + hm_port = (sp) ? sp->s_port : HM_SVC_FALLBACK; + + sp = getservbyname(HM_SRV_SVCNAME, "udp"); + hm_srv_port = (sp) ? sp->s_port : HM_SRV_SVC_FALLBACK; + + srv_socket = socket(AF_INET, SOCK_DGRAM, 0); + if (srv_socket < 0) { + syslog(LOG_ERR, "client_sock failed: %m"); + return 1; + } + if (bind(srv_socket, (struct sockaddr *) &srv_addr, + sizeof(srv_addr)) < 0) { + syslog(LOG_ERR, "client bind failed: %m"); + return 1; + } + + /* set not-blocking */ +#ifdef _POSIX_VERSION + flags = fcntl(srv_socket, F_GETFL); + flags |= O_NONBLOCK; + fcntl(srv_socket, F_SETFL, flags); +#else + flags = 1; + ioctl(srv_socket, FIONBIO, &flags); +#endif + + return 0; +} + + +/* + * print out a usage message. + */ + +static void +usage(void) +{ +#ifdef DEBUG + fprintf(stderr, "Usage: %s [-d] [-s] [-n] [-k realm] [-f dumpfile]\n", + programname); +#else + fprintf(stderr, "Usage: %s [-d] [-n] [-k realm] [-f dumpfile]\n", + programname); +#endif /* DEBUG */ + exit(2); +} + +static RETSIGTYPE +bye(int sig) +{ + server_shutdown(); /* tell other servers */ +#ifdef REALM_MGMT + realm_shutdown(); /* tell other realms */ +#endif + hostm_shutdown(); /* tell our hosts */ + kill_realm_pids(); +#ifdef HAVE_KRB4 + dest_tkt(); +#endif + syslog(LOG_NOTICE, "goodbye (sig %d)", sig); + exit(0); +} + +static RETSIGTYPE +dbug_on(int sig) +{ + syslog(LOG_DEBUG, "debugging turned on"); + zdebug = 1; +} + +static RETSIGTYPE +dbug_off(int sig) +{ + syslog(LOG_DEBUG, "debugging turned off"); + zdebug = 0; +} + +int fork_for_dump = 0; + +static void dump_strings(void) +{ + char filename[128]; + + FILE *fp; + int oerrno = errno; + + sprintf(filename, "%szephyr.strings", TEMP_DIRECTORY); + fp = fopen (filename, "w"); + if (!fp) { + syslog(LOG_ERR, "can't open strings dump file: %m"); + errno = oerrno; + dump_strings_flag = 0; + return; + } + syslog(LOG_INFO, "dumping strings to disk"); + print_string_table(fp); + if (fclose(fp) == EOF) + syslog(LOG_ERR, "error writing strings dump file"); + else + syslog(LOG_INFO, "dump done"); + oerrno = errno; + dump_strings_flag = 0; + return; +} + +static RETSIGTYPE +sig_dump_db(int sig) +{ + dump_db_flag = 1; +} + +static void +dump_db(void) +{ + /* dump the in-core database to human-readable form on disk */ + FILE *fp; + int oerrno = errno; + int pid; + char filename[128]; + + pid = (fork_for_dump) ? fork() : -1; + if (pid > 0) { + dump_db_flag = 0; + return; + } + sprintf(filename, "%szephyr.db", TEMP_DIRECTORY); + fp = fopen(filename, "w"); + if (!fp) { + syslog(LOG_ERR, "can't open dump database"); + errno = oerrno; + dump_db_flag = 0; + return; + } + syslog(LOG_INFO, "dumping to disk"); + server_dump_servers(fp); + uloc_dump_locs(fp); + client_dump_clients(fp); + triplet_dump_subs(fp); + realm_dump_realms(fp); + syslog(LOG_INFO, "dump done"); + if (fclose(fp) == EOF) + syslog(LOG_ERR, "can't close dump db"); + if (pid == 0) + exit(0); + errno = oerrno; + dump_db_flag = 0; +} + +static RETSIGTYPE +reset(int sig) +{ + zdbug((LOG_DEBUG,"reset()")); + doreset = 1; +} + +static RETSIGTYPE +reap(int sig) +{ + int pid, i = 0; + int oerrno = errno; + ZRealm *rlm; +#ifdef _POSIX_VERSION + int waitb; +#else + union wait waitb; +#endif + + zdbug((LOG_DEBUG,"reap()")); +#ifdef _POSIX_VERSION + while ((pid = waitpid(-1, &waitb, WNOHANG)) == 0) + { i++; if (i > 10) break; } +#else + while ((pid = wait3 (&waitb, WNOHANG, (struct rusage*) 0)) == 0) + { i++; if (i > 10) break; } +#endif + + errno = oerrno; + + if (pid) { + if (WIFSIGNALED(waitb) == 0) { + if (WIFEXITED(waitb) != 0) { + rlm = realm_get_realm_by_pid(pid); + if (rlm) { + rlm->child_pid = 0; + rlm->have_tkt = 1; + } + } + } else { + rlm = realm_get_realm_by_pid(pid); + if (rlm) { + rlm->child_pid = 0; + } + } + } +} + +static void +do_reset(void) +{ + int oerrno = errno; +#ifdef _POSIX_VERSION + sigset_t mask, omask; +#else + int omask; +#endif +#ifdef _POSIX_VERSION + sigemptyset(&mask); + sigaddset(&mask, SIGHUP); + sigprocmask(SIG_BLOCK, &mask, &omask); +#else + omask = sigblock(sigmask(SIGHUP)); +#endif + + /* reset various things in the server's state */ + subscr_reset(); + server_reset(); + realm_init(); + access_reinit(); + syslog(LOG_INFO, "restart completed"); + doreset = 0; + errno = oerrno; +#ifdef _POSIX_VERSION + sigprocmask(SIG_SETMASK, &omask, (sigset_t *)0); +#else + sigsetmask(omask); +#endif +} + +#ifndef DEBUG +/* + * detach from the terminal + */ + +static void +detach(void) +{ + /* detach from terminal and fork. */ + int i; + long size; + +#ifdef _POSIX_VERSION + size = sysconf(_SC_OPEN_MAX); +#else + size = getdtablesize(); +#endif + /* profiling seems to get confused by fork() */ + i = fork (); + if (i) { + if (i < 0) + perror("fork"); + exit(0); + } + + for (i = 0; i < size; i++) + close(i); + + i = open("/dev/tty", O_RDWR, 666); +#ifdef TIOCNOTTY /* Only necessary on old systems. */ + ioctl(i, TIOCNOTTY, NULL); +#endif + close(i); +#ifdef _POSIX_VERSION + setsid(); +#endif +} +#endif /* not DEBUG */ + +static void +read_from_dump(char *dumpfile) +{ + /* Not yet implemented. */ + return; +} + diff --git a/server/realm.c b/server/realm.c new file mode 100644 index 0000000..494c2e4 --- /dev/null +++ b/server/realm.c @@ -0,0 +1,1664 @@ +#include "zserver.h" +#include + +Unacked *rlm_nacklist = NULL; /* not acked list for realm-realm + packets */ +ZRealm **otherrealms = NULL; /* points to an array of the known + servers */ +int nrealms = 0; /* number of other realms */ +int n_realm_slots = 0; /* size of malloc'd otherrealms */ + +/* + * External Routines: + * + * ZRealm *realm_which_realm(struct sockaddr_in *who) + * figures out if this packet came from another realm's server + * + * ZRealm *realm_get_realm_by_pid(int pid) + * figures out which realm a child handler was for + * + * void kill_realm_pids() + * kills all ticket getting childen + * + * char *realm_expand_realm(char *realmname) + * figures out what an abbreviated realm expands to + * + * Code_t realm_send_realms() + * loops through all realms for a brain dump + * + * int realm_bound_for_realm(char *realm, char *recip) + * figures out if recip is in realm, expanding recip's realm + * + * int realm_sender_in_realm(char *realm, char *sender) + * figures out if sender is in realm + * + * ZRealm *realm_get_realm_by_name(char *name) + * finds a realm struct from the realm array by name, tries expansion + * + * Code_t realm_dispatch(ZNotice_t *notice, int auth, struct sockaddr_in *who, + * Server *server) + * dispatches a message from a foreign realm + * + * void realm_init() + * sets up the realm module + * + * void realm_deathgram() + * tells other realms this server is going down + * + * Code_t realm_control_dispatch(ZNotice_t *notice, int auth, + * struct sockaddr_in *who, Server *server, + * ZRealm *realm) + * dispatches a foreign realm control message + * + * void realm_handoff(ZNotice_t *notice, int auth, struct sockaddr_in *who, + * ZRealm *realm, int ack_to_sender) + * hands off a message to another realm + * + * void realm_dump_realms(File *fp) + * do a database dump of foreign realm info + * + */ +static int realm_next_idx_by_idx(ZRealm *realm, int idx); +static void realm_sendit(ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender); +#ifdef HAVE_KRB5 +static Code_t realm_sendit_auth(ZNotice_t *notice, struct sockaddr_in *who, int auth, ZRealm *realm, int ack_to_sender); +#endif +static void rlm_ack(ZNotice_t *notice, Unacked *nacked); +static void rlm_nack_cancel(ZNotice_t *notice, struct sockaddr_in *who); +static void rlm_rexmit(void *arg); +static Code_t realm_ulocate_dispatch(ZNotice_t *notice,int auth,struct sockaddr_in *who,Server *server,ZRealm *realm); +static Code_t realm_new_server(struct sockaddr_in *, ZNotice_t *, ZRealm *); +static Code_t realm_set_server(struct sockaddr_in *, ZRealm *); +#ifdef HAVE_KRB5 +static Code_t ticket_retrieve(ZRealm *realm); +static int ticket_lookup(char *realm); +#endif + +static int +is_usable(ZRealm_server *srvr) +{ + return !srvr->deleted && srvr->got_addr; +} + +static int +is_sendable(ZRealm_server *srvr) +{ + return !srvr->deleted && srvr->got_addr && !srvr->dontsend; +} + +static void +rlm_wakeup_cb(void *arg) +{ + ZRealm *realm = arg; + ZNotice_t snotice; + char *pack; + char rlm_recipient[REALM_SZ + 1]; + int packlen, retval; + + memset (&snotice, 0, sizeof (snotice)); + + snotice.z_opcode = REALM_BOOT; + snotice.z_port = srv_addr.sin_port; + snotice.z_class_inst = ZEPHYR_CTL_REALM; + snotice.z_class = ZEPHYR_CTL_CLASS; + snotice.z_recipient = ""; + snotice.z_kind = ACKED; + snotice.z_num_other_fields = 0; + snotice.z_default_format = ""; + snotice.z_sender = myname; /* my host name */ + sprintf(rlm_recipient, "@%s", realm->name); + snotice.z_recipient = rlm_recipient; + snotice.z_default_format = ""; + snotice.z_message = NULL; + snotice.z_message_len = 0; + +#ifdef HAVE_KRB5 + if (!ticket_lookup(realm->name)) + if ((retval = ticket_retrieve(realm)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_wakeup failed: %s", + error_message(retval)); + return; + } +#endif + + if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZAUTH)) + != ZERR_NONE) + { + syslog(LOG_WARNING, "rlm_wakeup format: %s", + error_message(retval)); + return; + } + if ((retval = ZParseNotice(pack, packlen, &snotice)) + != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_wakeup parse: %s", + error_message(retval)); + free(pack); + return; + } + + realm_handoff(&snotice, 1, NULL, realm, 0); + free(pack); +} + +static void +rlm_set_server_address(ZRealm_server *srvr, struct hostent *hp) +{ + memmove(&srvr->addr.sin_addr, hp->h_addr, sizeof(struct in_addr)); + /* use the server port */ + srvr->addr.sin_port = srv_addr.sin_port; + srvr->addr.sin_family = AF_INET; + srvr->got_addr = 1; + if (is_sendable(srvr) && srvr->realm->state == REALM_NEW) { + srvr->realm->idx = realm_next_idx_by_idx(srvr->realm, srvr->realm->idx); + srvr->realm->state = REALM_TARDY; + /* + * Set a timer to send a wakeup to this realm. We do this rather + * than just sending the notice now because, if we are not using + * C-ARES, then we might be called during server startup before + * the server is prepared to send notices. + */ + timer_set_rel(0, rlm_wakeup_cb, srvr->realm); + } +} + +#ifdef HAVE_ARES + +static void rlm_server_address_timer_cb(void *srvr); +static void rlm_server_address_lookup_cb(void *, int, int, struct hostent *); + +static void +rlm_lookup_server_address(ZRealm_server *srvr) +{ + /* Cancel any pending future lookup. */ + if (srvr->timer) { + timer_reset(srvr->timer); + srvr->timer = NULL; + } + ares_gethostbyname(achannel, srvr->name->string, AF_INET, + rlm_server_address_lookup_cb, srvr); +} + +static void +rlm_server_address_timer_cb(void *arg) +{ + ZRealm_server *srvr = arg; + + srvr->timer = NULL; + ares_gethostbyname(achannel, srvr->name->string, AF_INET, + rlm_server_address_lookup_cb, arg); +} + +static void +rlm_server_address_lookup_cb(void *arg, int status, int timeouts, + struct hostent *hp) +{ + ZRealm_server *srvr = arg; + int delay = 30; + + if (status == ARES_SUCCESS) { + rlm_set_server_address(srvr, hp); + delay = 24 * 3600; /* Check again once per day */ + } else { + syslog(LOG_WARNING, "%s: hostname lookup failed: %s", + srvr->name->string, ares_strerror(status)); + } + + /* + * Set a timer to trigger another lookup. + * But, not if the server is deleted, which may have happened + * while we were waiting for ARES to finish the last lookup. + * Also, not if there is already a timer, which is possible if + * there were two outstanding lookups and we are the second to + * complete. This can happen if we are asked to refresh the + * server list while a previous lookup is still in progress, + * since there is no convenient way to tell whether there is a + * lookup in progress. + */ + if (!srvr->timer && !srvr->deleted) + srvr->timer = timer_set_rel(delay, rlm_server_address_timer_cb, arg); +} + +#else + +static void +rlm_lookup_server_address(ZRealm_server *srvr) +{ + struct hostent *hp; + + hp = gethostbyname(srvr->name->string); + if (hp) + rlm_set_server_address(srvr, hp); + else + syslog(LOG_WARNING, "hostname failed, %s", srvr->name->string); +} + +#endif + +static int +realm_get_idx_by_addr(ZRealm *realm, + struct sockaddr_in *who) +{ + ZRealm_server *srvr; + int b; + + /* loop through the realms */ + for (b = 0; b < realm->count; b++) { + srvr = realm->srvrs[b]; + if (!is_usable(srvr)) + continue; + if (srvr->addr.sin_addr.s_addr == who->sin_addr.s_addr) + return(b); + } + + return 0; +} + +static int +realm_next_idx_by_idx(ZRealm *realm, int idx) +{ + ZRealm_server *srvr; + int b; + + /* loop through the servers */ + for (b = idx; b < realm->count; b++) { + srvr = realm->srvrs[b]; + if (is_sendable(srvr)) + return(b); + } + + /* recycle */ + if (idx != 0) + for (b = 0; b < idx; b++) { + srvr = realm->srvrs[b]; + if (is_sendable(srvr)) + return(b); + } + + return 0; +} + +const char * +realm_expand_realm(char *realmname) +{ + int a; + + /* First, look for an exact match (case insensitive) */ +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + if (!strcasecmp(ZGetRealm(), realmname)) + return(ZGetRealm()); +#endif + + for (a = 0; a < nrealms; a++) + if (!strcasecmp(otherrealms[a]->name, realmname)) + return(otherrealms[a]->name); + + /* No exact match. See if there's a partial match */ +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + if (!strncasecmp(ZGetRealm(), realmname, strlen(realmname))) + return(ZGetRealm()); +#endif + + for (a = 0; a < nrealms; a++) + if (!strncasecmp(otherrealms[a]->name, realmname, strlen(realmname))) + return(otherrealms[a]->name); + return(realmname); +} + +ZRealm * +realm_get_realm_by_pid(int pid) +{ + int a; + + for (a = 0; a < nrealms; a++) + if (otherrealms[a]->child_pid == pid) + return(otherrealms[a]); + + return 0; +} + +void +kill_realm_pids(void) +{ + int a; + + for (a = 0; a < nrealms; a++) + if (otherrealms[a]->child_pid != 0) + kill(otherrealms[a]->child_pid, 9); + + return; +} + +static ZRealmname * +get_realm_lists(char *file) +{ + ZRealmname *rlm_list, *rlm; + int ii, nused, ntotal; + FILE *fp; + char buf[REALM_SZ + NS_MAXDNAME + 1]; /* one for newline */ + char realm[REALM_SZ], server[NS_MAXDNAME + 1]; + String *realm_name; + + nused = 0; + if (!(fp = fopen(file, "r"))) + return((ZRealmname *)0); + + /* start with 16, realloc if necessary */ + ntotal = 16; + rlm_list = (ZRealmname *)malloc(ntotal * sizeof(ZRealmname)); + if (!rlm_list) { + syslog(LOG_CRIT, "get_realm_lists malloc"); + abort(); + } + + while (fgets(buf, sizeof(buf), fp)) { + if (sscanf(buf, "%s %s", realm, server) != 2) { + syslog(LOG_CRIT, "bad format in %s", file); + abort(); + } + realm_name = make_string(realm, 0); + for (ii = 0; ii < nused; ii++) { + /* look for this realm */ + if (rlm_list[ii].name == realm_name) + break; + } + if (ii < nused) { + free_string(realm_name); + rlm = &rlm_list[ii]; + if (rlm->nused +1 >= rlm->nservers) { + /* make more space */ + rlm->servers = (struct _ZRealm_server *) + realloc((char *)rlm->servers, + (unsigned)rlm->nservers * 2 * + sizeof(struct _ZRealm_server)); + if (!rlm->servers) { + syslog(LOG_CRIT, "get_realm_lists realloc"); + abort(); + } + rlm->nservers *= 2; + } + } else { + /* new realm */ + if (nused + 1 >= ntotal) { + /* make more space */ + rlm_list = (ZRealmname *)realloc((char *)rlm_list, + (unsigned)ntotal * 2 * + sizeof(ZRealmname)); + if (!rlm_list) { + syslog(LOG_CRIT, "get_realm_lists realloc"); + abort(); + } + ntotal *= 2; + } + rlm = &rlm_list[nused++]; + rlm->name = realm_name; + rlm->nused = 0; + rlm->nservers = 16; + rlm->servers = (struct _ZRealm_server *) + malloc(rlm->nservers * sizeof(struct _ZRealm_server)); + if (!rlm->servers) { + syslog(LOG_CRIT, "get_realm_lists malloc"); + abort(); + } + } + memset(&rlm->servers[rlm->nused], 0, sizeof(struct _ZRealm_server)); + if (*server == '/') { + rlm->servers[rlm->nused].name = make_string(server + 1, 1); + rlm->servers[rlm->nused].dontsend = 1; + } else { + rlm->servers[rlm->nused].name = make_string(server, 1); + } + rlm->nused++; + } + if (nused + 1 >= ntotal) { + rlm_list = (ZRealmname *)realloc((char *)rlm_list, + (unsigned)(ntotal + 1) * + sizeof(ZRealmname)); + if (!rlm_list) { + syslog(LOG_CRIT, "get_realm_lists realloc"); + abort(); + } + } + rlm_list[nused].name = 0; + + fclose(fp); + return(rlm_list); +} + +Code_t +realm_send_realms(void) +{ + int cnt, retval; + for (cnt = 0; cnt < nrealms; cnt++) { + retval = subscr_send_realm_subs(otherrealms[cnt]); + if (retval != ZERR_NONE) + return(retval); + } + return ZERR_NONE; +} + +int +realm_bound_for_realm(const char *realm, char *recip) +{ + char *rlm = NULL; + int remote = strcmp(ZGetRealm(), realm); + + if (recip) + rlm = strchr(recip, '@'); + + if (!rlm && !remote) + return 1; + + if (rlm && strcmp(realm_expand_realm(rlm + 1), realm) == 0) + return 1; + + return 0; +} + +int +realm_sender_in_realm(const char *realm, char *sender) +{ + char *rlm = NULL; + int remote = strcmp(ZGetRealm(), realm); + + if (sender) + rlm = strchr(sender, '@'); + + if (!rlm && !remote) + return 1; + + if (rlm && strcmp((rlm + 1), realm) == 0) + return 1; + + return 0; +} + +ZRealm * +realm_which_realm(struct sockaddr_in *who) +{ + ZRealm_server *srvr; + int a, b; + + if (who->sin_port != srv_addr.sin_port) + return 0; + + /* loop through the realms */ + for (a = 0; a < nrealms; a++) + /* loop through the addresses for the realm */ + for (b = 0; b < otherrealms[a]->count; b++) { + srvr = otherrealms[a]->srvrs[b]; + if (!is_usable(srvr)) + continue; + if (srvr->addr.sin_addr.s_addr == who->sin_addr.s_addr) + return(otherrealms[a]); + } + + return 0; +} + +ZRealm * +realm_get_realm_by_name(char *name) +{ + int a; + + /* First, look for an exact match (case insensitive) */ + for (a = 0; a < nrealms; a++) + if (!strcasecmp(otherrealms[a]->name, name)) + return(otherrealms[a]); + + /* Failing that, look for an inexact match */ + for (a = 0; a < nrealms; a++) + if (!strncasecmp(otherrealms[a]->name, name, strlen(name))) + return(otherrealms[a]); + + return 0; +} + +ZRealm * +realm_get_realm_by_name_string(String *namestr) +{ + int a; + + for (a = 0; a < nrealms; a++) + if (otherrealms[a]->namestr == namestr) + return otherrealms[a]; + + return 0; +} + +static void +rlm_nack_cancel(register ZNotice_t *notice, + struct sockaddr_in *who) +{ + register ZRealm *which = realm_which_realm(who); + register Unacked *nacked; + + zdbug((LOG_DEBUG, "rlm_nack_cancel: %s:%08X,%08X", + inet_ntoa(notice->z_uid.zuid_addr), + notice->z_uid.tv.tv_sec, notice->z_uid.tv.tv_usec)); + + if (!which) { + syslog(LOG_ERR, "non-realm ack?"); + return; + } + + for (nacked = rlm_nacklist; nacked; nacked = nacked->next) { + if (nacked->dest.rlm.realm == which) { + /* First, note the realm appears to be up */ + which->state = REALM_UP; + if (ZCompareUID(&nacked->uid, ¬ice->z_uid)) { + timer_reset(nacked->timer); + + if (nacked->ack_addr.sin_addr.s_addr) + rlm_ack(notice, nacked); + + /* free the data */ + free(nacked->packet); + Unacked_delete(nacked); + free(nacked); + return; + } + } + } + return; +} + +static void +rlm_ack(ZNotice_t *notice, + Unacked *nacked) +{ + ZNotice_t acknotice; + ZPacket_t ackpack; + int packlen; + Code_t retval; + + /* tell the original sender the result */ + acknotice = *notice; + acknotice.z_message_len = strlen(acknotice.z_message) + 1; + + packlen = sizeof(ackpack); + + if ((retval = ZFormatSmallRawNotice(&acknotice, ackpack, &packlen)) + != ZERR_NONE) { + syslog(LOG_ERR, "rlm_ack format: %s", + error_message(retval)); + return; + } + zdbug((LOG_DEBUG, "rlm_ack sending to %s/%d", + inet_ntoa(nacked->ack_addr.sin_addr), + ntohs(nacked->ack_addr.sin_port))); + if ((retval = ZSetDestAddr(&nacked->ack_addr)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_ack set addr: %s", + error_message(retval)); + return; + } + if ((retval = ZSendPacket(ackpack, packlen, 0)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_ack xmit: %s", error_message(retval)); + return; + } +} + +Code_t +realm_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + ZRealm *realm; + Code_t status = ZERR_NONE; + char rlm_recipient[REALM_SZ + 1]; + int external = 0; + String *notice_class; + + if (notice->z_kind == SERVACK || notice->z_kind == SERVNAK) { + rlm_nack_cancel(notice, who); + return(ZERR_NONE); + } + + /* check if it's a control message */ + realm = realm_which_realm(who); + + notice_class = make_string(notice->z_class,1); + + if (class_is_admin(notice_class)) { + syslog(LOG_WARNING, "%s sending admin opcode %s", + realm->name, notice->z_opcode); + } else if (class_is_hm(notice_class)) { + syslog(LOG_WARNING, "%s sending hm opcode %s", + realm->name, notice->z_opcode); + } else if (class_is_control(notice_class)) { + status = realm_control_dispatch(notice, auth, who, + server, realm); + } else if (class_is_ulogin(notice_class)) { + /* don't need to forward this */ + if (server == me_server) { + sprintf(rlm_recipient, "@%s", realm->name); + notice->z_recipient = rlm_recipient; + + sendit(notice, 1, who, 0); + } + } else if (class_is_ulocate(notice_class)) { + status = realm_ulocate_dispatch(notice, auth, who, server, realm); + } else { + /* redo the recipient */ + if (*notice->z_recipient == '\0') { + sprintf(rlm_recipient, "@%s", realm->name); + notice->z_recipient = rlm_recipient; + external = 0; + } else if (realm_bound_for_realm(ZGetRealm(), notice->z_recipient) + && *notice->z_recipient == '@') + { + /* we're responsible for getting this message out */ + external = 1; + notice->z_recipient = ""; + } + + /* otherwise, send to local subscribers */ + sendit(notice, auth, who, external); + } + + return(status); +} + +void +realm_init(void) +{ + Client *client; + ZRealmname *rlmnames; + ZRealm *rlm; + int ii, jj, kk, nrlmnames, nsendable; + char realm_list_file[128]; + char rlmprinc[MAX_PRINCIPAL_SIZE]; + + sprintf(realm_list_file, "%s/zephyr/%s", SYSCONFDIR, REALM_LIST_FILE); + rlmnames = get_realm_lists(realm_list_file); + if (!rlmnames) { + zdbug((LOG_DEBUG, "No other realms")); + /* should we nuke all existing server records? */ + return; + } + + for (nrlmnames = 0; rlmnames[nrlmnames].name; nrlmnames++); + + /* + * This happens only when we first start up. Otherwise, otherrealms + * is grown as needed. + */ + if (!otherrealms) { + otherrealms = (ZRealm **)malloc(nrlmnames * sizeof(ZRealm *)); + if (!otherrealms) { + syslog(LOG_CRIT, "malloc failed in realm_init"); + abort(); + } + memset(otherrealms, 0, (nrlmnames * sizeof(ZRealm *))); + n_realm_slots = nrlmnames; + } + + /* ii: entry in rlmnames */ + for (ii = 0; ii < nrlmnames; ii++) { + nsendable = 0; + rlm = realm_get_realm_by_name_string(rlmnames[ii].name); + if (rlm) { + /* jj: server entry in otherrealms */ + /* kk: server entry in rlmnames */ + for (jj = 0; jj < rlm->count; jj++) { + rlm->srvrs[jj]->deleted = 1; + for (kk = 0; kk < rlmnames[ii].nused; kk++) { + if (rlmnames[ii].servers[kk].name != rlm->srvrs[jj]->name) + continue; + /* update existing server */ + rlm->srvrs[jj]->dontsend = rlmnames[ii].servers[kk].dontsend; + rlm->srvrs[jj]->deleted = 0; + rlm_lookup_server_address(rlm->srvrs[jj]); + if (is_sendable(rlm->srvrs[jj])) nsendable++; + + /* mark realm.list server entry used */ + rlmnames[ii].servers[kk].deleted = 1; + break; + } + if (rlm->srvrs[jj]->deleted && rlm->srvrs[jj]->timer) { + timer_reset(rlm->srvrs[jj]->timer); + rlm->srvrs[jj]->timer = NULL; + } + } + for (jj = kk = 0; kk < rlmnames[ii].nused; kk++) + if (!rlmnames[ii].servers[kk].deleted) jj++; + + rlm->srvrs = realloc(rlm->srvrs, + (rlm->count + jj) * sizeof(ZRealm_server *)); + if (!rlm->srvrs) { + syslog(LOG_CRIT, "realloc failed in realm_init"); + abort(); + } + for (kk = 0; kk < rlmnames[ii].nused; kk++) { + if (rlmnames[ii].servers[kk].deleted) continue; + rlm->srvrs[rlm->count] = malloc(sizeof(ZRealm_server)); + if (!rlm->srvrs[rlm->count]) { + syslog(LOG_CRIT, "realloc failed in realm_init"); + abort(); + } + *(rlm->srvrs[rlm->count]) = rlmnames[ii].servers[kk]; + rlm->srvrs[rlm->count]->realm = rlm; + rlm_lookup_server_address(rlm->srvrs[rlm->count]); + if (is_sendable(rlm->srvrs[rlm->count])) nsendable++; + rlm->count++; + } + /* The current server might have been deleted or marked dontsend. + Advance to one we can use, if necessary. */ + if (nsendable) { + rlm->idx = realm_next_idx_by_idx(rlm, rlm->idx); + } else { + rlm->idx = 0; + rlm->state = REALM_NEW; + } + free(rlmnames[ii].servers); + continue; + } + + if (nrealms >= n_realm_slots) { + otherrealms = realloc(otherrealms, + n_realm_slots * 2 * sizeof(ZRealm *)); + if (!otherrealms) { + syslog(LOG_CRIT, "realloc failed in realm_init"); + abort(); + } + memset(otherrealms + n_realm_slots, 0, + n_realm_slots * sizeof(ZRealm *)); + n_realm_slots *= 2; + } + + rlm = (ZRealm *) malloc(sizeof(ZRealm)); + if (!rlm) { + syslog(LOG_CRIT, "malloc failed in realm_init"); + abort(); + } + memset(rlm, 0, sizeof(ZRealm)); + otherrealms[nrealms++] = rlm; + + rlm->namestr = rlmnames[ii].name; + rlm->name = rlm->namestr->string; + rlm->state = REALM_NEW; + + /* convert names to addresses */ + rlm->count = rlmnames[ii].nused; + rlm->srvrs = malloc(rlm->count * sizeof(ZRealm_server *)); + if (!rlm->srvrs) { + syslog(LOG_CRIT, "malloc failed in realm_init"); + abort(); + } + for (jj = 0; jj < rlm->count; jj++) { + rlm->srvrs[jj] = &rlmnames[ii].servers[jj]; + rlm->srvrs[jj]->realm = rlm; + rlm_lookup_server_address(rlm->srvrs[jj]); + if (is_sendable(rlm->srvrs[jj])) nsendable++; + } + + client = (Client *) malloc(sizeof(Client)); + if (!client) { + syslog(LOG_CRIT, "malloc failed in realm_init"); + abort(); + } + memset(&client->addr, 0, sizeof(struct sockaddr_in)); +#ifdef HAVE_KRB5 + client->session_keyblock = NULL; +#else +#ifdef HAVE_KRB4 + memset(&client->session_key, 0, sizeof(client->session_key)); +#endif +#endif + snprintf(rlmprinc, MAX_PRINCIPAL_SIZE, "%s.%s@%s", SERVER_SERVICE, SERVER_INSTANCE, + rlm->name); + client->principal = make_string(rlmprinc, 0); + client->last_send = 0; + client->last_ack = NOW; + client->subs = NULL; + client->realm = rlm; + client->addr.sin_family = 0; + client->addr.sin_port = 0; + client->addr.sin_addr.s_addr = 0; + + rlm->client = client; + rlm->idx = (nsendable) ? + realm_next_idx_by_idx(rlm, (random() % rlm->count)) : 0; + rlm->subs = NULL; + rlm->remsubs = NULL; + rlm->child_pid = 0; + rlm->have_tkt = 1; + } + free(rlmnames); +} + +void +realm_deathgram(Server *server) +{ + ZRealm *realm; + int jj = 0; + + /* Get it out once, and assume foreign servers will share */ + for (jj = 0; jj < nrealms; jj++) { + ZNotice_t snotice; + char *pack; + char rlm_recipient[REALM_SZ + 1]; + int packlen, retval; + + realm = otherrealms[jj]; + memset (&snotice, 0, sizeof (snotice)); + + snotice.z_kind = ACKED; + snotice.z_port = srv_addr.sin_port; + snotice.z_class = ZEPHYR_CTL_CLASS; + snotice.z_class_inst = ZEPHYR_CTL_REALM; + snotice.z_opcode = SERVER_SHUTDOWN; + snotice.z_sender = myname; /* my host name */ + sprintf(rlm_recipient, "@%s", realm->name); + snotice.z_recipient = rlm_recipient; + snotice.z_default_format = ""; + snotice.z_num_other_fields = 0; + snotice.z_default_format = ""; + snotice.z_message = (server) ? server->addr_str : NULL; + snotice.z_message_len = (server) ? strlen(server->addr_str) + 1 : 0; + + zdbug((LOG_DEBUG, "rlm_deathgram: suggesting %s to %s", + (server) ? server->addr_str : "nothing", realm->name)); + +#ifdef HAVE_KRB5 + if (!ticket_lookup(realm->name)) + if ((retval = ticket_retrieve(realm)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_deathgram failed: %s", + error_message(retval)); + return; + } +#endif + + if ((retval = ZFormatNotice(&snotice, &pack, &packlen, ZCAUTH)) + != ZERR_NONE) + { + syslog(LOG_WARNING, "rlm_deathgram format: %s", + error_message(retval)); + return; + } + if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_deathgram parse: %s", + error_message(retval)); + free(pack); + return; + } + + realm_handoff(&snotice, 1, NULL, realm, 0); + free(pack); + } +} + +static Code_t +realm_ulocate_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server, + ZRealm *realm) +{ + register char *opcode = notice->z_opcode; + + if (!auth) { + syslog(LOG_WARNING, "unauth locate msg from %s (%s/%s/%s)", + inet_ntoa(who->sin_addr), + notice->z_class, notice->z_class_inst, + notice->z_opcode); /* XXX */ + clt_ack(notice, who, AUTH_FAILED); + return(ZERR_NONE); + } + + if (!strcmp(opcode, REALM_REQ_LOCATE)) { + ack(notice, who); + ulogin_realm_locate(notice, who, realm); + } else if (!strcmp(opcode, REALM_ANS_LOCATE)) { + ack(notice, who); + ulogin_relay_locate(notice, who); + } else { + syslog(LOG_WARNING, "%s unknown/illegal loc opcode %s", + realm->name, opcode); + nack(notice, who); + } + + return(ZERR_NONE); +} + + +Code_t +realm_control_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server, + ZRealm *realm) +{ + register char *opcode = notice->z_opcode; + Code_t status; + + if (!auth) { + syslog(LOG_WARNING, "unauth ctl msg from %s (%s/%s/%s)", + inet_ntoa(who->sin_addr), + notice->z_class, notice->z_class_inst, + notice->z_opcode); /* XXX */ + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return(ZERR_NONE); + } + + if (strcmp(notice->z_class_inst, ZEPHYR_CTL_REALM)) { + syslog(LOG_WARNING, "Invalid rlm_dispatch instance %s", + notice->z_class_inst); + return(ZERR_NONE); + } + + if (!strcmp(opcode, REALM_REQ_SUBSCRIBE) || !strcmp(opcode, REALM_ADD_SUBSCRIBE)) { + /* try to add subscriptions */ + /* attempts to get defaults are ignored */ + if ((status = subscr_foreign_user(notice, who, server, realm)) != ZERR_NONE) { + clt_ack(notice, who, AUTH_FAILED); + } else if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + } + } else if (!strcmp(opcode, REALM_UNSUBSCRIBE)) { + /* try to remove subscriptions */ + if ((status = subscr_realm_cancel(who, notice, realm)) != ZERR_NONE) { + clt_ack(notice, who, NOT_FOUND); + } else if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + } + } else if (!strcmp(opcode, REALM_BOOT)) { + zdbug((LOG_DEBUG, "got a REALM_BOOT from %s", + inet_ntoa(server->addr.sin_addr))); + if (realm->state != REALM_UP) realm->state = REALM_STARTING; + realm_set_server(who, realm); +#ifdef REALM_MGMT + /* resend subscriptions but only if this was to us */ + if (server == me_server) { + if ((status = subscr_realm_subs(realm)) != ZERR_NONE) { + clt_ack(notice, who, NOT_FOUND); + } else { + /* do forward the hint in case it ever matters */ + server_forward(notice, auth, who); + ack(notice, who); + } + } +#endif + } else if (!strcmp(opcode, SERVER_SHUTDOWN)) { + /* try to remove subscriptions */ + if ((status = realm_new_server(who, notice, realm)) != ZERR_NONE) { + clt_ack(notice, who, NOT_FOUND); + } else if (server == me_server) { + server_forward(notice, auth, who); + ack(notice, who); + } + } else { + syslog(LOG_WARNING, "%s unknown/illegal ctl opcode %s", + realm->name, opcode); + if (server == me_server) + nack(notice, who); + return(ZERR_NONE); + } + return(ZERR_NONE); +} + +static Code_t +realm_new_server(struct sockaddr_in *sin, + ZNotice_t *notice, + ZRealm *realm) +{ + unsigned long addr; + ZRealm *rlm; + struct sockaddr_in sinaddr; + int srvidx; + + if (!realm) + return ZSRV_NORLM; + + srvidx = realm_get_idx_by_addr(realm, sin); + zdbug((LOG_DEBUG, "rlm_new_srv: message from %d in %s (%s)", + srvidx, realm->name, inet_ntoa(sin->sin_addr))); + if (realm->idx == srvidx) { + if (notice->z_message_len) { + addr = inet_addr(notice->z_message); + sinaddr.sin_addr.s_addr = addr; + rlm = realm_which_realm(&sinaddr); + /* Not exactly */ + if (!rlm || (rlm != realm)) + return ZSRV_NORLM; + /* Validate the hint */ + realm->idx = + realm_next_idx_by_idx(realm, realm_get_idx_by_addr(realm, + &sinaddr)); + } else { + realm->idx = realm_next_idx_by_idx(realm, (realm->idx + 1) % + realm->count); + } + zdbug((LOG_DEBUG, "rlm_new_srv: switched servers (%s)", inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + } else { + zdbug((LOG_DEBUG, "rlm_new_srv: not switching servers (%s)", inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + } + return 0; +} + +static Code_t +realm_set_server(struct sockaddr_in *sin, + ZRealm *realm) +{ + ZRealm *rlm; + int idx; + + rlm = realm_which_realm(sin); + /* Not exactly */ + if (!rlm || (rlm != realm)) + return ZSRV_NORLM; + idx = realm_get_idx_by_addr(realm, sin); + + /* Not exactly */ + if (!is_sendable(realm->srvrs[idx])) + return ZSRV_NORLM; + + realm->idx = idx; + + zdbug((LOG_DEBUG, "rlm_pick_srv: switched servers (%s)", inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + + return 0; +} + +void +realm_handoff(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + ZRealm *realm, + int ack_to_sender) +{ +#ifdef HAVE_KRB5 + Code_t retval; + + if (!auth) { + zdbug((LOG_DEBUG, "realm_sendit unauthentic to realm %s", + realm->name)); + realm_sendit(notice, who, auth, realm, ack_to_sender); + return; + } + + if (!ticket_lookup(realm->name)) + if ((retval = ticket_retrieve(realm)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_handoff failed: %s", + error_message(retval)); + realm_sendit(notice, who, auth, realm, ack_to_sender); + return; + } + + zdbug((LOG_DEBUG, "realm_sendit to realm %s auth %d", realm->name, auth)); + /* valid ticket available now, send the message */ + retval = realm_sendit_auth(notice, who, auth, realm, ack_to_sender); +#else /* HAVE_KRB4 */ + realm_sendit(notice, who, auth, realm, ack_to_sender); +#endif /* HAVE_KRB4 */ +} + +static void +realm_sendit(ZNotice_t *notice, + struct sockaddr_in *who, + int auth, + ZRealm *realm, + int ack_to_sender) +{ + char *pack; + int packlen; + Code_t retval; + Unacked *nacked; + + if (realm->count == 0 || realm->state == REALM_NEW) { + /* XXX we should have a queue or something */ + syslog(LOG_WARNING, "rlm_sendit no servers for %s", realm->name); + return; + } + + notice->z_auth = auth; + notice->z_authent_len = 0; + notice->z_ascii_authent = ""; + notice->z_checksum = 0; + + /* format the notice */ + if ((retval = ZFormatRawNotice(notice, &pack, &packlen)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_sendit format: %s", + error_message(retval)); + return; + } + + /* now send */ + if ((retval = ZSetDestAddr(&realm->srvrs[realm->idx]->addr)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_sendit set addr: %s", + error_message(retval)); + free(pack); + return; + } + if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_sendit xmit: %s", error_message(retval)); + free(pack); + return; + } + + /* now we've sent it, mark it as not ack'ed */ + + if (!(nacked = (Unacked *)malloc(sizeof(Unacked)))) { + /* no space: just punt */ + syslog(LOG_ERR, "rlm_sendit nack malloc"); + free(pack); + return; + } + + memset(nacked, 0, sizeof(Unacked)); + nacked->packet = pack; + nacked->dest.rlm.realm = realm; + nacked->dest.rlm.rlm_srv_idx = realm->idx; + nacked->packsz = packlen; + nacked->uid = notice->z_uid; + if (ack_to_sender) + nacked->ack_addr = *who; + else + nacked->ack_addr.sin_addr.s_addr = 0; + + /* set a timer to retransmit */ + nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked); + /* chain in */ + Unacked_insert(&rlm_nacklist, nacked); + return; +} + +static void +packet_ctl_nack(Unacked *nackpacket) +{ + ZNotice_t notice; + + /* extract the notice */ + ZParseNotice(nackpacket->packet, nackpacket->packsz, ¬ice); + if (nackpacket->ack_addr.sin_addr.s_addr != 0) + nack(¬ice, &nackpacket->ack_addr); + else + syslog(LOG_WARNING, "would have acked nobody (%s/%s/%s)", + notice.z_class, notice.z_class_inst, notice.z_opcode); /* XXX */ +} + +static void +rlm_rexmit(void *arg) +{ + Unacked *nackpacket = (Unacked *) arg; + Code_t retval; + register ZRealm *realm; + + zdbug((LOG_DEBUG,"rlm_rexmit")); + + realm = nackpacket->dest.rlm.realm; + + zdbug((LOG_DEBUG, "rlm_rexmit: sending to %s:%d (%d)", + realm->name, realm->idx, nackpacket->rexmits)); + + if (realm->count == 0 || realm->state == REALM_NEW) + return; + + /* Check to see if we've retransmitted as many times as we can */ + if (nackpacket->rexmits >= (NUM_REXMIT_TIMES * realm->count)) { + /* give a server ack that the packet is lost/realm dead */ + packet_ctl_nack(nackpacket); + Unacked_delete(nackpacket); + + zdbug((LOG_DEBUG, "rlm_rexmit: %s appears dead", realm->name)); + realm->state = REALM_DEAD; + + free(nackpacket->packet); + free(nackpacket); + return; + } + + /* if we've reached our limit, move on to the next server */ + if ((realm->state == REALM_TARDY) || + (nackpacket->rexmits && + !((nackpacket->rexmits+1) % (NUM_REXMIT_TIMES/3)))) + { + realm->idx = realm_next_idx_by_idx(realm, (realm->idx + 1) % + realm->count); + zdbug((LOG_DEBUG, "rlm_rexmit: %s switching servers:%d (%s)", + realm->name, realm->idx, + inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + } + + /* throttle back if it looks like the realm is down */ + if ((realm->state != REALM_DEAD) || + ((nackpacket->rexmits % (realm->count+1)) == 1)) { + /* do the retransmit */ + retval = ZSetDestAddr(&realm->srvrs[realm->idx]->addr); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "rlm_rexmit set addr: %s", + error_message(retval)); + } else { + retval = ZSendPacket(nackpacket->packet, nackpacket->packsz, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "rlm_rexmit xmit: %s", + error_message(retval)); + } + /* no per-server nack queues for foreign realms yet, doesn't matter */ + nackpacket->dest.rlm.rlm_srv_idx = realm->idx; + zdbug((LOG_DEBUG, "rlm_rexmit(%s): send to %s", realm->name, + inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + } else { + zdbug((LOG_DEBUG, "rlm_rexmit(%s): not sending to %s", realm->name, + inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + } + + /* reset the timer */ + nackpacket->rexmits++; + nackpacket->timer = + timer_set_rel(rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES], + rlm_rexmit, nackpacket); + if (rexmit_times[nackpacket->rexmits%NUM_REXMIT_TIMES] == -1) { + zdbug((LOG_DEBUG, "rlm_rexmit(%s): would send at -1 to %s", + realm->name, inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr))); + } + + return; +} + +void +realm_dump_realms(FILE *fp) +{ + register int ii, jj; + + for (ii = 0; ii < nrealms; ii++) { + (void) fprintf(fp, "%d:%s\n", ii, otherrealms[ii]->name); + for (jj = 0; jj < otherrealms[ii]->count; jj++) { + (void) fprintf(fp, "\t%s%s%s%s\n", + inet_ntoa(otherrealms[ii]->srvrs[jj]->addr.sin_addr), + otherrealms[ii]->srvrs[jj]->dontsend ? " nosend" : "", + otherrealms[ii]->srvrs[jj]->got_addr ? " gotaddr" : "", + otherrealms[ii]->srvrs[jj]->deleted ? " deleted" : ""); + } + /* dump the subs */ + subscr_dump_subs(fp, otherrealms[ii]->subs); + } +} + +#ifdef HAVE_KRB5 + +static Code_t +realm_auth_sendit_nacked(char *buffer, int packlen, ZRealm *realm, + ZUnique_Id_t uid, int ack_to_sender, + struct sockaddr_in *who) +{ + Unacked *nacked; + + nacked = (Unacked *) malloc(sizeof(Unacked)); + if (nacked == NULL) + return ENOMEM; + + memset(nacked, 0, sizeof(Unacked)); + nacked->packet = buffer; + nacked->dest.rlm.realm = realm; + nacked->dest.rlm.rlm_srv_idx = realm->idx; + nacked->packsz = packlen; + nacked->uid = uid; + + /* Do the ack for the last frag, below */ + if (ack_to_sender) + nacked->ack_addr = *who; + else + nacked->ack_addr.sin_addr.s_addr = 0; + + /* set a timer to retransmit */ + nacked->timer = timer_set_rel(rexmit_times[0], rlm_rexmit, nacked); + + /* chain in */ + Unacked_insert(&rlm_nacklist, nacked); + + return ZERR_NONE; +} + +static Code_t +realm_sendit_auth(ZNotice_t *notice, + struct sockaddr_in *who, + int auth, + ZRealm *realm, + int ack_to_sender) +{ + char *buffer = NULL; + int hdrlen, offset, fragsize, message_len; + int origoffset, origlen; + Code_t retval; + char multi[64]; + ZNotice_t partnotice, newnotice; + + if (realm->count == 0 || realm->state == REALM_NEW) { + /* XXX we should have a queue or something */ + syslog(LOG_WARNING, "rlm_sendit_auth no servers for %s", realm->name); + return ZERR_INTERNAL; + } + + offset = 0; + + buffer = (char *)malloc(sizeof(ZPacket_t)); + if (!buffer) { + syslog(LOG_ERR, "realm_sendit_auth malloc"); + return ENOMEM; /* DON'T put on nack list */ + } + + newnotice = *notice; + + hdrlen = 0; + retval = ZMakeZcodeRealmAuthentication(&newnotice, buffer, sizeof(ZPacket_t), + &hdrlen, realm->name); + if (retval) + syslog(LOG_WARNING, + "rlm_sendit_auth: ZMakeZcodeRealmAuthentication: %s", + error_message(retval)); + + if (!retval) { + retval = ZSetDestAddr(&realm->srvrs[realm->idx]->addr); + if (retval) + syslog(LOG_WARNING, "rlm_sendit_auth: ZSetDestAddr: %s", + error_message(retval)); + } + + /* This is not terribly pretty, but it does do its job. + * If a packet we get that needs to get sent off to another realm is + * too big after we slap on our authent, we refragment it further, + * a la Z_SendFragmentedNotice. This obviates the need for what + * used to be done in ZFormatAuthenticRealmNotice, as we do it here. + * At some point it should be pulled back out into its own function, + * but only the server uses it. + */ + + if (!retval && + ((notice->z_message_len+hdrlen > (int)sizeof(ZPacket_t)) || + (notice->z_message_len+hdrlen > Z_MAXPKTLEN))) { + + /* Reallocate buffers inside the refragmenter */ + free(buffer); + buffer = NULL; + + partnotice = *notice; + + origoffset = 0; + origlen = notice->z_message_len; + + if (notice->z_multinotice && strcmp(notice->z_multinotice, "")) { + if (sscanf(notice->z_multinotice, "%d/%d", &origoffset, + &origlen) != 2) { + syslog(LOG_WARNING, + "rlm_sendit_auth frag: multinotice parse failed"); + retval = ZERR_BADFIELD; + } + } + + fragsize = Z_MAXPKTLEN - hdrlen - Z_FRAGFUDGE; + + if (fragsize < 0) + retval = ZERR_HEADERLEN; + + while (!retval && + (offset < notice->z_message_len || !notice->z_message_len)) { + (void)sprintf(multi, "%d/%d", offset+origoffset, origlen); + partnotice.z_multinotice = multi; + if (offset > 0) { + (void)Z_gettimeofday(&partnotice.z_uid.tv, + (struct timezone *)0); + partnotice.z_uid.tv.tv_sec = htonl((u_long) + partnotice.z_uid.tv.tv_sec); + partnotice.z_uid.tv.tv_usec = + htonl((u_long) partnotice.z_uid.tv.tv_usec); + (void)memcpy((char *)&partnotice.z_uid.zuid_addr, &__My_addr, + sizeof(__My_addr)); + partnotice.z_sender_sockaddr.ip4.sin_family = AF_INET; /* XXX */ + (void)memcpy((char *)&partnotice.z_sender_sockaddr.ip4.sin_addr, + &__My_addr, sizeof(__My_addr)); + } + message_len = min(notice->z_message_len-offset, fragsize); + partnotice.z_message = notice->z_message+offset; + partnotice.z_message_len = message_len; + + buffer = (char *)malloc(sizeof(ZPacket_t)); + if (!buffer) { + syslog(LOG_ERR, "realm_sendit_auth malloc"); + retval = ENOMEM; /* DON'T put on nack list */ + } + + if (!retval) { + retval = ZMakeZcodeRealmAuthentication(&partnotice, buffer, + sizeof(ZPacket_t), + &hdrlen, + realm->name); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "rlm_sendit_auth set addr: %s", + error_message(retval)); + } + + if (!retval) { + (void) memcpy(buffer + hdrlen, partnotice.z_message, + partnotice.z_message_len); + + retval = ZSendPacket(buffer, + hdrlen + partnotice.z_message_len, 0); + if (retval) + syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s", + error_message(retval)); + } + + if (!retval) { + retval = realm_auth_sendit_nacked(buffer, hdrlen + + partnotice.z_message_len,realm, + partnotice.z_uid, + ack_to_sender, who); + if (retval) /* no space: just punt */ + syslog(LOG_ERR, + "rlm_sendit_auth: realm_auth_sendit_nacked: %s", + error_message(retval)); + } + + if (!retval) + offset += fragsize; + + if (!notice->z_message_len) + break; + } + } else if (!retval) { + /* This is easy, no further fragmentation needed */ + (void)memcpy(buffer + hdrlen, newnotice.z_message, + newnotice.z_message_len); + + retval = ZSendPacket(buffer, hdrlen + newnotice.z_message_len, 0); + if (retval) + syslog(LOG_WARNING, "rlm_sendit_auth xmit: %s", + error_message(retval)); + else { + retval = realm_auth_sendit_nacked(buffer, + hdrlen + newnotice.z_message_len, + realm, newnotice.z_uid, + ack_to_sender, who); + if (retval) /* no space: just punt */ + syslog(LOG_ERR, "rlm_sendit_auth: realm_auth_sendit_nacked: %s", + error_message(retval)); + } + } + + if (retval && buffer != NULL) + free(buffer); + return retval; +} + +static int +ticket_lookup(char *realm) +{ + krb5_error_code result; + krb5_timestamp sec; + krb5_ccache ccache; + krb5_creds creds_in, creds; + + result = krb5_cc_default(Z_krb5_ctx, &ccache); + if (result) + return 0; + + memset(&creds_in, 0, sizeof(creds_in)); + memset(&creds, 0, sizeof(creds)); + + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client); + if (result) { + krb5_cc_close(Z_krb5_ctx, ccache); + return 0; + } + + result = krb5_build_principal(Z_krb5_ctx, &creds_in.server, + strlen(realm), + realm, + SERVER_KRB5_SERVICE, SERVER_INSTANCE, + NULL); + if (result) { + krb5_cc_close(Z_krb5_ctx, ccache); + return 0; + } + + result = krb5_cc_retrieve_cred(Z_krb5_ctx, ccache, 0, &creds_in, &creds); + krb5_cc_close(Z_krb5_ctx, ccache); + /* good ticket? */ + + krb5_timeofday (Z_krb5_ctx, &sec); + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */ + if ((result == 0) && (sec < creds.times.endtime)) { + krb5_free_cred_contents(Z_krb5_ctx, &creds); + return (1); + } + if (!result) + krb5_free_cred_contents(Z_krb5_ctx, &creds); + + return (0); +} + +static Code_t +ticket_retrieve(ZRealm *realm) +{ + int pid; + krb5_ccache ccache; + krb5_error_code result; + krb5_creds creds_in, *creds; + + get_tgt(); + + if (realm->child_pid) + /* Right idea. Basically, we haven't gotten it yet */ + return KRB5KRB_AP_ERR_TKT_EXPIRED; + + if (realm->have_tkt) { + /* Get a pointer to the default ccache. We don't need to free this. */ + result = krb5_cc_default(Z_krb5_ctx, &ccache); + + /* GRRR. There's no allocator or constructor for krb5_creds */ + /* GRRR. It would be nice if this API were documented at all */ + memset(&creds_in, 0, sizeof(creds_in)); + + if (!result) + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, &creds_in.client); + /* construct the service principal */ + if (!result) + result = krb5_build_principal(Z_krb5_ctx, &creds_in.server, + strlen(realm->name), realm->name, + SERVER_KRB5_SERVICE, SERVER_INSTANCE, + NULL); + + /* HOLDING: creds_in.server */ + + /* look up or get the credentials we need */ + if (!result) + result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache, + &creds_in, &creds); + krb5_cc_close(Z_krb5_ctx, ccache); + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */ + if (!result) { + krb5_free_creds(Z_krb5_ctx, creds); + return 0; + } + } else { + syslog(LOG_ERR, "tkt_rtrv: don't have ticket, but have no child"); + result = KRB5KRB_AP_ERR_TKT_EXPIRED; + } + + pid = fork(); + if (pid < 0) { + syslog(LOG_ERR, "tkt_rtrv: can't fork"); + return errno; + } + else if (pid == 0) { +#ifdef _POSIX_VERSION + struct sigaction action; + + action.sa_flags = 0; + sigemptyset(&action.sa_mask); + action.sa_handler = 0; + sigaction(SIGCHLD, &action, NULL); + sigaction(SIGINT, &action, NULL); + sigaction(SIGTERM, &action, NULL); + sigaction(SIGUSR1, &action, NULL); + sigaction(SIGUSR2, &action, NULL); + sigaction(SIGFPE, &action, NULL); + sigaction(SIGHUP, &action, NULL); +#ifdef SIGEMT + sigaction(SIGEMT, &action, NULL); +#endif +#else + signal(SIGCHLD, SIG_DFL); + signal(SIGINT, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGUSR1, SIG_DFL); + signal(SIGUSR2, SIG_DFL); + signal(SIGFPE, SIG_DFL); + signal(SIGHUP, SIG_DFL); +#ifdef SIGEMT + signal(SIGEMT, SIG_DFL); +#endif +#endif + + syslog(LOG_INFO, "tkt_rtrv running for %s", realm->name); + while (1) { + /* Get a pointer to the default ccache. + We don't need to free this. */ + result = krb5_cc_default(Z_krb5_ctx, &ccache); + + /* GRRR. There's no allocator or constructor for krb5_creds */ + /* GRRR. It would be nice if this API were documented at all */ + memset(&creds_in, 0, sizeof(creds_in)); + + if (!result) + result = krb5_cc_get_principal(Z_krb5_ctx, ccache, + &creds_in.client); + /* construct the service principal */ + if (!result) + result = krb5_build_principal(Z_krb5_ctx, &creds_in.server, + strlen(realm->name), realm->name, + SERVER_KRB5_SERVICE, + SERVER_INSTANCE, + NULL); + + /* HOLDING: creds_in.server */ + + /* look up or get the credentials we need */ + if (!result) + result = krb5_get_credentials(Z_krb5_ctx, 0 /* flags */, ccache, + &creds_in, &creds); + krb5_cc_close(Z_krb5_ctx, ccache); + krb5_free_cred_contents(Z_krb5_ctx, &creds_in); /* hope this is OK */ + if (!result) { + krb5_free_creds(Z_krb5_ctx, creds); + syslog(LOG_INFO, "tkt_rtrv succeeded for %s", realm->name); + exit(0); + } + + /* Sleep a little while before retrying */ + sleep(30); + } + } else { + realm->child_pid = pid; + realm->have_tkt = 0; + + syslog(LOG_WARNING, "tkt_rtrv: %s: %d", realm->name, + result); + return (result); + } +} +#endif /* HAVE_KRB5 */ diff --git a/server/server.c b/server/server.c new file mode 100644 index 0000000..54d40ca --- /dev/null +++ b/server/server.c @@ -0,0 +1,1485 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for communication with other servers. + * + * Created by: John T. Kohl + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987, 1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include + +#ifndef lint +#ifndef SABER +static const char rcsid_server_c[] = "$Id$"; +#endif +#endif + +enum { + SRV_NACKTAB_HASHSIZE = 1023 +}; +inline static unsigned int +srv_nacktab_hashval(int which, ZUnique_Id_t uid) { + return (which ^ + uid.zuid_addr.s_addr ^ uid.tv.tv_sec ^ uid.tv.tv_usec) + % SRV_NACKTAB_HASHSIZE; +} + +/* + * Server manager. Deal with traffic to and from other servers. + * + * void server_init() + * + * void server_shutdown() + * + * void server_timo(which) + * Server *which; + * + * void server_dispatch(notice, auth, who) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * + * void server_recover(client) + * Client *client; + * + * void server_adispatch(notice, auth, who, server) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * Server *server; + * + * void server_forward(notice, auth, who) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * + * Server *server_which_server(who) + * struct sockaddr_in *who; + * + * void server_kill_clt(client); + * Client *client; + * + * void server_dump_servers(fp); + * FILE *fp; + * + * void server_reset(); + */ + +static void server_flush(Server *); +static void hello_respond(struct sockaddr_in *, int, int); +static void srv_responded(struct sockaddr_in *); +static void send_msg(struct sockaddr_in *, char *, int); +static void send_msg_list(struct sockaddr_in *, char *, char **, int, + int); +static void srv_nack_cancel(ZNotice_t *, struct sockaddr_in *); +static void srv_nack_release(Server *); +static void srv_nack_renumber (int *); +static void send_stats(struct sockaddr_in *); +static void server_queue(Server *, int, void *, int, + struct sockaddr_in *); +static void server_hello(Server *, int); +static void setup_server(Server *, struct in_addr *); +static void srv_rexmit(void *); +static void server_forw_reliable(Server *, void *, int, ZNotice_t *); +static Code_t admin_dispatch(ZNotice_t *, int, struct sockaddr_in *, + Server *); +static Code_t kill_clt(ZNotice_t *, Server *); +static Code_t extract_addr(ZNotice_t *, struct sockaddr_in *); + +static struct in_addr *get_server_addrs(int *number); +static char **get_server_list(char *file); +static char **get_single_server(void); +static void free_server_list(char **list); + +static Unacked *srv_nacktab[SRV_NACKTAB_HASHSIZE]; +Server *otherservers; /* points to an array of the known + servers */ +int nservers; /* number of other servers */ +int me_server_idx; /* # of my entry in the array */ + +#define ADJUST (1) /* adjust timeout on hello input */ +#define DONT_ADJUST (0) /* don't adjust timeout */ + +/* parameters controlling the transitions of the FSM's--patchable with adb */ +long timo_up = TIMO_UP; +long timo_tardy = TIMO_TARDY; +long timo_dead = TIMO_DEAD; + +/* + * Initialize the array of servers. The `limbo' server goes in the first + * slot (otherservers[0]). + * Contact Hesiod to find all the other servers, allocate space for the + * structure, initialize them all to SERV_DEAD with expired timeouts. + * Set up a list header for server_forward retransmits. + */ + +void +server_init(void) +{ + int i; + struct in_addr *serv_addr, *server_addrs, limbo_addr; + + /* we don't need to mask SIGFPE here since when we are called, + the signal handler isn't set up yet. */ + + /* talk to hesiod here, set nservers */ + server_addrs = get_server_addrs(&nservers); + if (!server_addrs) { + syslog(LOG_ERR, "No servers?!?"); + exit(1); + } + +#ifdef DEBUG + if (zalone) + nservers = 1; + else +#endif /* DEBUG */ + /* increment servers to make room for 'limbo' */ + nservers++; + + otherservers = (Server *) malloc(nservers * sizeof(Server)); + me_server_idx = -1; + + /* set up limbo */ + limbo_addr.s_addr = 0; + setup_server(otherservers, &limbo_addr); + timer_reset(otherservers[0].timer); + otherservers[0].timer = NULL; + otherservers[0].queue = NULL; + otherservers[0].dumping = 0; + + for (serv_addr = server_addrs, i = 1; i < nservers; serv_addr++, i++) { + setup_server(&otherservers[i], serv_addr); + /* is this me? */ + if (serv_addr->s_addr == my_addr.s_addr) { + me_server_idx = i; + otherservers[i].state = SERV_UP; + timer_reset(otherservers[i].timer); + otherservers[i].timer = NULL; + otherservers[i].queue = NULL; + otherservers[i].dumping = 0; + } + } + + /* free up the addresses */ + free(server_addrs); + + if (me_server_idx == -1) { + syslog(LOG_WARNING, "I'm a renegade server!"); + otherservers = (Server *) realloc(otherservers, + ++nservers * sizeof(Server)); + if (!otherservers) { + syslog(LOG_CRIT, "renegade realloc"); + abort(); + } + setup_server(&otherservers[nservers - 1], &my_addr); + /* we are up. */ + otherservers[nservers - 1].state = SERV_UP; + + /* I don't send hello's to myself--cancel the timer */ + timer_reset(otherservers[nservers - 1].timer); + otherservers[nservers - 1].timer = NULL; + + /* cancel and reschedule all the timers--pointers need + adjusting */ + /* don't reschedule limbo's timer, so start i=1 */ + for (i = 1; i < nservers - 1; i++) { + timer_reset(otherservers[i].timer); + /* all the HELLO's are due now */ + otherservers[i].timer = timer_set_rel(0L, server_timo, + &otherservers[i]); + } + me_server_idx = nservers - 1; + } + +} + +/* + * server_reset: re-initializes otherservers array by refreshing from Hesiod + * or disk file. + * + * If any server is no longer named in the new list, and that server is in + * state SERV_DEAD, it is dropped from the server list. + * All other currently-known servers are retained. + * Any additional servers not previously known are added to the table. + * + * WARNING: Don't call this routine if any of the ancestor procedures have a + * handle on a particular server other than by indexing on otherservers[]. + */ +void +server_reset(void) +{ + int num_servers; + struct in_addr *server_addrs; + struct in_addr *serv_addr; + Server *servers; + int i, j; + int *ok_list_new, *ok_list_old; + int num_ok, new_num; + +#ifdef DEBUG + if (zalone) { + syslog(LOG_INFO, "server_reset while alone, punt"); + return; + } +#endif /* DEBUG */ + + /* Find out what servers are supposed to be known. */ + server_addrs = get_server_addrs(&num_servers); + if (!server_addrs) { + syslog(LOG_ERR, "server_reset no servers. nothing done."); + return; + } + ok_list_new = (int *) malloc(num_servers * sizeof(int)); + if (!ok_list_new) { + syslog(LOG_ERR, "server_reset no mem new"); + return; + } + ok_list_old = (int *) malloc(nservers * sizeof(int)); + if (!ok_list_old) { + syslog(LOG_ERR, "server_reset no mem old"); + free(ok_list_new); + return; + } + + memset(ok_list_old, 0, nservers * sizeof(int)); + memset(ok_list_new, 0, num_servers * sizeof(int)); + + /* reset timers--pointers will move */ + for (j = 1; j < nservers; j++) { /* skip limbo */ + if (j == me_server_idx) + continue; + timer_reset(otherservers[j].timer); + otherservers[j].timer = NULL; + } + + /* check off entries on new list which are on old list. + check off entries on old list which are on new list. */ + + /* count limbo as "OK" */ + num_ok = 1; + ok_list_old[0] = 1; /* limbo is OK */ + + for (serv_addr = server_addrs, i = 0; i < num_servers; serv_addr++, i++) { + for (j = 1; j < nservers; j++) { /* j = 1 since we skip limbo */ + if (otherservers[j].addr.sin_addr.s_addr == serv_addr->s_addr) { + /* if server is on both lists, mark */ + ok_list_new[i] = 1; + ok_list_old[j] = 1; + num_ok++; + break; /* for j loop */ + } + } + } + + /* remove any dead servers on old list not on new list. */ + if (num_ok < nservers) { + int *srv; + + new_num = 1; /* limbo */ + /* count number of servers to keep */ + for (j = 1; j < nservers; j++) { + /* since we are never SERV_DEAD, the following + test prevents removing ourself from the list */ + if (ok_list_old[j] || (otherservers[j].state != SERV_DEAD)) { + syslog(LOG_INFO, "keeping server %s", + otherservers[j].addr_str); + new_num++; + } + } + if (new_num < nservers) { + servers = (Server *) malloc(new_num * sizeof(Server)); + if (!servers) { + syslog(LOG_CRIT, "server_reset server malloc"); + abort(); + } + i = 1; + servers[0] = otherservers[0]; /* copy limbo */ + + srv = (int *) malloc(nservers * sizeof(int)); + memset(srv, 0, nservers * sizeof(int)); + + /* copy the kept servers */ + for (j = 1; j < nservers; j++) { /* skip limbo */ + if (ok_list_old[j] || + otherservers[j].state != SERV_DEAD) { + servers[i] = otherservers[j]; + srv[j] = i; + i++; + } else { + syslog(LOG_INFO, "flushing server %s", + otherservers[j].addr_str); + server_flush(&otherservers[j]); + srv[j] = -1; + } + + } + srv_nack_renumber(srv); + + free(srv); + free(otherservers); + otherservers = servers; + nservers = new_num; + } + } + + /* add any new servers on new list not on old list. */ + new_num = 0; + for (i = 0; i < num_servers; i++) { + if (!ok_list_new[i]) + new_num++; + } + + /* new_num is number of extras. */ + nservers += new_num; + otherservers = (Server *) realloc(otherservers, nservers * sizeof(Server)); + if (!otherservers) { + syslog(LOG_CRIT, "server_reset realloc"); + abort(); + } + + me_server_idx = 0; + for (j = 1; j < nservers - new_num; j++) { + if (otherservers[j].addr.sin_addr.s_addr == my_addr.s_addr) { + me_server_idx = j; + break; + } + } + if (!me_server_idx) { + syslog(LOG_CRIT, "can't find myself"); + abort(); + } + + /* fill in otherservers with the new servers */ + for (i = 0; i < num_servers; i++) { + if (!ok_list_new[i]) { + setup_server(&otherservers[nservers - (new_num--)], + &server_addrs[i]); + syslog(LOG_INFO, "adding server %s", inet_ntoa(server_addrs[i])); + } + } + + free(server_addrs); + /* reset timers, to go off now. + We can't get a time-left indication (bleagh!) + so we expire them all now. This will generally + be non-destructive. We assume that when this code is + entered via a SIGHUP trigger that a system wizard + is watching the goings-on to make sure things straighten + themselves out. + */ + for (i = 1; i < nservers; i++) { /* skip limbo */ + if (i != me_server_idx && !otherservers[i].timer) { + otherservers[i].timer = + timer_set_rel(0L, server_timo, &otherservers[i]); + } + } + free(ok_list_old); + free(ok_list_new); + +} + +/* note: these must match the order given in zserver.h */ +static char * +srv_states[] = { + "SERV_UP", + "SERV_TARDY", + "SERV_DEAD", + "SERV_STARTING" +}; +static char * +rlm_states[] = { + "REALM_NEW", + "REALM_UP", + "REALM_TARDY", + "REALM_DEAD", + "REALM_STARTING" +}; + +/* + * A server timout has expired. If enough hello's have been unanswered, + * change state and act accordingly. Send a "hello" and reset the timer, + * incrementing the number of hello's sent. + * + * See the FSM in the Zephyr document for a better picture of what's + * happening here. + */ + +void +server_timo(void *arg) +{ + Server *which = (Server *) arg; + int auth = 0; + + /* change state and reset if appropriate */ + switch(which->state) { + case SERV_DEAD: /* leave him dead */ + server_flush(which); + auth = 1; + break; + case SERV_UP: /* he's now tardy */ + which->state = SERV_TARDY; + which->num_hello_sent = 0; + which->timeout = timo_tardy; + auth = 0; + break; + case SERV_TARDY: + case SERV_STARTING: + if (which->num_hello_sent >= ((which->state == SERV_TARDY) ? + H_NUM_TARDY : + H_NUM_STARTING)) { + /* he hasn't answered, assume DEAD */ + which->state = SERV_DEAD; + which->num_hello_sent = 0; + which->timeout = timo_dead; + srv_nack_release(which); + } + auth = 0; + break; + default: + syslog(LOG_ERR,"Bad server state, server 0x%p\n", (void *)which); + abort(); + } + /* now he's either TARDY, STARTING, or DEAD + We send a "hello," which increments the counter */ + server_hello(which, auth); + /* reschedule the timer */ + which->timer = timer_set_rel(which->timeout, server_timo, which); +} + +/* + * Dispatch a notice from some other server + */ + +/*ARGSUSED*/ +Code_t +server_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who) +{ + Server *server; + struct sockaddr_in newwho; + Code_t status; + String *notice_class; + + + if (notice->z_kind == SERVACK) { + srv_nack_cancel(notice, who); + srv_responded(who); + return ZERR_NONE; + } + /* set up a who for the real origin */ + notice_extract_address(notice, &newwho); + + server = server_which_server(who); + + /* we can dispatch to routines safely here, since they will + return ZSRV_REQUEUE if appropriate. We bounce this back + to the caller, and the caller will re-queue the message + for us to process later. */ + + notice_class = make_string(notice->z_class, 1); + + if (realm_which_realm(&newwho)) + status = realm_dispatch(notice, auth, &newwho, server); + else if (class_is_admin(notice_class)) { + /* admins don't get acked, else we get a packet loop */ + /* will return requeue if bdump request and dumping */ + i_s_admins.val++; + return admin_dispatch(notice, auth, who, server); + } else if (class_is_control(notice_class)) { + status = control_dispatch(notice, auth, &newwho, server); + i_s_ctls.val++; + } else if (class_is_ulogin(notice_class)) { + status = ulogin_dispatch(notice, auth, &newwho, server); + i_s_logins.val++; + } else if (class_is_ulocate(notice_class)) { + status = ulocate_dispatch(notice, auth, &newwho, server); + i_s_locates.val++; + } else { + /* shouldn't come from another server */ + syslog(LOG_WARNING, "srv_disp: pkt cls %s", notice->z_class); + status = ZERR_NONE; /* XXX */ + } + if (status != ZSRV_REQUEUE) + ack(notice, who); /* acknowledge it if processed */ + free_string(notice_class); + return status; +} + +/* + * Tell the other servers that this client died. + */ + +void +server_kill_clt(Client *client) +{ + int i; + char buf[512], *lyst[2]; + ZNotice_t notice; + ZNotice_t *pnotice; /* speed hack */ + char *pack; + int packlen, auth; + Code_t retval; + + lyst[0] = inet_ntoa(client->addr.sin_addr), + sprintf(buf, "%d", ntohs(client->addr.sin_port)); + lyst[1] = buf; + + pnotice = ¬ice; + + memset (¬ice, 0, sizeof(notice)); + + pnotice->z_kind = ACKED; + + pnotice->z_port = srv_addr.sin_port; + pnotice->z_class = ZEPHYR_ADMIN_CLASS; + pnotice->z_class_inst = ""; + pnotice->z_opcode = ADMIN_KILL_CLT; + pnotice->z_sender = myname; /* myname is the hostname */ + pnotice->z_recipient = ""; + pnotice->z_default_format = ""; + pnotice->z_num_other_fields = 0; + + /* XXX */ + auth = 0; + + /* don't tell limbo to flush, start at 1*/ + for (i = 1; i < nservers; i++) { + if (i == me_server_idx) /* don't xmit to myself */ + continue; + if (otherservers[i].state == SERV_DEAD) + continue; + + retval = ZFormatNoticeList(pnotice, lyst, 2, &pack, &packlen, + auth ? ZAUTH : ZNOAUTH); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "kill_clt format: %s", error_message(retval)); + return; + } + server_forw_reliable(&otherservers[i], pack, packlen, pnotice); + } +} + +/* + * A client has died. remove it + */ + +static Code_t +kill_clt(ZNotice_t *notice, + Server *server) +{ + struct sockaddr_in who; + Client *client; + + if (extract_addr(notice, &who) != ZERR_NONE) + return ZERR_NONE; /* XXX */ + client = client_find(&who.sin_addr, notice->z_port); + if (!client) { + syslog(LOG_NOTICE, "kill_clt: no such client (%s/%d) from %s", + inet_ntoa(who.sin_addr), ntohs(who.sin_port), + server->addr_str); + return ZERR_NONE; /* XXX */ + } + + if (zdebug) { + syslog(LOG_DEBUG, "kill_clt clt_dereg %s/%d from %s", + inet_ntoa(who.sin_addr), ntohs(who.sin_port), server->addr_str); + } + + /* remove the locations, too */ + client_deregister(client, 1); + return ZERR_NONE; +} + +/* + * extract a sockaddr_in from a message body + */ + +static Code_t +extract_addr(ZNotice_t *notice, + struct sockaddr_in *who) +{ + char *cp = notice->z_message; + + if (!notice->z_message_len) { + syslog(LOG_WARNING, "bad addr pkt"); + return ZSRV_PKSHORT; + } + who->sin_addr.s_addr = inet_addr(notice->z_message); + + cp += strlen(cp) + 1; + if (cp >= notice->z_message + notice->z_message_len) { + syslog(LOG_WARNING, "short addr pkt"); + return ZSRV_PKSHORT; + } + who->sin_port = notice->z_port = htons((u_short) atoi(cp)); + who->sin_family = AF_INET; + return ZERR_NONE; +} + +/* + * Flush all data associated with the server which + */ + +static void +server_flush(Server *which) +{ + srv_nack_release(which); +} + +/* + * send a hello to which, updating the count of hello's sent + * Authenticate if auth is set. + */ + +static void +server_hello(Server *which, + int auth) +{ + send_msg(&which->addr, ADMIN_HELLO, auth); + which->num_hello_sent++; +} + +/* + * Handle an ADMIN message from a server + */ + +/*ARGSUSED*/ +static Code_t +admin_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + char *opcode = notice->z_opcode; + Code_t status = ZERR_NONE; + + if (strcmp(opcode, ADMIN_HELLO) == 0) { + hello_respond(who, ADJUST, auth); + } else if (strcmp(opcode, ADMIN_IMHERE) == 0) { + srv_responded(who); + } else if (strcmp(opcode, ADMIN_SHUTDOWN) == 0) { + if (server) { + srv_nack_release(server); + server->state = SERV_DEAD; + server->timeout = timo_dead; + /* don't worry about the timer, it will + be set appropriately on the next send */ + } + } else if (strcmp(opcode, ADMIN_BDUMP) == 0) { + /* Ignore a brain dump request if this is a brain dump packet + * or a packet being processed concurrently during a brain + * dump. */ + if (bdumping || bdump_concurrent) + return ZERR_NONE; + bdump_get(notice, auth, who, server); + } else if (strcmp(opcode, ADMIN_KILL_CLT) == 0) { + status = kill_clt(notice, server); + if (status == ZERR_NONE) + ack(notice, who); + } else { + syslog(LOG_WARNING, "ADMIN unknown opcode %s",opcode); + } + return status; +} + + +/* + * Handle an ADMIN message from some random client. + * For now, assume it's a registration-type message from some other + * previously unknown server + */ + +/*ARGSUSED*/ +Code_t +server_adispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + + /* this had better be a HELLO message--start of acquisition + protocol, OR a status req packet */ + + if (strcmp(notice->z_opcode, ADMIN_STATUS) == 0) { + /* status packet */ + send_stats(who); + return ZERR_NONE; + } + + syslog(LOG_INFO, "srv_adisp: server attempt from %s", + inet_ntoa(who->sin_addr)); + + return ZERR_NONE; +} + +static void +send_stats(struct sockaddr_in *who) +{ + int i; + char buf[BUFSIZ]; + char **responses; + int num_resp; + char *vers, *pkts, *upt; + ZRealm *realm; + + int extrafields = 0; +#define NUM_FIXED 3 /* 3 fixed fields, plus server info */ + /* well, not really...but for + backward compatibility, we gotta + do it this way. */ + vers = get_version(); + + sprintf(buf, "%lu pkts", npackets); + pkts = strsave(buf); + sprintf(buf, "%ld seconds operational",NOW - uptime); + upt = strsave(buf); + + extrafields += nrealms; + responses = (char **) malloc((NUM_FIXED + nservers + extrafields) * + sizeof(char *)); + responses[0] = vers; + responses[1] = pkts; + responses[2] = upt; + + num_resp = NUM_FIXED; + /* start at 1 and ignore limbo */ + for (i = 1; i < nservers ; i++) { + sprintf(buf, "%s/%s%s", otherservers[i].addr_str, + srv_states[(int) otherservers[i].state], + otherservers[i].dumping ? " (DUMPING)" : ""); + responses[num_resp++] = strsave(buf); + } + for (i = 0; i < nrealms ; i++) { + realm = otherrealms[i]; + sprintf(buf, "%s(%s)/%s", realm->name, + inet_ntoa((realm->srvrs[realm->idx]->addr).sin_addr), + rlm_states[(int) realm->state]); + responses[num_resp++] = strsave(buf); + } + + send_msg_list(who, ADMIN_STATUS, responses, num_resp, 0); + + /* Start at one; don't try to free static version string */ + for (i = 1; i < num_resp; i++) + free(responses[i]); + free(responses); +} + +/* + * Get a list of server addresses. +#ifdef HAVE_HESIOD + * This list is retrieved from Hesiod. +#else + * This list is read from a file. +#endif + * Return a pointer to an array of allocated storage. This storage is + * freed by the caller. + */ + +static struct in_addr * +get_server_addrs(int *number) +{ + int i; + char **server_hosts = NULL; + char **server_hosts_free = NULL; + char **cpp; + struct in_addr *addrs; + struct in_addr *addr; + struct hostent *hp; + + server_hosts = get_server_list(list_file); + server_hosts_free = server_hosts; +#ifdef HAVE_HESIOD + if (!server_hosts) + server_hosts = hes_resolve("zephyr","sloc"); +#endif + if (!server_hosts) { + server_hosts = get_single_server(); + server_hosts_free = server_hosts; + } + if (!server_hosts) + return NULL; + /* count up */ + i = 0; + for (cpp = server_hosts; *cpp; cpp++) + i++; + + addrs = (struct in_addr *) malloc(i * sizeof(struct in_addr)); + + /* Convert to in_addr's */ + for (cpp = server_hosts, addr = addrs, i = 0; *cpp; cpp++) { + hp = gethostbyname(*cpp); + if (hp) { + memcpy(addr, hp->h_addr, sizeof(struct in_addr)); + addr++, i++; + } else { + syslog(LOG_WARNING, "hostname failed, %s", *cpp); + } + } + *number = i; + if (server_hosts_free) + free_server_list(server_hosts_free); + return addrs; +} + +static int nhosts = 0; + +/* + * read "file" to get a list of names of hosts to peer with. + * The file should contain a list of host names, one per line. + */ + +static char ** +get_server_list(char *file) +{ + FILE *fp; + char buf[NS_MAXDNAME]; + char **ret_list; + int nused = 0; + char *newline; + + fp = fopen(file, "r"); + if (!fp) + return NULL; + /* start with 16, realloc if necessary */ + nhosts = 16; + ret_list = (char **) malloc(nhosts * sizeof(char *)); + if (!ret_list) + return NULL; + + while (fgets(buf, sizeof(buf), fp)) { + /* nuke the newline, being careful not to overrun + the buffer searching for it with strlen() */ + buf[sizeof(buf) - 1] = '\0'; + newline = strchr(buf, '\n'); + if (newline) + *newline = '\0'; + + if (nused + 1 >= nhosts) { + /* get more pointer space if necessary */ + /* +1 to leave room for null pointer */ + ret_list = (char **) realloc(ret_list, nhosts * 2); + nhosts = nhosts * 2; + } + ret_list[nused++] = strsave(buf); + } + fclose(fp); + if (!nused) { + free(ret_list); + return NULL; + } + ret_list[nused] = NULL; + return ret_list; +} + +static char ** +get_single_server(void) +{ + char buf[NS_MAXDNAME]; + char **ret_list; + int nused = 0; + nhosts = 2; + ret_list = (char **) malloc(nhosts * sizeof(char *)); + if (!ret_list) + return NULL; + if (gethostname(buf, sizeof(buf)) < 0) { + free(ret_list); + return NULL; + } + ret_list[nused++] = strsave(buf); + ret_list[nused] = NULL; + return ret_list; +} + +/* + * free storage allocated by get_server_list + */ +static void +free_server_list(char **list) +{ + char **orig_list = list; + + if (!nhosts) /* nothing allocated */ + return; + for (; *list; list++) + free(*list); + free(orig_list); + return; +} + +/* + * initialize the server structure for address addr, and set a timer + * to go off immediately to send hello's to other servers. + */ + +static void +setup_server(Server *server, + struct in_addr *addr) +{ + server->state = SERV_DEAD; + server->timeout = timo_dead; + server->num_hello_sent = 0; + server->addr.sin_family = AF_INET; + /* he listens to the same port we do */ + server->addr.sin_port = srv_addr.sin_port; + server->addr.sin_addr = *addr; + strcpy(server->addr_str, inet_ntoa(*addr)); + server->timer = timer_set_rel(0L, server_timo, server); + server->queue = NULL; + server->dumping = 0; +} + +/* + * Someone sent us a hello message, respond to them. + */ + +static void +hello_respond(struct sockaddr_in *who, + int adj, + int auth) +{ + Server *which; + + send_msg(who, ADMIN_IMHERE, auth); + if (adj != ADJUST) + return; + + /* If we think he's down, schedule an immediate HELLO. */ + + which = server_which_server(who); + if (!which) + return; + + switch (which->state) { + case SERV_DEAD: + /* he said hello, we thought he was dead. + reschedule his hello for now. */ + timer_reset(which->timer); + which->timer = timer_set_rel(0L, server_timo, which); + break; + case SERV_STARTING: + case SERV_TARDY: + case SERV_UP: + default: + break; + } +} + +/* + * return the server descriptor for server at who + */ + +Server * +server_which_server(struct sockaddr_in *who) +{ + Server *server; + int i; + + if (who->sin_port != srv_addr.sin_port) + return NULL; + + /* don't check limbo */ + for (server = &otherservers[1], i = 1; i < nservers; i++, server++) { + if (server->addr.sin_addr.s_addr == who->sin_addr.s_addr) + return server; + } + return NULL; +} + +/* + * We received a response to a hello packet or an ack. Adjust server state + * appropriately. + */ +static void +srv_responded(struct sockaddr_in *who) +{ + Server *which = server_which_server(who); + + if (!which) { + syslog(LOG_ERR, "hello input from non-server?!"); + return; + } + + switch (which->state) { + case SERV_DEAD: + /* he responded, we thought he was dead. mark as starting + and negotiate */ + which->state = SERV_STARTING; + which->timeout = timo_tardy; + timer_reset(which->timer); + which->timer = timer_set_rel(0L, server_timo, which); + + case SERV_STARTING: + /* here we negotiate and set up a braindump */ + if (bdump_socket < 0) + bdump_offer(who); + break; + + case SERV_TARDY: + which->state = SERV_UP; + /* Fall through. */ + + case SERV_UP: + /* reset the timer and counts */ + which->num_hello_sent = 0; + which->timeout = timo_up; + timer_reset(which->timer); + which->timer = timer_set_rel(which->timeout, server_timo, which); + break; + } +} + +/* + * Send each of the other servers a shutdown message. + */ + +void +server_shutdown(void) +{ + int i; + + /* don't tell limbo to go away, start at 1*/ + for (i = 1; i < nservers; i++) + send_msg(&otherservers[i].addr, ADMIN_SHUTDOWN, 1); +} + +/* + * send a message to who with admin class and opcode and clinst as specified. + * auth is set if we want to send authenticated + */ + +static void +send_msg(struct sockaddr_in *who, + char *opcode, + int auth) +{ + ZNotice_t notice; + ZNotice_t *pnotice; /* speed hack */ + char *pack; + int packlen; + Code_t retval; + + pnotice = ¬ice; + + memset (¬ice, 0, sizeof(notice)); + + pnotice->z_kind = ACKED; + + pnotice->z_port = srv_addr.sin_port; + pnotice->z_class = ZEPHYR_ADMIN_CLASS; + pnotice->z_class_inst = ""; + pnotice->z_opcode = opcode; + pnotice->z_sender = myname; /* myname is the hostname */ + pnotice->z_recipient = ""; + pnotice->z_default_format = ""; + pnotice->z_message = NULL; + pnotice->z_message_len = 0; + pnotice->z_num_other_fields = 0; + + /* XXX for now, we don't do authentication */ + auth = 0; + + retval = ZFormatNotice(pnotice, &pack, &packlen, auth ? ZAUTH : ZNOAUTH); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg format: %s", error_message(retval)); + return; + } + retval = ZSetDestAddr(who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg set addr: %s", error_message(retval)); + free(pack); + return; + } + /* don't wait for ack */ + retval = ZSendPacket(pack, packlen, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "snd_msg xmit: %s", error_message(retval)); + free(pack); +} + +/* + * send a notice with a message to who with admin class and opcode and + * message body as specified. + * auth is set if we want to send authenticated + * server_idx is -1 if we are sending to a client, or the server index + * if we are sending to a server. + */ + +static void +send_msg_list(struct sockaddr_in *who, + char *opcode, + char **lyst, + int num, + int auth) +{ + ZNotice_t notice; + char *pack; + int packlen; + Code_t retval; + + memset (¬ice, 0, sizeof(notice)); + + notice.z_kind = UNSAFE; + notice.z_port = srv_addr.sin_port; + notice.z_class = ZEPHYR_ADMIN_CLASS; + notice.z_class_inst = ""; + notice.z_opcode = opcode; + notice.z_sender = myname; /* myname is the hostname */ + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_message = NULL; + notice.z_message_len = 0; + notice.z_num_other_fields = 0; + + /* XXX for now, we don't do authentication */ + auth = 0; + + retval = ZFormatNoticeList(¬ice, lyst, num, &pack, &packlen, + auth ? ZAUTH : ZNOAUTH); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg_lst format: %s", error_message(retval)); + return; + } + retval = ZSetDestAddr(who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "snd_msg_lst set addr: %s", error_message(retval)); + free(pack); + return; + } + xmit_frag(¬ice, pack, packlen, 0); + free(pack); +} + +/* + * Forward the notice to the other servers + */ +/*ARGSUSED*/ +void +server_forward(ZNotice_t *notice, + int auth, + struct sockaddr_in *who) +{ + int i; + void *pack; + int packlen; + Code_t retval; + + /* don't send to limbo */ + for (i = 1; i < nservers; i++) { + if (i == me_server_idx) /* don't xmit to myself */ + continue; + if (otherservers[i].state == SERV_DEAD && + otherservers[i].dumping == 0) { + /* if we are dumping to him, we want to + queue it, even if he's dead */ + continue; + } + + pack = malloc(sizeof(ZPacket_t)); + if (!pack) { + syslog(LOG_CRIT, "srv_fwd malloc"); + abort(); + } + retval = ZNewFormatSmallRawNotice(notice, pack, &packlen); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "srv_fwd format: %s", error_message(retval)); + free(pack); + continue; + } + if (otherservers[i].dumping) { + server_queue(&otherservers[i], packlen, pack, auth, who); + continue; + } + server_forw_reliable(&otherservers[i], pack, packlen, notice); + } +} + +static void +server_forw_reliable(Server *server, + void *pack, + int packlen, + ZNotice_t *notice) +{ + Code_t retval; + Unacked *nacked; + int hashval; + + retval = ZSetDestAddr(&server->addr); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "srv_fwd_rel set addr: %s", error_message(retval)); + free(pack); + return; + } + retval = ZSendPacket(pack, packlen, 0); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "srv_fwd xmit: %s", error_message(retval)); + free(pack); + return; + } + /* now we've sent it, mark it as not ack'ed */ + + nacked = (Unacked *) malloc(sizeof(Unacked)); + if (!nacked) { + /* no space: just punt */ + syslog(LOG_ERR, "srv_forw_rel nack malloc"); + free(pack); + return; + } + + nacked->client = NULL; + nacked->rexmits = 0; + nacked->packet = pack; + nacked->dest.srv_idx = server - otherservers; + nacked->packsz = packlen; + nacked->uid = notice->z_uid; + nacked->timer = timer_set_rel(rexmit_times[0], srv_rexmit, nacked); + hashval = srv_nacktab_hashval(nacked->dest.srv_idx, nacked->uid); + Unacked_insert(&srv_nacktab[hashval], nacked); +} + +/* + * send the queued message for the server. + */ + +void +server_send_queue(Server *server) +{ + Pending *pending; + ZNotice_t notice; + Code_t status; + + while (server->queue) { + pending = server_dequeue(server); + status = ZParseNotice(pending->packet, pending->len, ¬ice); + if (status != ZERR_NONE) { + syslog(LOG_ERR, "ssq bad notice parse (%s): %s", + inet_ntoa(pending->who.sin_addr), error_message(status)); + } else { + server_forw_reliable(server, pending->packet, pending->len, + ¬ice); + free(pending); + /* ACK handling routines will free the packet */ + } + } +} + +/* + * a server has acknowledged a message we sent to him; remove it from + * server unacked queue + */ + +static void +srv_nack_cancel(ZNotice_t *notice, + struct sockaddr_in *who) +{ + Server *server = server_which_server(who); + Unacked *nacked; + int hashval; + + if (!server) { + syslog(LOG_ERR, "non-server ack?"); + return; + } + hashval = srv_nacktab_hashval(server - otherservers, notice->z_uid); + for (nacked = srv_nacktab[hashval]; nacked; nacked = nacked->next) { + if (nacked->dest.srv_idx == server - otherservers + && ZCompareUID(&nacked->uid, ¬ice->z_uid)) { + timer_reset(nacked->timer); + free(nacked->packet); + Unacked_delete(nacked); + free(nacked); + return; + } + } +} + +/* + * retransmit a message to another server + */ + +static void +srv_rexmit(void *arg) +{ + Unacked *packet = (Unacked *) arg; + Code_t retval; + /* retransmit the packet */ + + if (otherservers[packet->dest.srv_idx].state == SERV_DEAD) { + Unacked_delete(packet); + free(packet->packet); + srv_nack_release(&otherservers[packet->dest.srv_idx]); + free(packet); + return; + } + retval = ZSetDestAddr(&otherservers[packet->dest.srv_idx].addr); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "srv_rexmit set addr: %s", error_message(retval)); + } else { + retval = ZSendPacket(packet->packet, packet->packsz, 0); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "srv_rexmit xmit: %s", + error_message(retval)); + } + + /* reset the timer */ + if (rexmit_times[packet->rexmits + 1] != -1) + packet->rexmits++; + packet->timer = timer_set_rel(rexmit_times[packet->rexmits], srv_rexmit, + packet); +} + +/* + * Clean up the not-yet-acked queue and release anything destined + * to the server. + */ + +static void +srv_nack_release(Server *server) +{ + int i; + Unacked *nacked, *next; + + for (i = 0; i < SRV_NACKTAB_HASHSIZE; i++) { + for (nacked = srv_nacktab[i]; nacked; nacked = next) { + next = nacked->next; + if (nacked->dest.srv_idx == server - otherservers) { + timer_reset(nacked->timer); + Unacked_delete(nacked); + free(nacked->packet); + free(nacked); + } + } + } +} + +/* + * Adjust indices of not-yet-acked packets sent to other servers to + * continue to refer to the correct server. + */ + +static void +srv_nack_renumber (int *new_idx) +{ + /* XXX release any private queue for this server */ + Unacked *nacked; + int idx, i; + + /* search the not-yet-acked list for anything destined to 'from', and + change the index to 'to'. */ + for (i = 0; i < SRV_NACKTAB_HASHSIZE; i++) { + for (nacked = srv_nacktab[i]; nacked; nacked = nacked->next) { + idx = new_idx[nacked->dest.srv_idx]; + if (idx < 0) { + syslog(LOG_ERR, "srv_nack_renumber error: [%d]=%d", + nacked->dest.srv_idx, idx); + idx = 0; + } + nacked->dest.srv_idx = idx; + } + } +} + +/* + * Queue this notice to be transmitted to the server when it is ready. + */ +static void +server_queue(Server *server, + int len, + void *pack, + int auth, + struct sockaddr_in *who) +{ + Pending *pending; + + pending = (Pending *) malloc(sizeof(Pending)); + if (!pending) { + syslog(LOG_CRIT, "update_queue malloc"); + abort(); + } + pending->packet = pack; + pending->len = len; + pending->auth = auth; + pending->who = *who; + pending->next = NULL; + + /* put it on the end of the list */ + if (server->queue) + server->queue_last->next = pending; + else + server->queue = server->queue_last = pending; +} + +/* + * Pull a notice off the hold queue. + */ + +Pending * +server_dequeue(Server *server) +{ + Pending *pending; + + if (!server->queue) + return NULL; + pending = server->queue; + server->queue = pending->next; + return pending; +} + +/* + * free storage used by a pending queue entry. + */ + +void +server_pending_free(Pending *pending) +{ + free(pending->packet); + free(pending); + return; +} + +/* + * Queue something to be handled later by this server. + */ + +void +server_self_queue(ZNotice_t* notice, + int auth, + struct sockaddr_in * who) +{ + char *pack; + int packlen; + Code_t retval; + + retval = ZFormatRawNotice(notice, &pack, &packlen); + if (retval != ZERR_NONE) { + syslog(LOG_CRIT, "srv_self_queue format: %s", error_message(retval)); + abort(); + } + server_queue(me_server, packlen, pack, auth, who); +} + +/* + * dump info about servers onto the fp. + * assumed to be called with SIGFPE blocked + * (true if called from signal handler) + */ +void +server_dump_servers(FILE *fp) +{ + int i; + + for (i = 0; i < nservers ; i++) { + fprintf(fp, "%d:%s/%s%s\n", i, otherservers[i].addr_str, + srv_states[otherservers[i].state], + otherservers[i].dumping ? " (DUMPING)" : ""); + } +} diff --git a/server/subscr.c b/server/subscr.c new file mode 100644 index 0000000..b788663 --- /dev/null +++ b/server/subscr.c @@ -0,0 +1,1317 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for managing subscription lists. + * + * Created by: John T. Kohl + * + * $Source$ + * $Author$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_subscr_c[] = "$Id$"; +#endif +#endif + +#ifndef INADDR_NONE +#define INADDR_NONE 0xffffffff +#endif + +/* + * The subscription manager. + * + * External functions: + * + * Code_t subscr_subscribe(who, notice) + * Client *who; + * ZNotice_t *notice; + * + * Code_t subscr_cancel(sin, notice) + * struct sockaddr_in *sin; + * ZNotice_t *notice; + * + * Code_t subscr_cancel_client(client) + * Client *client; + * + * Code_t subscr_cancel_host(addr) + * struct in_addr *addr; + * + * Client *subscr_match_list(notice) + * ZNotice_t *notice; + * + * void subscr_free_list(list) + * Client *list; + * + * void subscr_sendlist(notice, auth, who) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * + * Code_t subscr_send_subs(client, vers) + * Client *client; + * char *vers; + * + * Code_t subscr_def_subs(who) + * Client *who; + * + * void subscr_reset(); + * + */ + +#if defined(HAVE_KRB4) +C_Block serv_key; +Sched serv_ksched; +#endif + +static Code_t add_subscriptions(Client *who, Destlist *subs_queue, + ZNotice_t *notice, Server *server); +static Destlist *extract_subscriptions(ZNotice_t *notice); +static void free_subscriptions(Destlist *subs); +static void free_subscription(Destlist *sub); +static char **subscr_marshal_subs(ZNotice_t *notice, int auth, + struct sockaddr_in *who, + int *found); +static Destlist *subscr_copy_def_subs(char *person); +static Code_t subscr_realm_sendit(Client *who, Destlist *subs, + ZNotice_t *notice, ZRealm *realm); +static void subscr_unsub_sendit(Client *who, Destlist *subs, + ZRealm *realm); + +static int defaults_read = 0; /* set to 1 if the default subs + are in memory */ +static ZNotice_t default_notice; /* contains default subscriptions */ + +String *wildcard_instance; +String *empty; + +/* WARNING: make sure this is the same as the number of strings you */ +/* plan to hand back to the user in response to a subscription check, */ +/* else you will lose. See subscr_sendlist() */ +#define NUM_FIELDS 3 + +/* + * subscribe the client to types described in notice. + */ + +Code_t +subscr_subscribe(Client *who, + ZNotice_t *notice, + Server *server) +{ + Destlist *subs; + + subs = extract_subscriptions(notice); + return add_subscriptions(who, subs, notice, server); +} + +static Code_t +add_subscriptions(Client *who, + Destlist *subs, + ZNotice_t *notice, + Server *server) +{ + Destlist *next; + Code_t retval; + Acl *acl; + String *sender; + ZRealm *realm = NULL; + + if (!subs) + return ZERR_NONE; /* no subscr -> no error */ + + sender = make_string(notice->z_sender, 0); + + /* Loop over the new subscriptions. */ + for (; subs; subs = next) { + next = subs->next; + /* check the recipient for a realm which isn't ours */ + realm = NULL; + if (subs->dest.recip->string[0] == '@' && + strcmp((subs->dest.recip->string + 1), ZGetRealm()) != 0) + realm = realm_get_realm_by_name(subs->dest.recip->string + 1); + if (!bdumping) { + if (subs->dest.recip != empty && subs->dest.recip != sender + && subs->dest.recip->string[0] != '@') { + syslog(LOG_WARNING, "subscr unauth %s recipient %s", + sender->string, subs->dest.recip->string); + free_subscription(subs); /* free this one - denied */ + continue; /* the for loop */ + } + acl = class_get_acl(subs->dest.classname); + if (acl && !realm) { + if (!access_check(sender->string, &who->addr, acl, SUBSCRIBE)) { + syslog(LOG_WARNING, "subscr unauth %s class %s", + sender->string, subs->dest.classname->string); + free_subscription(subs); /* free this one - denied */ + continue; /* the for loop */ + } + if (wildcard_instance == subs->dest.inst) { + if (!access_check(sender->string, &who->addr, acl, INSTWILD)) { + syslog(LOG_WARNING, + "subscr unauth %s class %s wild inst", + sender->string, subs->dest.classname->string); + free_subscription(subs); /* free this one - denied */ + continue; /* the for loop */ + } + } + } + } + if (realm && !bdumping) { + retval = subscr_realm_sendit(who, subs, notice, realm); + if (retval != ZERR_NONE) { + free_subscription(subs); + continue; /* the for loop */ + } else { + free_subscription(subs); /* free this one, wil get from + ADD */ + } + } else { + retval = triplet_register(who, &subs->dest, NULL); + if (retval != ZERR_NONE) { + if (retval == ZSRV_CLASSXISTS) { + free_subscription(subs); /* free this one */ + } else { + free_subscriptions(subs); + free_string(sender); + return retval; + } + } else { + /* If realm, let the REALM_ADD_SUBSCRIBE do insertion */ + Destlist_insert(&who->subs, subs); + } + } + } + + free_string(sender); + return ZERR_NONE; +} + +/* + * add default subscriptions to the client's subscription chain. + */ + +Code_t +subscr_def_subs(Client *who) +{ + Destlist *subs; + + subs = subscr_copy_def_subs(who->principal->string); + return add_subscriptions(who, subs, &default_notice, NULL); +} + +void +subscr_reset(void) +{ + free(default_notice.z_message); + default_notice.z_message = NULL; + defaults_read = 0; +} + +static Destlist * +subscr_copy_def_subs(char *person) +{ + int retval, fd; + struct stat statbuf; + char *def_sub_area, *cp; + Destlist *subs, *sub; + + if (!defaults_read) { + fd = open(subs_file, O_RDONLY, 0666); + if (fd < 0) { + syslog(LOG_ERR, "can't open %s:%m", subs_file); + return NULL; + } + retval = fstat(fd, &statbuf); + if (retval < 0) { + syslog(LOG_ERR, "fstat failure on %s:%m", subs_file); + close(fd); + return NULL; + } + def_sub_area = (char *) malloc(statbuf.st_size + 1); + if (!def_sub_area) { + syslog(LOG_ERR, "no mem copy_def_subs"); + close(fd); + return NULL; + } + retval = read(fd, def_sub_area, (size_t) statbuf.st_size); + if (retval != statbuf.st_size) { + syslog(LOG_ERR, "short read in copy_def_subs"); + close(fd); + return NULL; + } + + close(fd); + def_sub_area[statbuf.st_size] = '\0'; /* null-terminate it */ + + /* + def_subs_area now points to a buffer full of subscription info. + Each line of the stuff is of the form: + class,inst,recipient + + Commas and newlines may not appear as part of the class, + instance, or recipient. XXX! + */ + + /* split up the subscription info */ + for (cp = def_sub_area; cp < def_sub_area + statbuf.st_size; cp++) { + if (*cp == '\n' || *cp == ',') + *cp = '\0'; + } + default_notice.z_message = def_sub_area; + default_notice.z_message_len = statbuf.st_size + 1; + default_notice.z_auth = 1; + defaults_read = 1; + } + + /* needed later for access_check() */ + default_notice.z_sender = person; + subs = extract_subscriptions(&default_notice); + /* replace any non-* recipients with "person" */ + + for (sub = subs; sub; sub = sub->next) { + /* if not a wildcard, replace it with person */ + if (strcmp(sub->dest.recip->string, "*")) { + free_string(sub->dest.recip); + sub->dest.recip = make_string(person, 0); + } else { /* replace with null recipient */ + free_string(sub->dest.recip); + sub->dest.recip = dup_string(empty); + } + } + return subs; +} + +/* + * Cancel a specific set of subscriptions. + */ + +Code_t +subscr_cancel(struct sockaddr_in *sin, + ZNotice_t *notice) +{ + ZRealm *realm; + Client *who; + Destlist *cancel_subs, *subs, *cancel_next, *client_subs, *client_next; + Code_t retval; + int found = 0; + + who = client_find(&sin->sin_addr, notice->z_port); + if (!who) + return ZSRV_NOCLT; + + if (!who->subs) + return ZSRV_NOSUB; + + cancel_subs = extract_subscriptions(notice); + if (!cancel_subs) + return ZERR_NONE; /* no subscr -> no error */ + + for (subs = cancel_subs; subs; subs = cancel_next) { + cancel_next = subs->next; + for (client_subs = who->subs; client_subs; client_subs = client_next) { + client_next = client_subs->next; + if (ZDest_eq(&client_subs->dest, &subs->dest)) { + Destlist_delete(client_subs); + retval = triplet_deregister(who, &client_subs->dest, NULL); + if (retval == ZSRV_EMPTYCLASS && + client_subs->dest.recip->string[0] == '@') { + realm = + realm_get_realm_by_name(client_subs->dest.recip->string + + 1); + if (realm) + subscr_unsub_sendit(who, client_subs, realm); + realm = NULL; + } + free_subscription(client_subs); + found = 1; + break; + } + } + } + + free_subscriptions(cancel_subs); + + if (found) { + return ZERR_NONE; + } else { + return ZSRV_NOSUB; + } +} + +Code_t +subscr_realm_cancel(struct sockaddr_in *sin, + ZNotice_t *notice, + ZRealm *realm) +{ + Destlist *cancel_subs, *subs, *client_subs, *next, *next2; + int found = 0; + + if (!realm) + return ZSRV_NORLM; + + if (!realm->subs) + return ZSRV_NOSUB; + + cancel_subs = extract_subscriptions(notice); + if (!cancel_subs) + return ZERR_NONE; /* no subscr -> no error */ + + for (subs = cancel_subs; subs; subs = next) { + next = subs->next; + for (client_subs = realm->subs; client_subs; client_subs = next2) { + next2 = client_subs->next; + if (ZDest_eq(&client_subs->dest, &subs->dest)) { + Destlist_delete(client_subs); + triplet_deregister(realm->client, &client_subs->dest, realm); + free_subscription(client_subs); + found = 1; + break; + } + } + } + + free_subscriptions(cancel_subs); + + if (found) { + return ZERR_NONE; + } else { + return ZSRV_NOSUB; + } +} + +/* + * Cancel all the subscriptions for this client. + */ + +void +subscr_cancel_client(Client *client) +{ + Destlist *subs, *next; + Code_t retval; + ZRealm *realm; + + if (!client->subs) + return; + + for (subs = client->subs; subs; subs = next) { + next = subs->next; + retval = triplet_deregister(client, &subs->dest, NULL); + if (retval == ZSRV_EMPTYCLASS && + subs->dest.recip->string[0] == '@') { + realm = realm_get_realm_by_name(subs->dest.recip->string + 1); + if (realm) + subscr_unsub_sendit(client, subs, realm); + realm = NULL; + } + free_subscription(subs); + } + + client->subs = NULL; +} + +/* + * Send the requester a list of his current subscriptions + */ + +void +subscr_sendlist(ZNotice_t *notice, + int auth, + struct sockaddr_in *who) +{ + char **answer; + int found; + struct sockaddr_in send_to_who; + Code_t retval; + + answer = subscr_marshal_subs(notice, auth, who, &found); + send_to_who = *who; + send_to_who.sin_port = notice->z_port; /* Return port */ + + retval = ZSetDestAddr(&send_to_who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_sendlist set addr: %s", + error_message(retval)); + if (answer) + free(answer); + return; + } + + /* XXX for now, don't do authentication */ + auth = 0; + + notice->z_kind = ACKED; + + /* use xmit_frag() to send each piece of the notice */ + + retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "subscr_sendlist xmit: %s", error_message(retval)); + if (answer) + free(answer); +} + +static char ** +subscr_marshal_subs(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + int *found) +{ + char **answer = NULL; + unsigned short temp; + Code_t retval; + Client *client = NULL; + Destlist *subs = NULL, *sub; + int i; + int defsubs = 0; + + *found = 0; + + /* Note that the following code is an incredible crock! */ + + /* We cannot send multiple packets as acknowledgements to the client, + since the hostmanager will ignore the later packets. So we need + to send directly to the client. */ + + /* Make our own copy so we can send directly back to the client */ + /* RSF 11/07/87 */ + + if (strcmp(notice->z_opcode, CLIENT_GIMMESUBS) == 0) { + /* If the client has requested his current subscriptions, + the message field of the notice contains the port number + of the client for which the sender desires the subscription + list. The port field is the port of the sender. */ + + retval = ZReadAscii16(notice->z_message, notice->z_message_len, &temp); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_marshal read port num: %s", + error_message(retval)); + return(NULL); + } + + client = client_find(&who->sin_addr, htons(temp)); + + if (client) + subs = client->subs; + } else if (strcmp(notice->z_opcode, CLIENT_GIMMEDEFS) == 0) { + /* subscr_copy_def_subs allocates new pointer rings, so + it must be freed when finished. + the string areas pointed to are static, however.*/ + subs = subscr_copy_def_subs(notice->z_sender); + defsubs = 1; + } else { + syslog(LOG_ERR, "subscr_marshal bogus opcode %s", + notice->z_opcode); + return(NULL); + } + + if (subs) { + + /* check authenticity here. The user must be authentic to get + a list of subscriptions. If he is not subscribed to + anything, this if-clause fails, and he gets a response + indicating no subscriptions. + if retrieving default subscriptions, don't care about + authentication. */ + + if (!auth && !defsubs) + return(NULL); + if (!defsubs) { + if (client && (strcmp(client->principal->string, + notice->z_sender) != 0)) { + zdbug ((LOG_DEBUG, + "subscr_marshal: %s requests subs for %s at %s/%d", + notice->z_sender, client->principal->string, + inet_ntoa(who->sin_addr), ntohs(who->sin_port))); + return 0; + } + } + + for (sub = subs; sub; sub = sub->next) + (*found)++; + + /* found is now the number of subscriptions */ + + /* coalesce the subscription information into a list of char *'s */ + answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *)); + if (answer == NULL) { + syslog(LOG_ERR, "subscr no mem(answer)"); + *found = 0; + } else { + i = 0; + for (sub = subs; sub; sub = sub->next) { + answer[i * NUM_FIELDS] = sub->dest.classname->string; + answer[i * NUM_FIELDS + 1] = sub->dest.inst->string; + answer[i * NUM_FIELDS + 2] = sub->dest.recip->string; + i++; + } + } + } + if (defsubs) + free_subscriptions(subs); + return answer; +} + +static Code_t +subscr_send_some_subs(char *opcode, struct sockaddr_in *addr, Destlist *subs, char *subject) +{ + char *list[NUM_FIELDS]; + Code_t retval; + + for (; subs; subs = subs->next) { + /* for each subscription */ + list[0] = subs->dest.classname->string; + list[1] = subs->dest.inst->string; + list[2] = subs->dest.recip->string; + retval = bdump_send_list_tcp(ACKED, addr, + ZEPHYR_CTL_CLASS, "", + opcode, "", "", list, + NUM_FIELDS); + if (retval == ZERR_PKTLEN) { + syslog(LOG_ERR, "subscr_send_some_subs: dropping overlarge packet (%s)", subject); + } else if (retval != ZERR_NONE) { + syslog(LOG_ERR, "subscr_send_some_subs: bdump_send_list_tcp: %s", + error_message(retval)); + return retval; + } + } + + return ZERR_NONE; +} + +/* + * Send the client's subscriptions to another server + */ + +/* version is currently unused; if necessary later versions may key off it + to determine what to send to the peer (protocol changes) */ + +/*ARGSUSED*/ +Code_t +subscr_send_subs(Client *client) +{ +#ifdef HAVE_KRB5 + char buf[512]; + unsigned char *bufp; +#else +#ifdef HAVE_KRB4 + char buf[512]; + C_Block cblock; +#endif /* HAVE_KRB4 */ +#endif + char buf2[512]; + char *list[7 * NUM_FIELDS]; + int num = 0; + Code_t retval; + + sprintf(buf2, "%d",ntohs(client->addr.sin_port)); + + list[num++] = buf2; + +#ifdef HAVE_KRB5 +#ifdef HAVE_KRB4 /* XXX make this optional for server transition time */ + if (Z_enctype(client->session_keyblock) == ENCTYPE_DES_CBC_CRC) { + bufp = malloc(Z_keylen(client->session_keyblock)); + if (bufp == NULL) { + syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for DES keyblock: %m"); + return errno; + } + des_ecb_encrypt((C_Block *)Z_keydata(client->session_keyblock), (C_Block *)bufp, serv_ksched.s, DES_ENCRYPT); + retval = ZMakeAscii(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock)); + } else { +#endif + bufp = malloc(Z_keylen(client->session_keyblock) + 8); /* + enctype + + length */ + if (bufp == NULL) { + syslog(LOG_WARNING, "subscr_send_subs: cannot allocate memory for keyblock: %m"); + return errno; + } + *(krb5_enctype *)&bufp[0] = htonl(Z_enctype(client->session_keyblock)); + *(uint32_t *)&bufp[4] = htonl(Z_keylen(client->session_keyblock)); + memcpy(&bufp[8], Z_keydata(client->session_keyblock), Z_keylen(client->session_keyblock)); + + retval = ZMakeZcode(buf, sizeof(buf), bufp, Z_keylen(client->session_keyblock) + 8); +#ifdef HAVE_KRB4 + } +#endif /* HAVE_KRB4 */ +#else /* HAVE_KRB5 */ +#ifdef HAVE_KRB4 + des_ecb_encrypt((des_cblock *)client->session_key, (des_cblock *)cblock, + serv_ksched.s, DES_ENCRYPT); + + retval = ZMakeAscii(buf, sizeof(buf), cblock, sizeof(C_Block)); +#endif /* HAVE_KRB4 */ +#endif /* HAVE_KRB5 */ + +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) + if (retval != ZERR_NONE) { + } else { + list[num++] = buf; + } +#endif /* HAVE_KRB4 || HAVE_KRB5*/ + retval = bdump_send_list_tcp(SERVACK, &client->addr, ZEPHYR_ADMIN_CLASS, + num > 1 ? "CBLOCK" : "", ADMIN_NEWCLT, + client->principal->string, "", list, num); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "subscr_send_subs newclt: %s", error_message(retval)); + return retval; + } + + retval = subscr_send_some_subs(CLIENT_SUBSCRIBE, &client->addr, client->subs, client->principal->string); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "subscr_send_subs: subscr_send_some_subs: %s", error_message(retval)); + return retval; +} + +/* + * free the memory allocated for the list of subscriptions. + */ + +/* + * free the memory allocated for one subscription. + */ + +static void +free_subscription(Destlist *sub) +{ + free_string(sub->dest.classname); + free_string(sub->dest.inst); + free_string(sub->dest.recip); + free(sub); +} + +static void +free_subscriptions(Destlist *subs) +{ + Destlist *next; + + for (; subs; subs = next) { + next = subs->next; + free_subscription (subs); + } +} + +#define ADVANCE(xx) { cp += (strlen(cp) + 1); \ + if (cp >= notice->z_message + notice->z_message_len) { \ + syslog(LOG_WARNING, "malformed subscription %d", \ + xx); \ + return subs; \ + }} + +/* + * Parse the message body, returning a linked list of subscriptions, or + * NULL if there are no subscriptions there. + */ + +static Destlist * +extract_subscriptions(ZNotice_t *notice) +{ + Destlist *subs = NULL, *sub; + char *recip, *class_name, *classinst; + char *cp = notice->z_message; + + /* parse the data area for the subscriptions */ + while (cp < notice->z_message + notice->z_message_len) { + class_name = cp; + if (*cp == '\0') /* we've exhausted the subscriptions */ + return(subs); + ADVANCE(1); + classinst = cp; + ADVANCE(2); + recip = cp; + cp += (strlen(cp) + 1); + if (cp > notice->z_message + notice->z_message_len) { + syslog(LOG_WARNING, "malformed sub 3"); + return subs; + } + sub = (Destlist *) malloc(sizeof(Destlist)); + if (!sub) { + syslog(LOG_WARNING, "ex_subs: no mem 2"); + return subs; + } + sub->dest.classname = make_string(class_name, 1); + sub->dest.inst = make_string(classinst, 1); + /* Nuke @REALM if REALM is us. */ + if (recip[0] == '@' && !strcmp(recip + 1, ZGetRealm())) + sub->dest.recip = make_string("", 0); + else + sub->dest.recip = make_string(recip, 0); + Destlist_insert(&subs, sub); + } + return subs; +} + +/* + * print subscriptions in subs onto fp. + * assumed to be called with SIGFPE blocked + * (true if called from signal handler) + */ + +void +subscr_dump_subs(FILE *fp, + Destlist *subs) +{ + if (!subs) /* no subscriptions to dump */ + return; + + for (; subs; subs = subs->next) { + fputs("\t'", fp); + dump_quote(subs->dest.classname->string, fp); + fputs("' '", fp); + dump_quote(subs->dest.inst->string, fp); + fputs("' '", fp); + dump_quote(subs->dest.recip->string, fp); + fputs("'\n", fp); + } +} + +#define I_ADVANCE(xx) { cp += (strlen(cp) + 1); \ + if (cp >= notice->z_message + notice->z_message_len) { \ + syslog(LOG_WARNING, "malformed subscription %d", \ + xx); \ + return (ZERR_NONE); \ + }} + +/* As it exists, this function expects to take only the first sub from the + * Destlist. At some point, it and the calling code should be replaced */ +static Code_t +subscr_realm_sendit(Client *who, + Destlist *subs, + ZNotice_t *notice, + ZRealm *realm) +{ + ZNotice_t snotice; + char *pack; + int packlen; + char **text; + Code_t retval; + char addr[16]; /* xxx.xxx.xxx.xxx max */ + char port[16]; + + if ((text=(char **)malloc((NUM_FIELDS + 2)*sizeof(char *))) == (char **)0) { + syslog(LOG_ERR, "subscr_rlm_sendit malloc"); + return(ENOMEM); + } + /* convert the address to a string of the form x.x.x.x/port */ + strcpy(addr, inet_ntoa(who->addr.sin_addr)); + if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) + &who->addr.sin_port, sizeof(unsigned short))) != ZERR_NONE) + { + syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s", + error_message(retval)); + return(ZERR_NONE); + } + text[0] = addr; + text[1] = port; + + text[2] = subs->dest.classname->string; + text[3] = subs->dest.inst->string; + text[4] = subs->dest.recip->string; + + zdbug((LOG_DEBUG, "subscr_realm_sendit %s/%s (%s) %s,%s,%s\n", + text[0], text[1], who->principal->string, text[2], text[3], text[4])); + + /* format snotice */ + memset (&snotice, 0, sizeof(snotice)); + snotice.z_class_inst = ZEPHYR_CTL_REALM; + snotice.z_opcode = REALM_REQ_SUBSCRIBE; + snotice.z_port = srv_addr.sin_port; + + snotice.z_class = ZEPHYR_CTL_CLASS; + + snotice.z_recipient = ""; + snotice.z_kind = ACKED; + snotice.z_num_other_fields = 0; + snotice.z_sender = who->principal->string; + snotice.z_recipient = notice->z_recipient; + snotice.z_default_format = notice->z_default_format; + + if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2, + &pack, &packlen, ZNOAUTH)) != ZERR_NONE) + { + syslog(LOG_WARNING, "subscr_rlm_sendit format: %s", + error_message(retval)); + free(text); + return(ZERR_NONE); + } + free(text); + + if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s", + error_message(retval)); + free(pack); + return(ZERR_NONE); + } + + realm_handoff(&snotice, 1, &(who->addr), realm, 0); + free(pack); + + return(ZERR_NONE); +} + +/* Called from subscr_realm and subscr_foreign_user */ +static Code_t +subscr_add_raw(Client *client, + ZRealm *realm, + Destlist *newsubs) +{ + Destlist *subs, *subs2, **head; + Code_t retval; + + head = (realm) ? &realm->subs : &client->subs; + + /* Loop over the new subscriptions. */ + for (subs = newsubs; subs; subs = subs2) { + subs2 = subs->next; +#ifdef DEBUG + zdbug((LOG_DEBUG,"subscr_add_raw: %s/%s/%s", subs->dest.classname->string, subs->dest.inst->string, subs->dest.recip->string)); + if (realm) + zdbug((LOG_DEBUG,"subscr_add_raw: realm is %s", realm->name)); +#endif + retval = triplet_register(client, &subs->dest, realm); + if (retval != ZERR_NONE) { + free_subscription(subs); + if (retval == ZSRV_CLASSXISTS) { + continue; + } else { + free_subscriptions(subs2); + return retval; + } + } else { + if (!realm) { + ZRealm *remrealm = + realm_get_realm_by_name(subs->dest.recip->string + 1); + if (remrealm) { + Destlist *sub = (Destlist *) malloc(sizeof(Destlist)); + if (!sub) { + syslog(LOG_WARNING, "subscr_add_raw: no mem"); + } else { + sub->dest.classname = make_string(subs->dest.classname->string, 0); + sub->dest.inst = make_string(subs->dest.inst->string, 0); + sub->dest.recip = make_string(subs->dest.recip->string, 0); + zdbug ((LOG_DEBUG, "subscr: add %s/%s/%s in %s", + sub->dest.classname->string, sub->dest.inst->string, + sub->dest.recip->string, remrealm->name)); + Destlist_insert(&remrealm->remsubs, sub); + } + } + } + } + Destlist_insert(head, subs); + } + return ZERR_NONE; +} + +/* Called from bdump_recv_loop to decapsulate realm subs */ +Code_t +subscr_realm(ZRealm *realm, + ZNotice_t *notice) +{ + Destlist *newsubs; + + newsubs = extract_subscriptions(notice); + + if (!newsubs) { + syslog(LOG_WARNING, "empty subs in subscr_realm"); + return(ZERR_NONE); + } + + return(subscr_add_raw(realm->client, realm, newsubs)); +} + +/* Like realm_sendit, this only takes one item from subs */ +static void +subscr_unsub_sendit(Client *who, + Destlist *subs, + ZRealm *realm) +{ + ZNotice_t unotice; + Code_t retval; + char **list; + char *pack; + int packlen; + Destlist *subsp, *subsn; + + for (subsp = realm->remsubs; subsp; subsp = subsn) { + subsn = subsp->next; + if (ZDest_eq(&subs->dest, &subsp->dest)) { + zdbug ((LOG_DEBUG, "subscr: del %s/%s/%s in %s", + subsp->dest.classname->string, subsp->dest.inst->string, + subsp->dest.recip->string, realm->name)); + Destlist_delete(subsp); + free_subscription(subsp); + break; + } + } + + if ((list=(char **)malloc((NUM_FIELDS)*sizeof(char *))) == (char **)0) { + syslog(LOG_ERR, "subscr_unsub_sendit malloc"); + return; + } + + list[0] = subs->dest.classname->string; + list[1] = subs->dest.inst->string; + list[2] = ""; + + memset(&unotice, 0, sizeof(unotice)); + unotice.z_class = ZEPHYR_CTL_CLASS; + unotice.z_class_inst = ZEPHYR_CTL_REALM; + unotice.z_opcode = REALM_UNSUBSCRIBE; + unotice.z_recipient = ""; + unotice.z_kind = ACKED; + + unotice.z_sender = ""; + unotice.z_port = srv_addr.sin_port; + unotice.z_num_other_fields = 0; + unotice.z_default_format = ""; + + if ((retval = ZFormatNoticeList(&unotice, list, NUM_FIELDS, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_unsub_sendit format: %s", + error_message(retval)); + free(list); + return; + } + free(list); + + if ((retval = ZParseNotice(pack, packlen, &unotice)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_unsub_sendit parse: %s", + error_message(retval)); + free(pack); + return; + } + realm_handoff(&unotice, 1, who ? &(who->addr) : NULL, realm, 0); + free(pack); +} + +/* Called from bump_send_loop by way of realm_send_realms */ +Code_t +subscr_send_realm_subs(ZRealm *realm) +{ + char buf[512]; + char *list[7 * NUM_FIELDS]; + int num = 0; + Code_t retval; + + strcpy(buf, realm->name); + list[num++] = buf; + + retval = bdump_send_list_tcp(SERVACK, &srv_addr, ZEPHYR_ADMIN_CLASS, + "", ADMIN_NEWREALM, "", "", list, num); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "subscr_send_realm_subs newclt: %s", error_message(retval)); + return retval; + } + + retval = subscr_send_some_subs(REALM_SUBSCRIBE, &srv_addr, realm->subs, realm->name); + if (retval != ZERR_NONE) + syslog(LOG_ERR, "subscr_send_realm_subs: subscr_send_some_subs: %s", error_message(retval)); + return retval; +} + +Code_t +subscr_realm_subs(ZRealm *realm) +{ + Destlist *subs, *next; + char *text[2 + NUM_FIELDS]; + unsigned short num = 0; + Code_t retval; + ZNotice_t snotice; + char *pack; + int packlen; + Client **clientp; + char port[16]; + + if (!realm->remsubs) + return ZERR_NONE; + + for (subs=realm->remsubs; subs; subs = next) { + next = subs->next; +#ifdef DEBUG + zdbug ((LOG_DEBUG, "realm_subs: %s/%s/%s", subs->dest.classname->string, + subs->dest.inst->string, subs->dest.recip->string)); +#endif + + num = 0; + if ((retval = ZMakeAscii(port, sizeof(port), (unsigned char *) + &num, sizeof(unsigned short))) != ZERR_NONE) + { + syslog(LOG_ERR, "subscr_rlm_sendit make ascii: %s", + error_message(retval)); + return(ZERR_NONE); + } + + text[0] = "0.0.0.0"; + text[1] = port; + text[2] = subs->dest.classname->string; + text[3] = subs->dest.inst->string; + text[4] = subs->dest.recip->string; + + /* format snotice */ + memset (&snotice, 0, sizeof(snotice)); + snotice.z_class_inst = ZEPHYR_CTL_REALM; + snotice.z_opcode = REALM_REQ_SUBSCRIBE; + snotice.z_port = 0; + snotice.z_class = ZEPHYR_CTL_CLASS; + + snotice.z_recipient = ""; + snotice.z_kind = ACKED; + snotice.z_num_other_fields = 0; + snotice.z_default_format = ""; + /* Evil. In the event this is ACL'd, pick a user who is subscribed and + resubmit them as the sender. */ + clientp = triplet_lookup(&subs->dest); + if (!clientp) + snotice.z_sender = ""; + else + snotice.z_sender = (*clientp)->principal->string; + + if ((retval = ZFormatNoticeList(&snotice, text, NUM_FIELDS + 2, + &pack, &packlen, ZNOAUTH)) != ZERR_NONE) + { + syslog(LOG_WARNING, "subscr_rlm_subs format: %s", + error_message(retval)); + return(ZERR_NONE); + } + + if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_rlm_subs parse: %s", + error_message(retval)); + free(pack); + return(ZERR_NONE); + } + realm_handoff(&snotice, 1, NULL, realm, 0); + free(pack); + } + + return ZERR_NONE; +} + +/* Called from subscr_foreign_user for REALM_REQ_SUBSCRIBE */ +static Code_t +subscr_check_foreign_subs(ZNotice_t *notice, + struct sockaddr_in *who, + Server *server, + ZRealm *realm, + Destlist *newsubs) +{ + Destlist *subs, *next; + Acl *acl; + char **text; + int found = 0; + ZNotice_t snotice; + char *pack, *cp; + int packlen; + Code_t retval; + String *sender; + + for (subs = newsubs; subs; subs = subs->next) + found++; + + if (found == 0) + return(ZERR_NONE); + + sender = make_string(notice->z_sender, 0); + + if ((text = (char **)malloc((found * NUM_FIELDS + 2) * sizeof(char *))) + == (char **) 0) { + syslog(LOG_ERR, "subscr_ck_forn_subs no mem(text)"); + free_string(sender); + return(ENOMEM); + } + + /* grab the client information from the incoming message */ + cp = notice->z_message; + text[0] = cp; + + I_ADVANCE(2); + text[1] = cp; + + I_ADVANCE(3); + + found = 0; + for (subs = newsubs; subs; subs = next) { + ZRealm *rlm; + next=subs->next; + if (subs->dest.recip->string[0] != '\0') { + rlm = realm_which_realm(who); + syslog(LOG_WARNING, "subscr bad recip %s by %s (%s)", + subs->dest.recip->string, + sender->string, rlm->name); + continue; + } + acl = class_get_acl(subs->dest.classname); + if (acl) { + rlm = realm_which_realm(who); + if (rlm && server == me_server) { + if (!realm_sender_in_realm(rlm->name, sender->string)) { + syslog(LOG_WARNING, "subscr auth not verifiable %s (%s) class %s", + sender->string, rlm->name, + subs->dest.classname->string); + free_subscriptions(newsubs); + free_string(sender); + free(text); + return ZSRV_CLASSRESTRICTED; + } + } + if (!access_check(sender->string, who, acl, SUBSCRIBE)) { + syslog(LOG_WARNING, "subscr unauth %s class %s", + sender->string, subs->dest.classname->string); + continue; /* the for loop */ + } + if (wildcard_instance == subs->dest.inst) { + if (!access_check(sender->string, who, acl, INSTWILD)) { + syslog(LOG_WARNING, + "subscr unauth %s class %s wild inst", + sender->string, subs->dest.classname->string); + continue; + } + } + } + + /* okay to subscribe. save for return trip */ + text[found*NUM_FIELDS + 2] = subs->dest.classname->string; + text[found*NUM_FIELDS + 3] = subs->dest.inst->string; + text[found*NUM_FIELDS + 4] = ""; + found++; + + retval = triplet_register(realm->client, &subs->dest, realm); +#ifdef DEBUG + zdbug ((LOG_DEBUG, "ck_frn_subs: %s/%s/%s", subs->dest.classname->string, + subs->dest.inst->string, subs->dest.recip->string)); +#endif + + if (retval != ZERR_NONE) { + if (retval == ZSRV_CLASSXISTS) { + continue; + } else { + free_subscriptions(newsubs); /* subs->next XXX */ + free_string(sender); + free(text); + return retval; + } + } + Destlist_insert(&realm->subs, subs); + } + /* don't send confirmation if we're not the initial server contacted */ + if (!(server_which_server(who) || found == 0)) { + snotice = *notice; + snotice.z_opcode = REALM_ADD_SUBSCRIBE; + snotice.z_class_inst = ZEPHYR_CTL_REALM; + snotice.z_port = srv_addr.sin_port; + if ((retval = ZFormatNoticeList(&snotice, text, found * NUM_FIELDS + 2, &pack, &packlen, ZNOAUTH)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_ck_forn_subs format: %s", + error_message(retval)); + free_string(sender); + free(text); + return(ZERR_NONE); + } + if ((retval = ZParseNotice(pack, packlen, &snotice)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_ck_forn_subs parse: %s", + error_message(retval)); + free_string(sender); + free(text); + free(pack); + return(ZERR_NONE); + } + realm_handoff(&snotice, 1, who, realm, 0); + free(pack); + } + free_string(sender); + free(text); + return ZERR_NONE; +} + +/* Called from realm_control_dispatch for REALM_REQ/ADD_SUBSCRIBE */ +Code_t subscr_foreign_user(ZNotice_t *notice, + struct sockaddr_in *who, + Server *server, + ZRealm *realm) +{ + Destlist *newsubs, *temp; + Code_t status; + Client *client; + ZNotice_t snotice; + struct sockaddr_in newwho; + char *cp, *tp0; +#ifdef DEBUG + char *tp1; +#endif + char rlm_recipient[REALM_SZ + 1]; + + tp0 = cp = notice->z_message; + + newwho.sin_addr.s_addr = inet_addr(cp); + if (newwho.sin_addr.s_addr == INADDR_NONE) { + syslog(LOG_ERR, "malformed addr from %s", notice->z_sender); + return(ZERR_NONE); + } + + I_ADVANCE(0); +#ifdef DEBUG + tp1 = cp; +#endif + + snotice = *notice; + + if ((status = ZReadAscii(cp, strlen(cp), (unsigned char *)&snotice.z_port, + sizeof(unsigned short))) + != ZERR_NONE) + { + syslog(LOG_ERR, "subscr_foreign_user read ascii: %s", + error_message(status)); + return(ZERR_NONE); + } + + I_ADVANCE(1); + + snotice.z_message = cp; + snotice.z_message_len = notice->z_message_len - (cp - notice->z_message); + + newsubs = extract_subscriptions(&snotice); + if (!newsubs) { + syslog(LOG_WARNING, "empty subscr for %s", notice->z_sender); + return(ZERR_NONE); + } + + if (!strcmp(snotice.z_opcode, REALM_ADD_SUBSCRIBE)) { + /* this was approved by the other realm, add subscriptions */ + + if (!strcmp(tp0, "0.0.0.0")) { + /* skip bogus ADD reply from subscr_realm_subs */ + zdbug((LOG_DEBUG, "subscr_foreign_user ADD skipped")); + return(ZERR_NONE); + } + + zdbug((LOG_DEBUG, "subscr_foreign_user ADD %s/%s", tp0, tp1)); + client = client_find(&newwho.sin_addr, snotice.z_port); + if (client == (Client *)0) { + syslog(LOG_WARNING, "no client at %s/%d", + inet_ntoa(newwho.sin_addr), ntohs(snotice.z_port)); + free_subscriptions(newsubs); + return(ZERR_NONE); + } + + /* translate the recipient to represent the foreign realm */ + sprintf(rlm_recipient, "@%s", realm->name); + for (temp = newsubs; temp; temp = temp->next) { + temp->dest.recip = make_string(rlm_recipient, 0); + } + + status = subscr_add_raw(client, (ZRealm *)0, newsubs); + } else if (!strcmp(snotice.z_opcode, REALM_REQ_SUBSCRIBE)) { + zdbug((LOG_DEBUG, "subscr_foreign_user REQ %s/%s", tp0, tp1)); + status = subscr_check_foreign_subs(notice, who, server, realm, newsubs); + } else { + syslog(LOG_ERR, "bogus opcode %s in subscr_forn_user", + snotice.z_opcode); + status = ZERR_NONE; + } + return(status); +} + diff --git a/server/test_server.c b/server/test_server.c new file mode 100644 index 0000000..cec33f8 --- /dev/null +++ b/server/test_server.c @@ -0,0 +1,348 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the server unit tests. + * + * Created by: Karl Ramm + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "zserver.h" + +int ulogin_add_user(ZNotice_t *notice, Exposure_type exposure, + struct sockaddr_in *who); +Exposure_type ulogin_remove_user(ZNotice_t *notice, + struct sockaddr_in *who, + int *err_return); +int ulogin_find(char *user, struct in_addr *host, + unsigned int port); +int ulogin_find_user(char *user); +void ulogin_flush_user(ZNotice_t *notice); +extern Location *locations; + +#define TEST(EXP) \ + do { \ + printf("%s:%d: %s: ", __FILE__, __LINE__, #EXP); \ + fflush(stdout); \ + if (EXP) { \ + puts("PASS"); \ + } else { \ + puts("FAIL"); \ + failures++; \ + } \ + fflush(stdout); \ + } while (0) + +#define V(EXP) \ + do { \ + printf("%s:%d: %s\n", __FILE__, __LINE__, #EXP); \ + fflush(stdout); \ + EXP; \ + } while (0) + +#define VI(EXP) \ + do { \ + int result; \ + printf("%s:%d: %s ->", __FILE__, __LINE__, #EXP); \ + fflush(stdout); \ + result=EXP; \ + printf(" %d\n", result); \ + fflush(stdout); \ + } while (0) + +#define PP(s) \ + do { \ + printf("%s:%d: %s\n", __FILE__, __LINE__, s); \ + fflush(stdout); \ + } while (0) + +#define P1(fmt, x) \ + do { \ + printf("%s:%d: " fmt "\n", __FILE__, __LINE__, x); \ + fflush(stdout); \ + } while (0) + +int failures = 0; + +void test_uloc(void); +void test_acl_files(void); + +int +main(int argc, char **argv) +{ + int logopt = 0; +#if 0 && defined(LOG_PERROR) + logopt = LOG_PERROR; +#endif + openlog("test_server", logopt, LOG_USER); + puts("Zephyr server testing"); + puts(""); + + test_uloc(); + test_acl_files(); + + if(failures) + printf("\n%d FAILURES\n", failures); + + exit(!(failures == 0)); +} + +void +test_uloc(void) +{ + ZNotice_t z1, z2, z0, z4; + String *s1, *s2, *s0, *s4; + struct sockaddr_in who1, who2, who3, who0, who4; + int ret; + + puts("uloc storage routines"); + + TEST(ulogin_find_user("nonexistent") == -1); + + /* fake up just enough */ + who1.sin_family = AF_INET; + who1.sin_port = 1; + who1.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + z1.z_class_inst = "user1"; + z1.z_port = 1; + z1.z_message = "here\0now\0this\0"; + z1.z_message_len = 14; + + s1 = make_string(z1.z_class_inst, 0); + + TEST(ulogin_add_user(&z1, NET_ANN, &who1) == 0); + TEST(ulogin_find_user("user1") != -1); + + who2.sin_family = AF_INET; + who2.sin_port = 2; + who2.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + z2.z_class_inst = "user2"; + z2.z_port = 2; + z2.z_message = "here\0now\0this\0"; + z2.z_message_len = 14; + + s2 = make_string(z2.z_class_inst, 0); + + TEST(ulogin_add_user(&z2, NET_ANN, &who2) == 0); + TEST(ulogin_find_user("user2") != -1); + TEST(locations[ulogin_find_user("user1")].user == s1); + TEST(locations[ulogin_find_user("user2")].user == s2); + TEST(ulogin_add_user(&z1, NET_ANN, &who1) == 0); + TEST(locations[ulogin_find_user("user1")].user == s1); + TEST(locations[ulogin_find_user("user2")].user == s2); + + who3.sin_family = AF_INET; + who3.sin_port = 3; + who3.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + TEST(ulogin_find("user1", &who3.sin_addr, 3) == -1); + + who0.sin_family = AF_INET; + who0.sin_port = 3; + who0.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + + z0.z_class_inst = "user0"; + z0.z_port = 3; + z0.z_message = "here\0now\0this\0"; + z0.z_message_len = 14; + + s0 = make_string(z0.z_class_inst, 0); + + TEST(ulogin_add_user(&z0, NET_ANN, &who0) == 0); + TEST(ulogin_find_user("user0") != -1); + TEST(locations[ulogin_find_user("user1")].user == s1); + TEST(locations[ulogin_find_user("user2")].user == s2); + + TEST(ulogin_remove_user(&z0, &who0, &ret) == NET_ANN && ret == 0); + /* 1 = NOLOC */ + TEST(ulogin_remove_user(&z0, &who0, &ret) == NONE && ret == 1); + + TEST(ulogin_add_user(&z0, NET_ANN, &who0) == 0); + TEST(ulogin_remove_user(&z1, &who0, &ret) == NET_ANN && ret == 0); + + V(ulogin_flush_user(&z0)); + TEST(ulogin_find_user("user0") == -1); + + TEST(ulogin_add_user(&z0, NET_ANN, &who0) == 0); + TEST(ulogin_add_user(&z1, NET_ANN, &who1) == 0); + V(ulogin_flush_user(&z1)); + TEST(ulogin_find_user("user1") == -1); + + who4.sin_family = AF_INET; + who4.sin_port = 4; + who4.sin_addr.s_addr = htonl(INADDR_ANY); + + z4.z_class_inst = "user4"; + z4.z_port = 4; + z4.z_message = "here\0now\0this\0"; + z4.z_message_len = 14; + + s4 = make_string(z4.z_class_inst, 0); + + TEST(ulogin_add_user(&z4, NET_ANN, &who4) == 0); + + V(uloc_flush_client(&who2)); + TEST(locations[ulogin_find_user("user0")].user == s0); + TEST(ulogin_find_user("user1") == -1); + TEST(ulogin_find_user("user2") == -1); + TEST(locations[ulogin_find_user("user4")].user == s4); + + V(uloc_hflush(&who0.sin_addr)); + TEST(ulogin_find_user("user0") == -1); + TEST(ulogin_find_user("user1") == -1); + TEST(ulogin_find_user("user2") == -1); + TEST(locations[ulogin_find_user("user4")].user == s4); + puts(""); +} + +void +test_acl_files(){ + char filename[]="/tmp/test_server_acl.XXXXXX"; + int fd; + int result; + struct sockaddr_in who_zero; + struct sockaddr_in who_localhost; + struct sockaddr_in who_broadcast; + + memset(&who_zero, 0, sizeof(who_zero)); + memset(&who_localhost, 0, sizeof(who_localhost)); + memset(&who_broadcast, 0, sizeof(who_broadcast)); + + who_localhost.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + who_broadcast.sin_addr.s_addr = htonl(INADDR_BROADCAST); + + puts("low-level acl routines"); + puts(""); + + fd = mkstemp(filename); + P1("acl file is %s", filename); + + PP("empty acl"); + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 0); + + write(fd, "*\n", 2); + acl_cache_reset(); + PP("acl of *"); + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 1); + TEST(acl_check(filename, "bar", NULL) == 1); + + lseek(fd, 0, SEEK_SET); + write(fd, "foo\n", 4); + acl_cache_reset(); + PP("acl of just foo"); + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 1); + TEST(acl_check(filename, "bar", NULL) == 0); + + lseek(fd, 0, SEEK_SET); + write(fd, "*@TIM.EDU\n", 10); + acl_cache_reset(); + PP("acl of *@TIM.EDU"); + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 0); + TEST(acl_check(filename, "bar", NULL) == 0); + TEST(acl_check(filename, "foo@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 1); + + lseek(fd, 0, SEEK_SET); + write(fd, "*.*@TIM.EDU\n", 12); + acl_cache_reset(); + PP("acl of *.*@TIM.EDU"); + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 0); + TEST(acl_check(filename, "bar", NULL) == 0); + TEST(acl_check(filename, "foo@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 1); + + lseek(fd, 0, SEEK_SET); + write(fd, "foo@TIM.EDU\n", 12); + acl_cache_reset(); + PP("acl of foo@TIM.EDU"); + + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 0); + TEST(acl_check(filename, "bar", NULL) == 0); + TEST(acl_check(filename, "foo@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "f\\oo@TIM.EDU", NULL) == 0); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 0); + + lseek(fd, 0, SEEK_SET); + write(fd, "!bar@TIM.EDU\n*@*\n", 17); + acl_cache_reset(); + PP("acl of !bar@TIM.EDU, *@*"); + + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 1); + TEST(acl_check(filename, "bar", NULL) == 1); + TEST(acl_check(filename, "foo@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "f\\oo@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 0); + + TEST(acl_check(filename, NULL, &who_zero) == 0); + TEST(acl_check(filename, NULL, &who_localhost) == 0); + + write(fd, "@0.0.0.0\n", 9); + acl_cache_reset(); + PP("acl +@0.0.0.0"); + + TEST(acl_check(filename, NULL, &who_zero) == 1); + TEST(acl_check(filename, NULL, &who_localhost) == 0); + TEST(acl_check(filename, "bar@TIM.EDU", &who_zero) == 0); + + lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); + write(fd, "*@*\n@0.0.0.0\n!@127.0.0.0/8\n", 27); + acl_cache_reset(); + PP("acl *@*, @0.0.0.0, !@127/8"); + + TEST(acl_check(filename, NULL, &who_zero) == 1); + TEST(acl_check(filename, "bar@TIM.EDU", &who_zero) == 1); + TEST(acl_check(filename, "bar@TIM.EDU", &who_localhost) == 0); + + lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); + write(fd, "*/root@TIM.EDU\n", 15); + acl_cache_reset(); + PP("acl */root@TIM.EDU"); + TEST(acl_check(filename, NULL, NULL) == 0); + TEST(acl_check(filename, "foo", NULL) == 0); + TEST(acl_check(filename, "bar", NULL) == 0); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 0); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 0); + TEST(acl_check(filename, "foo/root@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "bar/root@TIM.EDU", NULL) == 1); + + lseek(fd, 0, SEEK_SET); + ftruncate(fd, 0); + write(fd, "foo/*@TIM.EDU\n", 14); + acl_cache_reset(); + PP("acl foo/*@TIM.EDU"); + TEST(acl_check(filename, "foo@TIM.EDU", NULL) == 0); + TEST(acl_check(filename, "bar@TIM.EDU", NULL) == 0); + TEST(acl_check(filename, "foo/root@TIM.EDU", NULL) == 1); + TEST(acl_check(filename, "bar/root@TIM.EDU", NULL) == 0); + + PP("check vs. nonexistent acl"); + TEST(acl_check("/nonexistent", "foo", NULL) == 0); + unlink(filename); + puts(""); +} diff --git a/server/timer.c b/server/timer.c new file mode 100644 index 0000000..932c819 --- /dev/null +++ b/server/timer.c @@ -0,0 +1,250 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for managing multiple timeouts. + * + * Created by: John T. Kohl + * Derived from timer_manager_ by Ken Raeburn + * + * $Id$ + * + */ + +#include "zserver.h" + +#ifndef SABER +#ifndef lint +static const char rcsid[] = +"$Id$"; +#endif /* lint */ +#endif /* SABER */ + +/* + * timer_manager_ -- routines for handling timers in login_shell + * (and elsewhere) + * + * Copyright 1986 Student Information Processing Board, + * Massachusetts Institute of Technology + * + * written by Ken Raeburn + + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright + notice and this permission notice appear in supporting + documentation, and that the name of M.I.T. and the Student + Information Processing Board not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + M.I.T. and the Student Information Processing Board + make no representations about the suitability of + this software for any purpose. It is provided "as is" + without express or implied warranty. + + */ + + +/* + * External functions: + * + * Timer *timer_set_rel (time_rel, proc, arg) + * long time_rel; + * void (*proc)(); + * void *arg; + * Timer *timer_set_abs (time_abs, proc, arg) + * long time_abs; + * void (*proc)(); + * void *arg; + * + * void timer_reset(tmr) + * Timer *tmr; + * + * void timer_process() + * + */ + +/* DELTA is just an offset to keep the size a bit less than a power + * of two. It's measured in pointers, so it's 32 bytes on most + * systems. */ +#define DELTA 8 +#define INITIAL_HEAP_SIZE (1024 - DELTA) + +/* We have three operations which we need to be able to perform + * quickly: adding a timer, deleting a timer given a pointer to + * it, and determining which timer will be the next to go off. A + * heap is an ideal data structure for these purposes, so we use + * one. The heap is an array of pointers to timers, and each timer + * knows the position of its pointer in the heap. + * + * Okay, what is the heap, exactly? It's a data structure, + * represented as an array, with the invariant condition that + * the timeout of heap[i] is less than or equal to the timeout of + * heap[i * 2 + 1] and heap[i * 2 + 2] (assuming i * 2 + 1 and + * i * 2 + 2 are valid * indices). An obvious consequence of this + * is that heap[0] has the lowest timer value, so finding the first + * timer to go off is easy. We say that an index i has "children" + * i * 2 + 1 and i * 2 + 1, and the "parent" (i - 1) / 2. + * + * To add a timer to the heap, we start by adding it to the end, and + * then keep swapping it with its parent until it has a parent with + * a timer value less than its value. With a little bit of thought, + * you can see that this preserves the heap property on all indices + * of the array. + * + * To delete a timer at position i from the heap, we discard it and + * fill in its position with the last timer in the heap. In order + * to restore the heap, we have to consider two cases: the timer + * value at i is less than that of its parent, or the timer value at + * i is greater than that of one of its children. In the first case, + * we propagate the timer at i up the tree, swapping it with its + * parent, until the heap is restored; in the second case, we + * propagate the timer down the tree, swapping it with its least + * child, until the heap is restored. */ + +/* In order to ensure that the back pointers from timers are consistent + * with the heap pointers, all heap assignments should be done with the + * HEAP_ASSIGN() macro, which sets the back pointer and updates the + * heap at the same time. */ +#define PARENT(i) (((i) - 1) / 2) +#define CHILD1(i) ((i) * 2 + 1) +#define CHILD2(i) ((i) * 2 + 2) +#define TIME(i) (heap[i]->abstime) +#define HEAP_ASSIGN(pos, tmr) ((heap[pos] = (tmr))->heap_pos = (pos)) + +static Timer **heap; +static int num_timers = 0; +static int heap_size = 0; + +static void timer_botch (void*); +static Timer *add_timer (Timer *); + +Timer * +timer_set_rel(long time_rel, + void (*proc)(void *), + void *arg) +{ + Timer *new_t; + + new_t = (Timer *) malloc(sizeof(*new_t)); + if (new_t == NULL) + return(NULL); + new_t->abstime = time_rel + NOW; + new_t->func = proc; + new_t->arg = arg; + return add_timer(new_t); +} + +void +timer_reset(Timer *tmr) +{ + int pos, min; + + /* Free the timer, saving its heap position. */ + pos = tmr->heap_pos; + free(tmr); + + if (pos != num_timers - 1) { + /* Replace the timer with the last timer in the heap and + * restore the heap, propagating the timer either up or + * down, depending on which way it violates the heap + * property to insert the last timer in place of the + * deleted timer. */ + if (pos > 0 && TIME(num_timers - 1) < TIME(PARENT(pos))) { + do { + HEAP_ASSIGN(pos, heap[PARENT(pos)]); + pos = PARENT(pos); + } while (pos > 0 && TIME(num_timers - 1) < TIME(PARENT(pos))); + HEAP_ASSIGN(pos, heap[num_timers - 1]); + } else { + while (CHILD2(pos) < num_timers) { + min = num_timers - 1; + if (TIME(CHILD1(pos)) < TIME(min)) + min = CHILD1(pos); + if (TIME(CHILD2(pos)) < TIME(min)) + min = CHILD2(pos); + HEAP_ASSIGN(pos, heap[min]); + pos = min; + } + if (pos != num_timers - 1) + HEAP_ASSIGN(pos, heap[num_timers - 1]); + } + } + num_timers--; +} + + +#define set_timeval(t,s) ((t).tv_sec=(s),(t).tv_usec=0,(t)) + +static Timer * +add_timer(Timer *new) +{ + int pos; + + /* Create or resize the heap as necessary. */ + if (heap_size == 0) { + heap_size = INITIAL_HEAP_SIZE; + heap = (Timer **) malloc(heap_size * sizeof(Timer *)); + } else if (num_timers >= heap_size) { + heap_size = heap_size * 2 + DELTA; + heap = (Timer **) realloc(heap, heap_size * sizeof(Timer *)); + } + if (!heap) { + free(new); + return NULL; + } + + /* Insert the Timer *into the heap. */ + pos = num_timers; + while (pos > 0 && new->abstime < TIME(PARENT(pos))) { + HEAP_ASSIGN(pos, heap[PARENT(pos)]); + pos = PARENT(pos); + } + HEAP_ASSIGN(pos, new); + num_timers++; + + return new; +} + +void +timer_process(void) +{ + Timer *t; + timer_proc func; + void *arg; + + if (num_timers == 0 || heap[0]->abstime > NOW) + return; + + /* Remove the first timer from the heap, remembering its + * function and argument. */ + t = heap[0]; + func = t->func; + arg = t->arg; + t->func = timer_botch; + t->arg = NULL; + timer_reset(t); + + /* Run the function. */ + func(arg); +} + +struct timeval * +timer_timeout(struct timeval *tvbuf) +{ + if (num_timers > 0) { + tvbuf->tv_sec = heap[0]->abstime - NOW; + if (tvbuf->tv_sec < 0) + tvbuf->tv_sec = 0; + tvbuf->tv_usec = 0; + return tvbuf; + } else { + return NULL; + } +} + +static void +timer_botch(void *arg) +{ + syslog(LOG_CRIT, "timer botch\n"); + abort(); +} + diff --git a/server/timer.h b/server/timer.h new file mode 100644 index 0000000..67ec93f --- /dev/null +++ b/server/timer.h @@ -0,0 +1,54 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains definitions used by timer.c + * + * Created by: John T. Kohl + * Derived from timer_manager_.h by Ken Raeburn + * + * $Id$ + * + */ + +#ifndef __TIMER_H + +/* + * timer_manager_ -- routines for handling timers in login_shell + * (and elsewhere) + * + * Copyright 1986 Student Information Processing Board, + * Massachusetts Institute of Technology + * + * written by Ken Raeburn + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting +documentation, and that the name of M.I.T. and the Student +Information Processing Board not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. +M.I.T. and the Student Information Processing Board +make no representations about the suitability of +this software for any purpose. It is provided "as is" +without express or implied warranty. + + */ + +typedef void (*timer_proc) __P((void *)); + +typedef struct _Timer { + int heap_pos; /* Position in timer heap */ + long abstime; + timer_proc func; + void *arg; +} Timer; + +Timer *timer_set_rel(long, timer_proc, void *); +Timer *timer_set_abs(long, timer_proc, void *); +void timer_reset(Timer *); +void timer_process(void); +struct timeval *timer_timeout(struct timeval *tvbuf); + +#endif /* __TIMER_H */ + diff --git a/server/uloc.c b/server/uloc.c new file mode 100644 index 0000000..ab936b8 --- /dev/null +++ b/server/uloc.c @@ -0,0 +1,932 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for the User Locator service. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" +#include + +#ifndef lint +#ifndef SABER +static const char rcsid_uloc_c[] = +"$Id$"; +#endif /* SABER */ +#endif /* lint */ + +/* + * The user locator functions. + * + * External functions: + * + * void ulocate_dispatch(notice, auth, who, server) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * Server *server; + * + * void ulogin_dispatch(notice, auth, who, server) + * ZNotice_t *notice; + * int auth; + * struct sockaddr_in *who; + * Server *server; + * + * void uloc_hflush(addr) + * struct in_addr *addr; + * + * void uloc_flush_client(sin) + * struct sockaddr_in *sin; + * + * Code_t uloc_send_locations() + * + * void uloc_dump_locs(fp) + * FILE *fp; + */ + +/* + * The user locator. + * We maintain an array of Location sorted by user (so we can do + * binary searches), growing and shrinking it as necessary. + */ + +/* WARNING: make sure this is the same as the number of strings you */ +/* plan to hand back to the user in response to a locate request, */ +/* else you will lose. See ulogin_locate() and uloc_send_locations() */ +#define NUM_FIELDS 3 + +#define NOLOC 1 +#define QUIET -1 +#define UNAUTH -2 + +static void ulogin_locate(ZNotice_t *notice, struct sockaddr_in *who, + int auth); +void ulogin_flush_user(ZNotice_t *notice); +int ulogin_find(char *user, struct in_addr *host, + unsigned int port); +int ulogin_find_user(char *user); +static int ulogin_setup(ZNotice_t *notice, Location *locs, + Exposure_type exposure, struct sockaddr_in *who); +int ulogin_add_user(ZNotice_t *notice, Exposure_type exposure, + struct sockaddr_in *who); +static int ulogin_parse(ZNotice_t *notice, Location *locs); +Exposure_type ulogin_remove_user(ZNotice_t *notice, + struct sockaddr_in *who, + int *err_return); +static void login_sendit(ZNotice_t *notice, int auth, + struct sockaddr_in *who, int external); +static char **ulogin_marshal_locs(ZNotice_t *notice, int *found, int auth); + +static void free_loc(Location *loc); +static void ulogin_locate_forward(ZNotice_t *notice, struct sockaddr_in *who, + ZRealm *realm); +static int reallocate_locations(int new_num); + +Location *locations = NULL; /* ptr to first in array */ +static int num_locs = 0; /* number in array */ + +/* + * Dispatch a LOGIN notice. + */ + +Code_t +ulogin_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + Exposure_type retval; + int err_ret; + + if (strcmp(notice->z_opcode, LOGIN_USER_LOGOUT) == 0) { + retval = ulogin_remove_user(notice, who, &err_ret); + switch (retval) { + case NONE: + if (err_ret == UNAUTH) { + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } else if (err_ret == NOLOC) { + if (server == me_server) + clt_ack(notice, who, NOT_FOUND); + return ZERR_NONE; + } + syslog(LOG_ERR,"bogus location exposure NONE, %s", + notice->z_sender); + break; + case OPSTAFF_VIS: + case REALM_VIS: + /* he is not announced to people. Silently ack */ + if (server == me_server) + ack(notice, who); + break; + case REALM_ANN: + case NET_VIS: + if (server == me_server) + sendit(notice, 1, who, 0); + break; + case NET_ANN: + /* currently no distinction between these. + just announce */ + /* we assume that if this user is at a certain + IP address, we can trust the logout to be + authentic. ulogin_remove_user checks the + ip addrs */ + if (server == me_server) + sendit(notice, 1, who, 1); + break; + default: + syslog(LOG_ERR,"bogus location exposure %d/%s", + (int) retval, notice->z_sender); + break; + } + if (server == me_server) /* tell the other servers */ + server_forward(notice, auth, who); + return ZERR_NONE; + } + if (!bdumping && + (!auth || strcmp(notice->z_sender, notice->z_class_inst) != 0) && + (!auth || !opstaff_check(notice->z_sender))) { + zdbug((LOG_DEBUG,"unauthentic ulogin: %d %s %s", auth, + notice->z_sender, notice->z_class_inst)); + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } + if (strcmp(notice->z_opcode, LOGIN_USER_FLUSH) == 0) { + ulogin_flush_user(notice); + if (server == me_server) + ack(notice, who); + } else if (strcmp(notice->z_opcode, EXPOSE_NONE) == 0) { + ulogin_remove_user(notice, who, &err_ret); + if (err_ret == UNAUTH) { + if (server == me_server) + clt_ack(notice, who, AUTH_FAILED); + return ZERR_NONE; + } else if (err_ret == NOLOC) { + if (server == me_server) + clt_ack(notice, who, NOT_FOUND); + return ZERR_NONE; + } + if (server == me_server) { + ack(notice, who); + server_forward(notice, auth, who); + } + return ZERR_NONE; + } else if (strcmp(notice->z_opcode, EXPOSE_OPSTAFF) == 0) { + err_ret = ulogin_add_user(notice, OPSTAFF_VIS, who); + if (server == me_server) { + if (err_ret) + nack(notice, who); + else + ack(notice, who); + } + } else if (strcmp(notice->z_opcode, EXPOSE_REALMVIS) == 0) { + err_ret = ulogin_add_user(notice, REALM_VIS, who); + if (server == me_server) { /* realm vis is not broadcast, + so we ack it here */ + if (err_ret) + nack(notice, who); + else + ack(notice, who); + } + } else if (!strcmp(notice->z_opcode, EXPOSE_REALMANN)) { + err_ret = ulogin_add_user(notice, REALM_ANN, who); + if (server == me_server) { /* announce to the realm */ + if (err_ret) + nack(notice, who); + else + login_sendit(notice, auth, who, 0); + } + } else if (!strcmp(notice->z_opcode, EXPOSE_NETVIS)) { + err_ret = ulogin_add_user(notice, NET_VIS, who); + if (server == me_server) { /* announce to the realm */ + if (err_ret) + nack(notice, who); + else + login_sendit(notice, auth, who, 0); + } + } else if (!strcmp(notice->z_opcode, EXPOSE_NETANN)) { + err_ret = ulogin_add_user(notice, NET_ANN, who); + if (server == me_server) { /* tell the world */ + if (err_ret) + nack(notice, who); + else + login_sendit(notice, auth, who, 1); + } + } else { + if (!strcmp(notice->z_opcode, LOGIN_USER_LOGIN)) { + zdbug((LOG_DEBUG, "ulog opcode from unknown foreign realm %s", + notice->z_opcode)); + } else { + syslog(LOG_ERR, "unknown ulog opcode %s", notice->z_opcode); + } + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } + if (server == me_server) + server_forward(notice, auth, who); + return ZERR_NONE; +} + +static void +login_sendit(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + int external) +{ + ZNotice_t log_notice; + + /* we must copy the notice struct here because we need the original + for forwarding. We needn't copy the private data of the notice, + since that isn't modified by sendit and its subroutines. */ + + log_notice = *notice; + + log_notice.z_opcode = LOGIN_USER_LOGIN; + sendit(&log_notice, auth, who, external); +} + + +/* + * Dispatch a LOCATE notice. + */ +Code_t +ulocate_dispatch(ZNotice_t *notice, + int auth, + struct sockaddr_in *who, + Server *server) +{ + char *cp; + ZRealm *realm; + + if (!strcmp(notice->z_opcode, LOCATE_LOCATE)) { + /* we are talking to a current-rev client; send an ack */ + ack(notice, who); + cp = strchr(notice->z_class_inst, '@'); + if (cp && (realm = realm_get_realm_by_name(cp + 1))) + ulogin_locate_forward(notice, who, realm); + else + ulogin_locate(notice, who, auth); + return ZERR_NONE; + } else { + syslog(LOG_ERR, "unknown uloc opcode %s", notice->z_opcode); + if (server == me_server) + nack(notice, who); + return ZERR_NONE; + } +} + +/* + * reallocate locations + */ +static int +reallocate_locations(int new_num) { + Location *new_loc; + + if (new_num) { + new_loc = realloc(locations, new_num * sizeof(Location)); + if (new_loc == NULL) { + syslog(LOG_ERR, "failed to resize uloc table: %m"); + if (new_num < num_locs) + num_locs = new_num; + return errno; + } + locations = new_loc; + } else { + free(locations); + locations = NULL; + } + + num_locs = new_num; + + return 0; +} + +/* + * Flush all locations at the address. + */ + +void +uloc_hflush(struct in_addr *addr) +{ + int i, new_num = 0; + + if (num_locs == 0) + return; /* none to flush */ + + for (i = 0; i < num_locs; i++) + if (locations[i].addr.sin_addr.s_addr != addr->s_addr) + locations[new_num++] = locations[i]; + else + free_loc(&locations[i]); + + reallocate_locations(new_num); +} + +void +uloc_flush_client(struct sockaddr_in *sin) +{ + int i, new_num = 0; + + if (num_locs == 0) + return; /* none to flush */ + + for (i = 0; i < num_locs; i++) + if ((locations[i].addr.sin_addr.s_addr != sin->sin_addr.s_addr) + || (locations[i].addr.sin_port != sin->sin_port)) + locations[new_num++] = locations[i]; + else + free_loc(&locations[i]); + + num_locs = new_num; + + reallocate_locations(new_num); +} + +/* + * Send the locations for host for a brain dump + */ + +/*ARGSUSED*/ +Code_t +uloc_send_locations(void) +{ + Location *loc; + int i; + char *lyst[NUM_FIELDS]; + char *exposure_level; + Code_t retval; + + for (i = 0, loc = locations; i < num_locs; i++, loc++) { + lyst[0] = (char *) loc->machine->string; + lyst[1] = (char *) loc->time; + lyst[2] = (char *) loc->tty->string; + + switch (loc->exposure) { + case OPSTAFF_VIS: + exposure_level = EXPOSE_OPSTAFF; + break; + case REALM_VIS: + exposure_level = EXPOSE_REALMVIS; + break; + case REALM_ANN: + exposure_level = EXPOSE_REALMANN; + break; + case NET_VIS: + exposure_level = EXPOSE_NETVIS; + break; + case NET_ANN: + exposure_level = EXPOSE_NETANN; + break; + default: + syslog(LOG_ERR,"broken location state %s/%d", + loc->user->string, (int) loc->exposure); + exposure_level = EXPOSE_OPSTAFF; + break; + } + retval = bdump_send_list_tcp(ACKED, &loc->addr, LOGIN_CLASS, + loc->user->string, exposure_level, myname, + "", lyst, NUM_FIELDS); + if (retval != ZERR_NONE) { + syslog(LOG_ERR, "uloc_send_locs: %s", error_message(retval)); + return(retval); + } + } + return ZERR_NONE; +} + +/* + * Add the user to the internal table of locations. + */ + +int +ulogin_add_user(ZNotice_t *notice, + Exposure_type exposure, + struct sockaddr_in *who) +{ + Location newloc; + int i, here; + + here = ulogin_find(notice->z_class_inst, &who->sin_addr, notice->z_port); + if (here >= 0) { + /* Update the time, tty, and exposure on the existing location. */ + locations[here].exposure = exposure; + if (ulogin_parse(notice, &newloc) == 0) { + free_string(locations[here].tty); + locations[here].tty = dup_string(newloc.tty); + free(locations[here].time); + locations[here].time = strsave(newloc.time); + free_loc(&newloc); + } + return 0; + } + + if (ulogin_setup(notice, &newloc, exposure, who)) + return 1; + + if(reallocate_locations(num_locs + 1)) + return 1; + + /* skip old locs */ + for (i = 0; + i < num_locs-1 && comp_string(locations[i].user, newloc.user) < 0; + i++) + ; + + here = i; + + /* copy the rest */ + for(i = num_locs - 1; i > here; i--) + locations[i] = locations[i - 1]; + + locations[here] = newloc; + + return 0; +} + +/* + * Set up the location locs with the information in the notice. + */ + +static int +ulogin_setup(ZNotice_t *notice, + Location *locs, + Exposure_type exposure, + struct sockaddr_in *who) +{ + if (ulogin_parse(notice, locs)) + return 1; + + locs->exposure = exposure; + locs->addr.sin_family = AF_INET; + locs->addr.sin_addr.s_addr = who->sin_addr.s_addr; + locs->addr.sin_port = notice->z_port; + return(0); +} + +/* + * Parse the location information in the notice, and fill it into *locs + */ + +static int +ulogin_parse(ZNotice_t *notice, + Location *locs) +{ + char *cp, *base; + int nulls = 0; + + if (!notice->z_message_len) { + syslog(LOG_ERR, "short ulogin"); + return 1; + } + + base = notice->z_message; + for (cp = base; cp < base + notice->z_message_len; cp++) { + if (!*cp) + nulls++; + } + if (nulls < 3) { + syslog(LOG_ERR, "zloc bad format from user %s (only %d fields)", + notice->z_sender, nulls); + return 1; + } + + locs->user = make_string(notice->z_class_inst,0); + + cp = base; + locs->machine = make_string(cp,0); + + cp += (strlen(cp) + 1); + locs->time = strsave(cp); + + /* This field might not be null-terminated */ + cp += (strlen(cp) + 1); + locs->tty = make_string(cp, 0); + + return 0; +} + +int +ulogin_find(char *user, + struct in_addr *host, + unsigned int port) +{ + int i; + String *str; + + /* Find the first location for this user. */ + i = ulogin_find_user(user); + if (i == -1) + return -1; + + /* Look for a location which matches the host and port. */ + str = make_string(user, 0); + while (i < num_locs && locations[i].user == str) { + if (locations[i].addr.sin_addr.s_addr == host->s_addr + && locations[i].addr.sin_port == port) { + free_string(str); + return i; + } + i++; + } + + free_string(str); + return -1; +} + +/* + * Return the table index of the first instance of this user@realm in the + * table. + */ +int +ulogin_find_user(char *user) +{ + int i, rlo, rhi; + int compar; + String *str; + + if (!locations) + return -1; + + str = make_string(user, 0); + + /* i is the current midpoint location, rlo is the lowest we will + * still check, and rhi is the highest we will still check. */ + + i = num_locs / 2; + rlo = 0; + rhi = num_locs - 1; + + while ((compar = comp_string(locations[i].user, str)) != 0) { + if (compar < 0) + rlo = i + 1; + else + rhi = i - 1; + if (rhi - rlo < 0) { + free_string(str); + return -1; + } + i = (rhi + rlo) / 2; + } + + /* Back up to the first location for this user. */ + while (i > 0 && locations[i - 1].user == str) + i--; + free_string(str); + return i; +} + +/* + * remove the user specified in notice from the internal table + */ + +Exposure_type +ulogin_remove_user(ZNotice_t *notice, + struct sockaddr_in *who, + int *err_return) +{ + int here, i; + Exposure_type quiet; + + *err_return = 0; + here = ulogin_find(notice->z_class_inst, &who->sin_addr, notice->z_port); + if (here == -1) { + *err_return = NOLOC; + return NONE; + } + + quiet = locations[here].exposure; + + /* free up this one */ + free_loc(&locations[here]); + + for(i = here; i < num_locs - 1; i++) + locations[i] = locations[i + 1]; + + reallocate_locations(num_locs - 1); + + /* all done */ + return quiet; +} + +/* + * remove all locs of the user specified in notice from the internal table + */ + +void +ulogin_flush_user(ZNotice_t *notice) +{ + int here, i, j, num_match, num_left; + + i = num_match = num_left = 0; + + here = ulogin_find_user(notice->z_class_inst); + if (here == -1) + return; + + num_left = num_locs - here; + + while (num_left && + !strcasecmp(locations[here + num_match].user->string, + notice->z_class_inst)) { + /* as long as we keep matching, march up the list */ + num_match++; + num_left--; + } + + for (j = 0; j < num_match; j++) + free_loc(&locations[here + j]); + + /* copy the rest */ + for (i = here; i < num_locs - num_match; i++) + locations[i] = locations[i + 1]; + + reallocate_locations(num_locs - num_match); +} + + +static void +ulogin_locate(ZNotice_t *notice, + struct sockaddr_in *who, + int auth) +{ + char **answer; + int found; + Code_t retval; + struct sockaddr_in send_to_who; + + answer = ulogin_marshal_locs(notice, &found, auth); + + send_to_who = *who; + send_to_who.sin_port = notice->z_port; + + retval = ZSetDestAddr(&send_to_who); + if (retval != ZERR_NONE) { + syslog(LOG_WARNING, "ulogin_locate set addr: %s", + error_message(retval)); + if (answer) + free(answer); + return; + } + + notice->z_kind = ACKED; + + /* use xmit_frag() to send each piece of the notice */ + + retval = ZSrvSendRawList(notice, answer, found * NUM_FIELDS, xmit_frag); + if (retval != ZERR_NONE) + syslog(LOG_WARNING, "ulog_locate xmit: %s", error_message(retval)); + if (answer) + free(answer); +} + +/* + * Locate the user and collect the locations into an array. Return the # of + * locations in *found. + */ + +static char ** +ulogin_marshal_locs(ZNotice_t *notice, + int *found, + int auth) +{ + Location **matches = (Location **) 0; + char **answer; + int i = 0; + String *inst; + int local = (auth && realm_sender_in_realm(ZGetRealm(), notice->z_sender)); + int opstaff = (auth && opstaff_check(notice->z_sender)); + + *found = 0; /* # of matches */ + + i = ulogin_find_user(notice->z_class_inst); + if (i == -1) + return NULL; + + inst = make_string(notice->z_class_inst,0); + while (i < num_locs && (inst == locations[i].user)) { + /* these locations match */ + switch (locations[i].exposure) { + case OPSTAFF_VIS: + if (!opstaff) { + i++; + continue; + } + case REALM_VIS: + case REALM_ANN: + if (!local) { + i++; + continue; + } + case NET_VIS: + case NET_ANN: + default: + break; + } + if (!*found) { + matches = (Location **) malloc(sizeof(Location *)); + if (!matches) { + syslog(LOG_ERR, "ulog_loc: no mem"); + break; /* from the while */ + } + matches[0] = &locations[i]; + (*found)++; + } else { + matches = (Location **) realloc(matches, + ++(*found) * sizeof(Location *)); + if (!matches) { + syslog(LOG_ERR, "ulog_loc: realloc no mem"); + *found = 0; + break; /* from the while */ + } + matches[*found - 1] = &locations[i]; + } + i++; + } + free_string(inst); + + /* OK, now we have a list of user@host's to return to the client + in matches */ + + +#ifdef DEBUG + if (zdebug) { + for (i = 0; i < *found ; i++) + zdbug((LOG_DEBUG,"found %s", + matches[i]->user->string)); + } +#endif + + /* coalesce the location information into a list of char *'s */ + answer = (char **) malloc((*found) * NUM_FIELDS * sizeof(char *)); + if (!answer) { + syslog(LOG_ERR, "zloc no mem(answer)"); + *found = 0; + } else + for (i = 0; i < *found ; i++) { + answer[i * NUM_FIELDS] = matches[i]->machine->string; + answer[i * NUM_FIELDS + 1] = matches[i]->time; + answer[i * NUM_FIELDS + 2] = matches[i]->tty->string; + } + + if (matches) + free(matches); + return answer; +} + +void +uloc_dump_locs(FILE *fp) +{ + int i; + + for (i = 0; i < num_locs; i++) { + fputs("'", fp); + dump_quote(locations[i].user->string, fp); + fputs("' '", fp); + dump_quote(locations[i].machine->string, fp); + fputs("' '", fp); + dump_quote(locations[i].time, fp); + fputs("' '", fp); + dump_quote(locations[i].tty->string, fp); + fputs("' ", fp); + switch (locations[i].exposure) { + case OPSTAFF_VIS: + fputs("OPSTAFF", fp); + break; + case REALM_VIS: + fputs("RLM_VIS", fp); + break; + case REALM_ANN: + fputs("RLM_ANN", fp); + break; + case NET_VIS: + fputs("NET_VIS", fp); + break; + case NET_ANN: + fputs("NET_ANN", fp); + break; + default: + fprintf(fp, "? %d ?", locations[i].exposure); + break; + } + fprintf(fp, " %s/%d\n", inet_ntoa(locations[i].addr.sin_addr), + ntohs(locations[i].addr.sin_port)); + } +} + +static void +free_loc(Location *loc) +{ + free_string(loc->user); + free_string(loc->machine); + free_string(loc->tty); + free(loc->time); + return; +} + +static void +ulogin_locate_forward(ZNotice_t *notice, + struct sockaddr_in *who, + ZRealm *realm) +{ + ZNotice_t lnotice; + + lnotice = *notice; + lnotice.z_opcode = REALM_REQ_LOCATE; + + realm_handoff(&lnotice, 1, who, realm, 0); +} + +void +ulogin_realm_locate(ZNotice_t *notice, + struct sockaddr_in *who, + ZRealm *realm) +{ + char **answer; + int found; + Code_t retval; + ZNotice_t lnotice; + char *pack; + int packlen; + +#ifdef DEBUG + if (zdebug) + zdbug((LOG_DEBUG, "ulogin_realm_locate")); +#endif + + answer = ulogin_marshal_locs(notice, &found, 0/*AUTH*/); + + lnotice = *notice; + lnotice.z_opcode = REALM_ANS_LOCATE; + + if ((retval = ZFormatRawNoticeList(&lnotice, answer, found * NUM_FIELDS, &pack, &packlen)) != ZERR_NONE) { + syslog(LOG_WARNING, "ulog_rlm_loc format: %s", + error_message(retval)); + + if (answer) + free(answer); + return; + } + if (answer) + free(answer); + + if ((retval = ZParseNotice(pack, packlen, &lnotice)) != ZERR_NONE) { + syslog(LOG_WARNING, "subscr_rlm_sendit parse: %s", + error_message(retval)); + free(pack); + return; + } + + realm_handoff(&lnotice, 1, who, realm, 0); + free(pack); + + return; +} + +void +ulogin_relay_locate(ZNotice_t *notice, + struct sockaddr_in *who) +{ + ZNotice_t lnotice; + Code_t retval; + struct sockaddr_in newwho; + char *pack; + int packlen; + + notice_extract_address(notice, &newwho); + + if ((retval = ZSetDestAddr(&newwho)) != ZERR_NONE) { + syslog(LOG_WARNING, "uloc_relay_loc set addr: %s", + error_message(retval)); + return; + } + + lnotice = *notice; + lnotice.z_opcode = LOCATE_LOCATE; + lnotice.z_kind = ACKED; + lnotice.z_auth = 0; + lnotice.z_authent_len = 0; + lnotice.z_ascii_authent = ""; + lnotice.z_checksum = 0; + lnotice.z_ascii_checksum = ""; + + if ((retval = ZFormatRawNotice(&lnotice, &pack, &packlen)) != ZERR_NONE) { + syslog(LOG_WARNING, "ulog_relay_loc format: %s", + error_message(retval)); + return; + } + + if ((retval = ZSendPacket(pack, packlen, 0)) != ZERR_NONE) { + syslog(LOG_WARNING, "ulog_relay_loc xmit: %s", + error_message(retval)); + } + free(pack); +} diff --git a/server/utf8proc.c b/server/utf8proc.c new file mode 100644 index 0000000..40530b9 --- /dev/null +++ b/server/utf8proc.c @@ -0,0 +1,585 @@ +/* + * Copyright (c) 2006-2007 Jan Behrens, FlexiGuided GmbH, Berlin + * + * 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. + */ + +/* + * This library contains derived data from a modified version of the + * Unicode data files. + * + * The original data files are available at + * http://www.unicode.org/Public/UNIDATA/ + * + * Please notice the copyright statement in the file "utf8proc_data.c". + */ + + +/* + * File name: utf8proc.c + * Version: 1.1.1 + * Last changed: 2007-07-22 + * + * Description: + * Implementation of libutf8proc. + */ + + +#include "utf8proc.h" +#include "utf8proc_data.c" + + +const int8_t utf8proc_utf8class[256] = { + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 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, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0 }; + +#define UTF8PROC_HANGUL_SBASE 0xAC00 +#define UTF8PROC_HANGUL_LBASE 0x1100 +#define UTF8PROC_HANGUL_VBASE 0x1161 +#define UTF8PROC_HANGUL_TBASE 0x11A7 +#define UTF8PROC_HANGUL_LCOUNT 19 +#define UTF8PROC_HANGUL_VCOUNT 21 +#define UTF8PROC_HANGUL_TCOUNT 28 +#define UTF8PROC_HANGUL_NCOUNT 588 +#define UTF8PROC_HANGUL_SCOUNT 11172 +// END is exclusive +#define UTF8PROC_HANGUL_L_START 0x1100 +#define UTF8PROC_HANGUL_L_END 0x115A +#define UTF8PROC_HANGUL_L_FILLER 0x115F +#define UTF8PROC_HANGUL_V_START 0x1160 +#define UTF8PROC_HANGUL_V_END 0x11A3 +#define UTF8PROC_HANGUL_T_START 0x11A8 +#define UTF8PROC_HANGUL_T_END 0x11FA +#define UTF8PROC_HANGUL_S_START 0xAC00 +#define UTF8PROC_HANGUL_S_END 0xD7A4 + + +#define UTF8PROC_BOUNDCLASS_START 0 +#define UTF8PROC_BOUNDCLASS_OTHER 1 +#define UTF8PROC_BOUNDCLASS_CR 2 +#define UTF8PROC_BOUNDCLASS_LF 3 +#define UTF8PROC_BOUNDCLASS_CONTROL 4 +#define UTF8PROC_BOUNDCLASS_EXTEND 5 +#define UTF8PROC_BOUNDCLASS_L 6 +#define UTF8PROC_BOUNDCLASS_V 7 +#define UTF8PROC_BOUNDCLASS_T 8 +#define UTF8PROC_BOUNDCLASS_LV 9 +#define UTF8PROC_BOUNDCLASS_LVT 10 + + +const char *utf8proc_errmsg(ssize_t errcode) { + switch (errcode) { + case UTF8PROC_ERROR_NOMEM: + return "Memory for processing UTF-8 data could not be allocated."; + case UTF8PROC_ERROR_OVERFLOW: + return "UTF-8 string is too long to be processed."; + case UTF8PROC_ERROR_INVALIDUTF8: + return "Invalid UTF-8 string"; + case UTF8PROC_ERROR_NOTASSIGNED: + return "Unassigned Unicode code point found in UTF-8 string."; + case UTF8PROC_ERROR_INVALIDOPTS: + return "Invalid options for UTF-8 processing chosen."; + default: + return "An unknown error occured while processing UTF-8 data."; + } +} + +ssize_t utf8proc_iterate( + const uint8_t *str, ssize_t strlen, int32_t *dst +) { + int length; + int i; + int32_t uc = -1; + *dst = -1; + if (!strlen) return 0; + length = utf8proc_utf8class[str[0]]; + if (!length) return UTF8PROC_ERROR_INVALIDUTF8; + if (strlen >= 0 && length > strlen) return UTF8PROC_ERROR_INVALIDUTF8; + for (i=1; i= 0xD800 && uc < 0xE000) || + (uc >= 0xFDD0 && uc < 0xFDF0)) uc = -1; + break; + case 4: + uc = ((str[0] & 0x07) << 18) + ((str[1] & 0x3F) << 12) + + ((str[2] & 0x3F) << 6) + (str[3] & 0x3F); + if (uc < 0x10000 || uc >= 0x110000) uc = -1; + break; + } + if (uc < 0 || ((uc & 0xFFFF) >= 0xFFFE)) + return UTF8PROC_ERROR_INVALIDUTF8; + *dst = uc; + return length; +} + +bool utf8proc_codepoint_valid(int32_t uc) { + if (uc < 0 || uc >= 0x110000 || + ((uc & 0xFFFF) >= 0xFFFE) || (uc >= 0xD800 && uc < 0xE000) || + (uc >= 0xFDD0 && uc < 0xFDF0)) return false; + else return true; +} + +ssize_t utf8proc_encode_char(int32_t uc, uint8_t *dst) { + if (uc < 0x00) { + return 0; + } else if (uc < 0x80) { + dst[0] = uc; + return 1; + } else if (uc < 0x800) { + dst[0] = 0xC0 + (uc >> 6); + dst[1] = 0x80 + (uc & 0x3F); + return 2; + } else if (uc == 0xFFFF) { + dst[0] = 0xFF; + return 1; + } else if (uc == 0xFFFE) { + dst[0] = 0xFE; + return 1; + } else if (uc < 0x10000) { + dst[0] = 0xE0 + (uc >> 12); + dst[1] = 0x80 + ((uc >> 6) & 0x3F); + dst[2] = 0x80 + (uc & 0x3F); + return 3; + } else if (uc < 0x110000) { + dst[0] = 0xF0 + (uc >> 18); + dst[1] = 0x80 + ((uc >> 12) & 0x3F); + dst[2] = 0x80 + ((uc >> 6) & 0x3F); + dst[3] = 0x80 + (uc & 0x3F); + return 4; + } else return 0; +} + +const utf8proc_property_t *utf8proc_get_property(int32_t uc) { + // ASSERT: uc >= 0 && uc < 0x110000 + return utf8proc_properties + ( + utf8proc_stage2table[ + utf8proc_stage1table[uc >> 8] + (uc & 0xFF) + ] + ); +} + +#define utf8proc_decompose_lump(replacement_uc) \ + return utf8proc_decompose_char((replacement_uc), dst, bufsize, \ + options & ~UTF8PROC_LUMP, last_boundclass) + +ssize_t utf8proc_decompose_char(int32_t uc, int32_t *dst, ssize_t bufsize, + int options, int *last_boundclass) { + // ASSERT: uc >= 0 && uc < 0x110000 + const utf8proc_property_t *property; + utf8proc_propval_t category; + int32_t hangul_sindex; + property = utf8proc_get_property(uc); + category = property->category; + hangul_sindex = uc - UTF8PROC_HANGUL_SBASE; + if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { + if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT) { + int32_t hangul_tindex; + if (bufsize >= 1) { + dst[0] = UTF8PROC_HANGUL_LBASE + + hangul_sindex / UTF8PROC_HANGUL_NCOUNT; + if (bufsize >= 2) dst[1] = UTF8PROC_HANGUL_VBASE + + (hangul_sindex % UTF8PROC_HANGUL_NCOUNT) / UTF8PROC_HANGUL_TCOUNT; + } + hangul_tindex = hangul_sindex % UTF8PROC_HANGUL_TCOUNT; + if (!hangul_tindex) return 2; + if (bufsize >= 3) dst[2] = UTF8PROC_HANGUL_TBASE + hangul_tindex; + return 3; + } + } + if (options & UTF8PROC_REJECTNA) { + if (!category) return UTF8PROC_ERROR_NOTASSIGNED; + } + if (options & UTF8PROC_IGNORE) { + if (property->ignorable) return 0; + } + if (options & UTF8PROC_LUMP) { + if (category == UTF8PROC_CATEGORY_ZS) utf8proc_decompose_lump(0x0020); + if (uc == 0x2018 || uc == 0x2019 || uc == 0x02BC || uc == 0x02C8) + utf8proc_decompose_lump(0x0027); + if (category == UTF8PROC_CATEGORY_PD || uc == 0x2212) + utf8proc_decompose_lump(0x002D); + if (uc == 0x2044 || uc == 0x2215) utf8proc_decompose_lump(0x002F); + if (uc == 0x2236) utf8proc_decompose_lump(0x003A); + if (uc == 0x2039 || uc == 0x2329 || uc == 0x3008) + utf8proc_decompose_lump(0x003C); + if (uc == 0x203A || uc == 0x232A || uc == 0x3009) + utf8proc_decompose_lump(0x003E); + if (uc == 0x2216) utf8proc_decompose_lump(0x005C); + if (uc == 0x02C4 || uc == 0x02C6 || uc == 0x2038 || uc == 0x2303) + utf8proc_decompose_lump(0x005E); + if (category == UTF8PROC_CATEGORY_PC || uc == 0x02CD) + utf8proc_decompose_lump(0x005F); + if (uc == 0x02CB) utf8proc_decompose_lump(0x0060); + if (uc == 0x2223) utf8proc_decompose_lump(0x007C); + if (uc == 0x223C) utf8proc_decompose_lump(0x007E); + if ((options & UTF8PROC_NLF2LS) && (options & UTF8PROC_NLF2PS)) { + if (category == UTF8PROC_CATEGORY_ZL || + category == UTF8PROC_CATEGORY_ZP) + utf8proc_decompose_lump(0x000A); + } + } + if (options & UTF8PROC_STRIPMARK) { + if (category == UTF8PROC_CATEGORY_MN || + category == UTF8PROC_CATEGORY_MC || + category == UTF8PROC_CATEGORY_ME) return 0; + } + if (options & UTF8PROC_CASEFOLD) { + if (property->casefold_mapping) { + const int32_t *casefold_entry; + ssize_t written = 0; + for (casefold_entry = property->casefold_mapping; + *casefold_entry >= 0; casefold_entry++) { + written += utf8proc_decompose_char(*casefold_entry, dst+written, + (bufsize > written) ? (bufsize - written) : 0, options, + last_boundclass); + if (written < 0) return UTF8PROC_ERROR_OVERFLOW; + } + return written; + } + } + if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) { + if (property->decomp_mapping && + (!property->decomp_type || (options & UTF8PROC_COMPAT))) { + const int32_t *decomp_entry; + ssize_t written = 0; + for (decomp_entry = property->decomp_mapping; + *decomp_entry >= 0; decomp_entry++) { + written += utf8proc_decompose_char(*decomp_entry, dst+written, + (bufsize > written) ? (bufsize - written) : 0, options, + last_boundclass); + if (written < 0) return UTF8PROC_ERROR_OVERFLOW; + } + return written; + } + } + if (options & UTF8PROC_CHARBOUND) { + bool boundary; + int tbc, lbc; + tbc = + (uc == 0x000D) ? UTF8PROC_BOUNDCLASS_CR : + (uc == 0x000A) ? UTF8PROC_BOUNDCLASS_LF : + ((category == UTF8PROC_CATEGORY_ZL || + category == UTF8PROC_CATEGORY_ZP || + category == UTF8PROC_CATEGORY_CC || + category == UTF8PROC_CATEGORY_CF) && + !(uc == 0x200C || uc == 0x200D)) ? UTF8PROC_BOUNDCLASS_CONTROL : + property->extend ? UTF8PROC_BOUNDCLASS_EXTEND : + ((uc >= UTF8PROC_HANGUL_L_START && uc < UTF8PROC_HANGUL_L_END) || + uc == UTF8PROC_HANGUL_L_FILLER) ? UTF8PROC_BOUNDCLASS_L : + (uc >= UTF8PROC_HANGUL_V_START && uc < UTF8PROC_HANGUL_V_END) ? + UTF8PROC_BOUNDCLASS_V : + (uc >= UTF8PROC_HANGUL_T_START && uc < UTF8PROC_HANGUL_T_END) ? + UTF8PROC_BOUNDCLASS_T : + (uc >= UTF8PROC_HANGUL_S_START && uc < UTF8PROC_HANGUL_S_END) ? ( + ((uc-UTF8PROC_HANGUL_SBASE) % UTF8PROC_HANGUL_TCOUNT == 0) ? + UTF8PROC_BOUNDCLASS_LV : UTF8PROC_BOUNDCLASS_LVT + ) : + UTF8PROC_BOUNDCLASS_OTHER; + lbc = *last_boundclass; + boundary = + (tbc == UTF8PROC_BOUNDCLASS_EXTEND) ? false : + (lbc == UTF8PROC_BOUNDCLASS_START) ? true : + (lbc == UTF8PROC_BOUNDCLASS_CR && + tbc == UTF8PROC_BOUNDCLASS_LF) ? false : + (lbc == UTF8PROC_BOUNDCLASS_CONTROL) ? true : + (tbc == UTF8PROC_BOUNDCLASS_CONTROL) ? true : + (lbc == UTF8PROC_BOUNDCLASS_L && + (tbc == UTF8PROC_BOUNDCLASS_L || + tbc == UTF8PROC_BOUNDCLASS_V || + tbc == UTF8PROC_BOUNDCLASS_LV || + tbc == UTF8PROC_BOUNDCLASS_LVT)) ? false : + ((lbc == UTF8PROC_BOUNDCLASS_LV || + lbc == UTF8PROC_BOUNDCLASS_V) && + (tbc == UTF8PROC_BOUNDCLASS_V || + tbc == UTF8PROC_BOUNDCLASS_T)) ? false : + ((lbc == UTF8PROC_BOUNDCLASS_LVT || + lbc == UTF8PROC_BOUNDCLASS_T) && + tbc == UTF8PROC_BOUNDCLASS_T) ? false : + true; + *last_boundclass = tbc; + if (boundary) { + if (bufsize >= 1) dst[0] = 0xFFFF; + if (bufsize >= 2) dst[1] = uc; + return 2; + } + } + if (bufsize >= 1) *dst = uc; + return 1; +} + +ssize_t utf8proc_decompose( + const uint8_t *str, ssize_t strlen, + int32_t *buffer, ssize_t bufsize, int options +) { + // strlen will be ignored, if UTF8PROC_NULLTERM is set in options + ssize_t wpos = 0; + if ((options & UTF8PROC_COMPOSE) && (options & UTF8PROC_DECOMPOSE)) + return UTF8PROC_ERROR_INVALIDOPTS; + if ((options & UTF8PROC_STRIPMARK) && + !(options & UTF8PROC_COMPOSE) && !(options & UTF8PROC_DECOMPOSE)) + return UTF8PROC_ERROR_INVALIDOPTS; + { + int32_t uc; + ssize_t rpos = 0; + ssize_t decomp_result; + int boundclass = UTF8PROC_BOUNDCLASS_START; + while (1) { + if (options & UTF8PROC_NULLTERM) { + rpos += utf8proc_iterate(str + rpos, -1, &uc); + // checking of return value is not neccessary, + // as 'uc' is < 0 in case of error + if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; + if (rpos < 0) return UTF8PROC_ERROR_OVERFLOW; + if (uc == 0) break; + } else { + if (rpos >= strlen) break; + rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc); + if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8; + } + decomp_result = utf8proc_decompose_char( + uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options, + &boundclass + ); + if (decomp_result < 0) return decomp_result; + wpos += decomp_result; + // prohibiting integer overflows due to too long strings: + if (wpos < 0 || wpos > (ssize_t)(SSIZE_MAX/sizeof(int32_t)/2)) + return UTF8PROC_ERROR_OVERFLOW; + } + } + if ((options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) && bufsize >= wpos) { + ssize_t pos = 0; + while (pos < wpos-1) { + int32_t uc1, uc2; + const utf8proc_property_t *property1, *property2; + uc1 = buffer[pos]; + uc2 = buffer[pos+1]; + property1 = utf8proc_get_property(uc1); + property2 = utf8proc_get_property(uc2); + if (property1->combining_class > property2->combining_class && + property2->combining_class > 0) { + buffer[pos] = uc2; + buffer[pos+1] = uc1; + if (pos > 0) pos--; else pos++; + } else { + pos++; + } + } + } + return wpos; +} + +ssize_t utf8proc_reencode(int32_t *buffer, ssize_t length, int options) { + // UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored + // ASSERT: 'buffer' has one spare byte of free space at the end! + if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) { + ssize_t rpos; + ssize_t wpos = 0; + int32_t uc; + for (rpos = 0; rpos < length; rpos++) { + uc = buffer[rpos]; + if (uc == 0x000D && rpos < length-1 && buffer[rpos+1] == 0x000A) rpos++; + if (uc == 0x000A || uc == 0x000D || uc == 0x0085 || + ((options & UTF8PROC_STRIPCC) && (uc == 0x000B || uc == 0x000C))) { + if (options & UTF8PROC_NLF2LS) { + if (options & UTF8PROC_NLF2PS) { + buffer[wpos++] = 0x000A; + } else { + buffer[wpos++] = 0x2028; + } + } else { + if (options & UTF8PROC_NLF2PS) { + buffer[wpos++] = 0x2029; + } else { + buffer[wpos++] = 0x0020; + } + } + } else if ((options & UTF8PROC_STRIPCC) && + (uc < 0x0020 || (uc >= 0x007F && uc < 0x00A0))) { + if (uc == 0x0009) buffer[wpos++] = 0x0020; + } else { + buffer[wpos++] = uc; + } + } + length = wpos; + } + if (options & UTF8PROC_COMPOSE) { + int32_t *starter = NULL; + int32_t current_char; + const utf8proc_property_t *starter_property = NULL, *current_property; + utf8proc_propval_t max_combining_class = -1; + ssize_t rpos; + ssize_t wpos = 0; + int32_t composition; + for (rpos = 0; rpos < length; rpos++) { + current_char = buffer[rpos]; + current_property = utf8proc_get_property(current_char); + if (starter && current_property->combining_class > max_combining_class) { + // combination perhaps possible + int32_t hangul_lindex; + int32_t hangul_sindex; + hangul_lindex = *starter - UTF8PROC_HANGUL_LBASE; + if (hangul_lindex >= 0 && hangul_lindex < UTF8PROC_HANGUL_LCOUNT) { + int32_t hangul_vindex; + hangul_vindex = current_char - UTF8PROC_HANGUL_VBASE; + if (hangul_vindex >= 0 && hangul_vindex < UTF8PROC_HANGUL_VCOUNT) { + *starter = UTF8PROC_HANGUL_SBASE + + (hangul_lindex * UTF8PROC_HANGUL_VCOUNT + hangul_vindex) * + UTF8PROC_HANGUL_TCOUNT; + starter_property = NULL; + continue; + } + } + hangul_sindex = *starter - UTF8PROC_HANGUL_SBASE; + if (hangul_sindex >= 0 && hangul_sindex < UTF8PROC_HANGUL_SCOUNT && + (hangul_sindex % UTF8PROC_HANGUL_TCOUNT) == 0) { + int32_t hangul_tindex; + hangul_tindex = current_char - UTF8PROC_HANGUL_TBASE; + if (hangul_tindex >= 0 && hangul_tindex < UTF8PROC_HANGUL_TCOUNT) { + *starter += hangul_tindex; + starter_property = NULL; + continue; + } + } + if (!starter_property) { + starter_property = utf8proc_get_property(*starter); + } + if (starter_property->comb1st_index >= 0 && + current_property->comb2nd_index >= 0) { + composition = utf8proc_combinations[ + starter_property->comb1st_index + + current_property->comb2nd_index + ]; + if (composition >= 0 && (!(options & UTF8PROC_STABLE) || + !(utf8proc_get_property(composition)->comp_exclusion))) { + *starter = composition; + starter_property = NULL; + continue; + } + } + } + buffer[wpos] = current_char; + if (current_property->combining_class) { + if (current_property->combining_class > max_combining_class) { + max_combining_class = current_property->combining_class; + } + } else { + starter = buffer + wpos; + starter_property = NULL; + max_combining_class = -1; + } + wpos++; + } + length = wpos; + } + { + ssize_t rpos, wpos = 0; + int32_t uc; + for (rpos = 0; rpos < length; rpos++) { + uc = buffer[rpos]; + wpos += utf8proc_encode_char(uc, ((uint8_t *)buffer) + wpos); + } + ((uint8_t *)buffer)[wpos] = 0; + return wpos; + } +} + +ssize_t utf8proc_map( + const uint8_t *str, ssize_t strlen, uint8_t **dstptr, int options +) { + int32_t *buffer; + ssize_t result; + *dstptr = NULL; + result = utf8proc_decompose(str, strlen, NULL, 0, options); + if (result < 0) return result; + buffer = malloc(result * sizeof(int32_t) + 1); + if (!buffer) return UTF8PROC_ERROR_NOMEM; + result = utf8proc_decompose(str, strlen, buffer, result, options); + if (result < 0) { + free(buffer); + return result; + } + result = utf8proc_reencode(buffer, result, options); + if (result < 0) { + free(buffer); + return result; + } + { + int32_t *newptr; + newptr = realloc(buffer, result+1); + if (newptr) buffer = newptr; + } + *dstptr = (uint8_t *)buffer; + return result; +} + +uint8_t *utf8proc_NFD(const uint8_t *str) { + uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_DECOMPOSE); + return retval; +} + +uint8_t *utf8proc_NFC(const uint8_t *str) { + uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_COMPOSE); + return retval; +} + +uint8_t *utf8proc_NFKD(const uint8_t *str) { + uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT); + return retval; +} + +uint8_t *utf8proc_NFKC(const uint8_t *str) { + uint8_t *retval; + utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE | + UTF8PROC_COMPOSE | UTF8PROC_COMPAT); + return retval; +} + diff --git a/server/utf8proc.h b/server/utf8proc.h new file mode 100644 index 0000000..2fd4f17 --- /dev/null +++ b/server/utf8proc.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2006-2007 Jan Behrens, FlexiGuided GmbH, Berlin + * + * 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. + */ + + +/* + * File name: utf8proc.h + * Version: 1.1.1 + * Last changed: 2007-07-22 + * + * Description: + * Header files for libutf8proc, which is a mapping tool for UTF-8 strings + * with following features: + * - decomposing and composing of strings + * - replacing compatibility characters with their equivalents + * - stripping of "default ignorable characters" + * like SOFT-HYPHEN or ZERO-WIDTH-SPACE + * - folding of certain characters for string comparison + * (e.g. HYPHEN U+2010 and MINUS U+2212 to ASCII "-") + * (see "LUMP" option) + * - optional rejection of strings containing non-assigned code points + * - stripping of control characters + * - stripping of character marks (accents, etc.) + * - transformation of LF, CRLF, CR and NEL to line-feed (LF) + * or to the unicode chararacters for paragraph separation (PS) + * or line separation (LS). + * - unicode case folding (for case insensitive string comparisons) + * - rejection of illegal UTF-8 data + * (i.e. UTF-8 encoded UTF-16 surrogates) + * - support for korean hangul characters + * Unicode Version 5.0.0 is supported. + */ + + +#ifndef UTF8PROC_H +#define UTF8PROC_H + + +#include +#ifdef HAVE_STDBOOL_H +#include +#else +typedef enum {false = 0, true = 1} bool; +#endif +#include +#include +#include + +#ifndef SSIZE_MAX +#define SSIZE_MAX (SIZE_MAX/2) +#endif + +#define UTF8PROC_NULLTERM (1<<0) +#define UTF8PROC_STABLE (1<<1) +#define UTF8PROC_COMPAT (1<<2) +#define UTF8PROC_COMPOSE (1<<3) +#define UTF8PROC_DECOMPOSE (1<<4) +#define UTF8PROC_IGNORE (1<<5) +#define UTF8PROC_REJECTNA (1<<6) +#define UTF8PROC_NLF2LS (1<<7) +#define UTF8PROC_NLF2PS (1<<8) +#define UTF8PROC_NLF2LF (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS) +#define UTF8PROC_STRIPCC (1<<9) +#define UTF8PROC_CASEFOLD (1<<10) +#define UTF8PROC_CHARBOUND (1<<11) +#define UTF8PROC_LUMP (1<<12) +#define UTF8PROC_STRIPMARK (1<<13) +/* + * Flags being regarded by several functions in the library: + * NULLTERM: The given UTF-8 input is NULL terminated. + * STABLE: Unicode Versioning Stability has to be respected. + * COMPAT: Compatiblity decomposition + * (i.e. formatting information is lost) + * COMPOSE: Return a result with composed characters. + * DECOMPOSE: Return a result with decomposed characters. + * IGNORE: Strip "default ignorable characters" + * REJECTNA: Return an error, if the input contains unassigned + * code points. + * NLF2LS: Indicating that NLF-sequences (LF, CRLF, CR, NEL) are + * representing a line break, and should be converted to the + * unicode character for line separation (LS). + * NLF2PS: Indicating that NLF-sequences are representing a paragraph + * break, and should be converted to the unicode character for + * paragraph separation (PS). + * NLF2LF: Indicating that the meaning of NLF-sequences is unknown. + * STRIPCC: Strips and/or convers control characters. + * NLF-sequences are transformed into space, except if one of + * the NLF2LS/PS/LF options is given. + * HorizontalTab (HT) and FormFeed (FF) are treated as a + * NLF-sequence in this case. + * All other control characters are simply removed. + * CASEFOLD: Performs unicode case folding, to be able to do a + * case-insensitive string comparison. + * CHARBOUND: Inserts 0xFF bytes at the beginning of each sequence which + * is representing a single grapheme cluster (see UAX#29). + * LUMP: Lumps certain characters together + * (e.g. HYPHEN U+2010 and MINUS U+2212 to ASCII "-"). + * (See lump.txt for details.) + * If NLF2LF is set, this includes a transformation of + * paragraph and line separators to ASCII line-feed (LF). + * STRIPMARK: Strips all character markings + * (non-spacing, spacing and enclosing) (i.e. accents) + * NOTE: this option works only with COMPOSE or DECOMPOSE + */ + +#define UTF8PROC_ERROR_NOMEM -1 +#define UTF8PROC_ERROR_OVERFLOW -2 +#define UTF8PROC_ERROR_INVALIDUTF8 -3 +#define UTF8PROC_ERROR_NOTASSIGNED -4 +#define UTF8PROC_ERROR_INVALIDOPTS -5 +/* + * Error codes being returned by almost all functions: + * ERROR_NOMEM: Memory could not be allocated. + * ERROR_OVERFLOW: The given string is too long to be processed. + * ERROR_INVALIDUTF8: The given string is not a legal UTF-8 string. + * ERROR_NOTASSIGNED: The REJECTNA flag was set, + * and an unassigned code point was found. + * ERROR_INVALIDOPTS: Invalid options have been used. + */ + +typedef int16_t utf8proc_propval_t; +typedef struct utf8proc_property_struct { + utf8proc_propval_t category; + utf8proc_propval_t combining_class; + utf8proc_propval_t bidi_class; + utf8proc_propval_t decomp_type; + const int32_t *decomp_mapping; + unsigned bidi_mirrored:1; + int32_t uppercase_mapping; + int32_t lowercase_mapping; + int32_t titlecase_mapping; + int32_t comb1st_index; + int32_t comb2nd_index; + unsigned comp_exclusion:1; + unsigned ignorable:1; + unsigned control_boundary:1; + unsigned extend:1; + const int32_t *casefold_mapping; +} utf8proc_property_t; + +#define UTF8PROC_CATEGORY_LU 1 +#define UTF8PROC_CATEGORY_LL 2 +#define UTF8PROC_CATEGORY_LT 3 +#define UTF8PROC_CATEGORY_LM 4 +#define UTF8PROC_CATEGORY_LO 5 +#define UTF8PROC_CATEGORY_MN 6 +#define UTF8PROC_CATEGORY_MC 7 +#define UTF8PROC_CATEGORY_ME 8 +#define UTF8PROC_CATEGORY_ND 9 +#define UTF8PROC_CATEGORY_NL 10 +#define UTF8PROC_CATEGORY_NO 11 +#define UTF8PROC_CATEGORY_PC 12 +#define UTF8PROC_CATEGORY_PD 13 +#define UTF8PROC_CATEGORY_PS 14 +#define UTF8PROC_CATEGORY_PE 15 +#define UTF8PROC_CATEGORY_PI 16 +#define UTF8PROC_CATEGORY_PF 17 +#define UTF8PROC_CATEGORY_PO 18 +#define UTF8PROC_CATEGORY_SM 19 +#define UTF8PROC_CATEGORY_SC 20 +#define UTF8PROC_CATEGORY_SK 21 +#define UTF8PROC_CATEGORY_SO 22 +#define UTF8PROC_CATEGORY_ZS 23 +#define UTF8PROC_CATEGORY_ZL 24 +#define UTF8PROC_CATEGORY_ZP 25 +#define UTF8PROC_CATEGORY_CC 26 +#define UTF8PROC_CATEGORY_CF 27 +#define UTF8PROC_CATEGORY_CS 28 +#define UTF8PROC_CATEGORY_CO 29 +#define UTF8PROC_CATEGORY_CN 30 +#define UTF8PROC_BIDI_CLASS_L 1 +#define UTF8PROC_BIDI_CLASS_LRE 2 +#define UTF8PROC_BIDI_CLASS_LRO 3 +#define UTF8PROC_BIDI_CLASS_R 4 +#define UTF8PROC_BIDI_CLASS_AL 5 +#define UTF8PROC_BIDI_CLASS_RLE 6 +#define UTF8PROC_BIDI_CLASS_RLO 7 +#define UTF8PROC_BIDI_CLASS_PDF 8 +#define UTF8PROC_BIDI_CLASS_EN 9 +#define UTF8PROC_BIDI_CLASS_ES 10 +#define UTF8PROC_BIDI_CLASS_ET 11 +#define UTF8PROC_BIDI_CLASS_AN 12 +#define UTF8PROC_BIDI_CLASS_CS 13 +#define UTF8PROC_BIDI_CLASS_NSM 14 +#define UTF8PROC_BIDI_CLASS_BN 15 +#define UTF8PROC_BIDI_CLASS_B 16 +#define UTF8PROC_BIDI_CLASS_S 17 +#define UTF8PROC_BIDI_CLASS_WS 18 +#define UTF8PROC_BIDI_CLASS_ON 19 +#define UTF8PROC_DECOMP_TYPE_FONT 1 +#define UTF8PROC_DECOMP_TYPE_NOBREAK 2 +#define UTF8PROC_DECOMP_TYPE_INITIAL 3 +#define UTF8PROC_DECOMP_TYPE_MEDIAL 4 +#define UTF8PROC_DECOMP_TYPE_FINAL 5 +#define UTF8PROC_DECOMP_TYPE_ISOLATED 6 +#define UTF8PROC_DECOMP_TYPE_CIRCLE 7 +#define UTF8PROC_DECOMP_TYPE_SUPER 8 +#define UTF8PROC_DECOMP_TYPE_SUB 9 +#define UTF8PROC_DECOMP_TYPE_VERTICAL 10 +#define UTF8PROC_DECOMP_TYPE_WIDE 11 +#define UTF8PROC_DECOMP_TYPE_NARROW 12 +#define UTF8PROC_DECOMP_TYPE_SMALL 13 +#define UTF8PROC_DECOMP_TYPE_SQUARE 14 +#define UTF8PROC_DECOMP_TYPE_FRACTION 15 +#define UTF8PROC_DECOMP_TYPE_COMPAT 16 + +extern const int8_t utf8proc_utf8class[256]; + +const char *utf8proc_errmsg(ssize_t errcode); +/* + * Returns a static error string for the given error code. + */ + +ssize_t utf8proc_iterate(const uint8_t *str, ssize_t strlen, int32_t *dst); +/* + * Reads a single char from the UTF-8 sequence being pointed to by 'str'. + * The maximum number of bytes read is 'strlen', unless 'strlen' is + * negative. + * If a valid unicode char could be read, it is stored in the variable + * being pointed to by 'dst', otherwise that variable will be set to -1. + * In case of success the number of bytes read is returned, otherwise a + * negative error code is returned. + */ + +bool utf8proc_codepoint_valid(int32_t uc); +/* + * Returns 1, if the given unicode code-point is valid, otherwise 0. + */ + +ssize_t utf8proc_encode_char(int32_t uc, uint8_t *dst); +/* + * Encodes the unicode char with the code point 'uc' as an UTF-8 string in + * the byte array being pointed to by 'dst'. This array has to be at least + * 4 bytes long. + * In case of success the number of bytes written is returned, + * otherwise 0. + * This function does not check if 'uc' is a valid unicode code point. + */ + +const utf8proc_property_t *utf8proc_get_property(int32_t uc); +/* + * Returns a pointer to a (constant) struct containing information about + * the unicode char with the given code point 'uc'. + * If the character is not existent a pointer to a special struct is + * returned, where 'category' is a NULL pointer. + * WARNING: The parameter 'uc' has to be in the range of 0x0000 to + * 0x10FFFF, otherwise the program might crash! + */ + +ssize_t utf8proc_decompose_char( + int32_t uc, int32_t *dst, ssize_t bufsize, + int options, int *last_boundclass +); +/* + * Writes a decomposition of the unicode char 'uc' into the array being + * pointed to by 'dst'. + * Following flags in the 'options' field are regarded: + * REJECTNA: an unassigned unicode code point leads to an error + * IGNORE: "default ignorable" chars are stripped + * CASEFOLD: unicode casefolding is applied + * COMPAT: replace certain characters with their + * compatibility decomposition + * CHARBOUND: Inserts 0xFF bytes before each grapheme cluster + * LUMP: lumps certain different characters together + * STRIPMARK: removes all character marks + * The pointer 'last_boundclass' has to point to an integer variable which + * is storing the last character boundary class, if the CHARBOUND option + * is used. + * In case of success the number of chars written is returned, + * in case of an error, a negative error code is returned. + * If the number of written chars would be bigger than 'bufsize', + * the buffer (up to 'bufsize') has inpredictable data, and the needed + * buffer size is returned. + * WARNING: The parameter 'uc' has to be in the range of 0x0000 to + * 0x10FFFF, otherwise the program might crash! + */ + +ssize_t utf8proc_decompose( + const uint8_t *str, ssize_t strlen, + int32_t *buffer, ssize_t bufsize, int options +); +/* + * Does the same as 'utf8proc_decompose_char', but acts on a whole UTF-8 + * string, and orders the decomposed sequences correctly. + * If the NULLTERM flag in 'options' is set, processing will be stopped, + * when a NULL byte is encounted, otherwise 'strlen' bytes are processed. + * The result in form of unicode code points is written into the buffer + * being pointed to by 'buffer', having the length of 'bufsize' entries. + * In case of success the number of chars written is returned, + * in case of an error, a negative error code is returned. + * If the number of written chars would be bigger than 'bufsize', + * the buffer (up to 'bufsize') has inpredictable data, and the needed + * buffer size is returned. + */ + +ssize_t utf8proc_reencode(int32_t *buffer, ssize_t length, int options); +/* + * Reencodes the sequence of unicode characters given by the pointer + * 'buffer' and 'length' as UTF-8. + * The result is stored in the same memory area where the data is read. + * Following flags in the 'options' field are regarded: + * NLF2LS: converts LF, CRLF, CR and NEL into LS + * NLF2PS: converts LF, CRLF, CR and NEL into PS + * NLF2LF: converts LF, CRLF, CR and NEL into LF + * STRIPCC: strips or converts all non-affected control characters + * COMPOSE: tries to combine decomposed characters into composite + * characters + * STABLE: prohibits combining characters which would violate + * the unicode versioning stability + * In case of success the length of the resulting UTF-8 string is + * returned, otherwise a negative error code is returned. + * WARNING: The amount of free space being pointed to by 'buffer', has to + * exceed the amount of the input data by one byte, and the + * entries of the array pointed to by 'str' have to be in the + * range of 0x0000 to 0x10FFFF, otherwise the program might + * crash! + */ + +ssize_t utf8proc_map( + const uint8_t *str, ssize_t strlen, uint8_t **dstptr, int options +); +/* + * Maps the given UTF-8 string being pointed to by 'str' to a new UTF-8 + * string, which is allocated dynamically, and afterwards pointed to by + * the pointer being pointed to by 'dstptr'. + * If the NULLTERM flag in the 'options' field is set, the length is + * determined by a NULL terminator, otherwise the parameter 'strlen' is + * evaluated to determine the string length, but in any case the result + * will be NULL terminated (though it might contain NULL characters + * before). Other flags in the 'options' field are passed to the functions + * defined above, and regarded as described. + * In case of success the length of the new string is returned, + * otherwise a negative error code is returned. + * NOTICE: The memory of the new UTF-8 string will have been allocated with + * 'malloc', and has theirfore to be freed with 'free'. + */ + +uint8_t *utf8proc_NFD(const uint8_t *str); +uint8_t *utf8proc_NFC(const uint8_t *str); +uint8_t *utf8proc_NFKD(const uint8_t *str); +uint8_t *utf8proc_NFKC(const uint8_t *str); +/* + * Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC + * normalized version of the null-terminated string 'str'. + */ + + +#endif + diff --git a/server/utf8proc_data.c b/server/utf8proc_data.c new file mode 100644 index 0000000..1426b76 --- /dev/null +++ b/server/utf8proc_data.c @@ -0,0 +1,13383 @@ +/* + * This file contains derived data from a modified version of the + * Unicode data files. + * + * The original data files are available at + * http://www.unicode.org/Public/UNIDATA/ + * + * + * COPYRIGHT AND PERMISSION NOTICE + * + * Copyright (c) 1991-2007 Unicode, Inc. All rights reserved. Distributed + * under the Terms of Use in http://www.unicode.org/copyright.html. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of the Unicode data files and any associated documentation (the "Data + * Files") or Unicode software and any associated documentation (the + * "Software") to deal in the Data Files or Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, and/or sell copies of the Data Files or Software, and + * to permit persons to whom the Data Files or Software are furnished to do + * so, provided that (a) the above copyright notice(s) and this permission + * notice appear with all copies of the Data Files or Software, (b) both the + * above copyright notice(s) and this permission notice appear in associated + * documentation, and (c) there is clear notice in each modified Data File or + * in the Software as well as in the documentation associated with the Data + * File(s) or Software that the data or software has been modified. + * + * THE DATA FILES AND SOFTWARE ARE 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 OF + * THIRD PARTY RIGHTS. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR HOLDERS + * INCLUDED IN THIS NOTICE BE LIABLE FOR ANY CLAIM, OR ANY SPECIAL INDIRECT OR + * CONSEQUENTIAL DAMAGES, OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THE DATA FILES OR SOFTWARE. + * + * Except as contained in this notice, the name of a copyright holder shall + * not be used in advertising or otherwise to promote the sale, use or other + * dealings in these Data Files or Software without prior written + * authorization of the copyright holder. + */ + + +const int32_t utf8proc_sequences[] = { + 97, -1, 98, -1, 99, -1, 100, + -1, 101, -1, 102, -1, 103, -1, 104, + -1, 105, -1, 106, -1, 107, -1, 108, + -1, 109, -1, 110, -1, 111, -1, 112, + -1, 113, -1, 114, -1, 115, -1, 116, + -1, 117, -1, 118, -1, 119, -1, 120, + -1, 121, -1, 122, -1, 32, -1, 32, + 776, -1, 32, 772, -1, 50, -1, 51, + -1, 32, 769, -1, 956, -1, 32, 807, + -1, 49, -1, 49, 8260, 52, -1, 49, + 8260, 50, -1, 51, 8260, 52, -1, 65, + 768, -1, 224, -1, 65, 769, -1, 225, + -1, 65, 770, -1, 226, -1, 65, 771, + -1, 227, -1, 65, 776, -1, 228, -1, + 65, 778, -1, 229, -1, 230, -1, 67, + 807, -1, 231, -1, 69, 768, -1, 232, + -1, 69, 769, -1, 233, -1, 69, 770, + -1, 234, -1, 69, 776, -1, 235, -1, + 73, 768, -1, 236, -1, 73, 769, -1, + 237, -1, 73, 770, -1, 238, -1, 73, + 776, -1, 239, -1, 240, -1, 78, 771, + -1, 241, -1, 79, 768, -1, 242, -1, + 79, 769, -1, 243, -1, 79, 770, -1, + 244, -1, 79, 771, -1, 245, -1, 79, + 776, -1, 246, -1, 248, -1, 85, 768, + -1, 249, -1, 85, 769, -1, 250, -1, + 85, 770, -1, 251, -1, 85, 776, -1, + 252, -1, 89, 769, -1, 253, -1, 254, + -1, 115, 115, -1, 97, 768, -1, 97, + 769, -1, 97, 770, -1, 97, 771, -1, + 97, 776, -1, 97, 778, -1, 99, 807, + -1, 101, 768, -1, 101, 769, -1, 101, + 770, -1, 101, 776, -1, 105, 768, -1, + 105, 769, -1, 105, 770, -1, 105, 776, + -1, 110, 771, -1, 111, 768, -1, 111, + 769, -1, 111, 770, -1, 111, 771, -1, + 111, 776, -1, 117, 768, -1, 117, 769, + -1, 117, 770, -1, 117, 776, -1, 121, + 769, -1, 121, 776, -1, 65, 772, -1, + 257, -1, 97, 772, -1, 65, 774, -1, + 259, -1, 97, 774, -1, 65, 808, -1, + 261, -1, 97, 808, -1, 67, 769, -1, + 263, -1, 99, 769, -1, 67, 770, -1, + 265, -1, 99, 770, -1, 67, 775, -1, + 267, -1, 99, 775, -1, 67, 780, -1, + 269, -1, 99, 780, -1, 68, 780, -1, + 271, -1, 100, 780, -1, 273, -1, 69, + 772, -1, 275, -1, 101, 772, -1, 69, + 774, -1, 277, -1, 101, 774, -1, 69, + 775, -1, 279, -1, 101, 775, -1, 69, + 808, -1, 281, -1, 101, 808, -1, 69, + 780, -1, 283, -1, 101, 780, -1, 71, + 770, -1, 285, -1, 103, 770, -1, 71, + 774, -1, 287, -1, 103, 774, -1, 71, + 775, -1, 289, -1, 103, 775, -1, 71, + 807, -1, 291, -1, 103, 807, -1, 72, + 770, -1, 293, -1, 104, 770, -1, 295, + -1, 73, 771, -1, 297, -1, 105, 771, + -1, 73, 772, -1, 299, -1, 105, 772, + -1, 73, 774, -1, 301, -1, 105, 774, + -1, 73, 808, -1, 303, -1, 105, 808, + -1, 73, 775, -1, 105, 775, -1, 73, + 74, -1, 307, -1, 105, 106, -1, 74, + 770, -1, 309, -1, 106, 770, -1, 75, + 807, -1, 311, -1, 107, 807, -1, 76, + 769, -1, 314, -1, 108, 769, -1, 76, + 807, -1, 316, -1, 108, 807, -1, 76, + 780, -1, 318, -1, 108, 780, -1, 76, + 183, -1, 320, -1, 108, 183, -1, 322, + -1, 78, 769, -1, 324, -1, 110, 769, + -1, 78, 807, -1, 326, -1, 110, 807, + -1, 78, 780, -1, 328, -1, 110, 780, + -1, 700, 110, -1, 331, -1, 79, 772, + -1, 333, -1, 111, 772, -1, 79, 774, + -1, 335, -1, 111, 774, -1, 79, 779, + -1, 337, -1, 111, 779, -1, 339, -1, + 82, 769, -1, 341, -1, 114, 769, -1, + 82, 807, -1, 343, -1, 114, 807, -1, + 82, 780, -1, 345, -1, 114, 780, -1, + 83, 769, -1, 347, -1, 115, 769, -1, + 83, 770, -1, 349, -1, 115, 770, -1, + 83, 807, -1, 351, -1, 115, 807, -1, + 83, 780, -1, 353, -1, 115, 780, -1, + 84, 807, -1, 355, -1, 116, 807, -1, + 84, 780, -1, 357, -1, 116, 780, -1, + 359, -1, 85, 771, -1, 361, -1, 117, + 771, -1, 85, 772, -1, 363, -1, 117, + 772, -1, 85, 774, -1, 365, -1, 117, + 774, -1, 85, 778, -1, 367, -1, 117, + 778, -1, 85, 779, -1, 369, -1, 117, + 779, -1, 85, 808, -1, 371, -1, 117, + 808, -1, 87, 770, -1, 373, -1, 119, + 770, -1, 89, 770, -1, 375, -1, 121, + 770, -1, 89, 776, -1, 255, -1, 90, + 769, -1, 378, -1, 122, 769, -1, 90, + 775, -1, 380, -1, 122, 775, -1, 90, + 780, -1, 382, -1, 122, 780, -1, 595, + -1, 387, -1, 389, -1, 596, -1, 392, + -1, 598, -1, 599, -1, 396, -1, 477, + -1, 601, -1, 603, -1, 402, -1, 608, + -1, 611, -1, 617, -1, 616, -1, 409, + -1, 623, -1, 626, -1, 629, -1, 79, + 795, -1, 417, -1, 111, 795, -1, 419, + -1, 421, -1, 640, -1, 424, -1, 643, + -1, 429, -1, 648, -1, 85, 795, -1, + 432, -1, 117, 795, -1, 650, -1, 651, + -1, 436, -1, 438, -1, 658, -1, 441, + -1, 445, -1, 68, 381, -1, 454, -1, + 68, 382, -1, 100, 382, -1, 76, 74, + -1, 457, -1, 76, 106, -1, 108, 106, + -1, 78, 74, -1, 460, -1, 78, 106, + -1, 110, 106, -1, 65, 780, -1, 462, + -1, 97, 780, -1, 73, 780, -1, 464, + -1, 105, 780, -1, 79, 780, -1, 466, + -1, 111, 780, -1, 85, 780, -1, 468, + -1, 117, 780, -1, 220, 772, -1, 470, + -1, 252, 772, -1, 220, 769, -1, 472, + -1, 252, 769, -1, 220, 780, -1, 474, + -1, 252, 780, -1, 220, 768, -1, 476, + -1, 252, 768, -1, 196, 772, -1, 479, + -1, 228, 772, -1, 550, 772, -1, 481, + -1, 551, 772, -1, 198, 772, -1, 483, + -1, 230, 772, -1, 485, -1, 71, 780, + -1, 487, -1, 103, 780, -1, 75, 780, + -1, 489, -1, 107, 780, -1, 79, 808, + -1, 491, -1, 111, 808, -1, 490, 772, + -1, 493, -1, 491, 772, -1, 439, 780, + -1, 495, -1, 658, 780, -1, 106, 780, + -1, 68, 90, -1, 499, -1, 68, 122, + -1, 100, 122, -1, 71, 769, -1, 501, + -1, 103, 769, -1, 405, -1, 447, -1, + 78, 768, -1, 505, -1, 110, 768, -1, + 197, 769, -1, 507, -1, 229, 769, -1, + 198, 769, -1, 509, -1, 230, 769, -1, + 216, 769, -1, 511, -1, 248, 769, -1, + 65, 783, -1, 513, -1, 97, 783, -1, + 65, 785, -1, 515, -1, 97, 785, -1, + 69, 783, -1, 517, -1, 101, 783, -1, + 69, 785, -1, 519, -1, 101, 785, -1, + 73, 783, -1, 521, -1, 105, 783, -1, + 73, 785, -1, 523, -1, 105, 785, -1, + 79, 783, -1, 525, -1, 111, 783, -1, + 79, 785, -1, 527, -1, 111, 785, -1, + 82, 783, -1, 529, -1, 114, 783, -1, + 82, 785, -1, 531, -1, 114, 785, -1, + 85, 783, -1, 533, -1, 117, 783, -1, + 85, 785, -1, 535, -1, 117, 785, -1, + 83, 806, -1, 537, -1, 115, 806, -1, + 84, 806, -1, 539, -1, 116, 806, -1, + 541, -1, 72, 780, -1, 543, -1, 104, + 780, -1, 414, -1, 547, -1, 549, -1, + 65, 775, -1, 551, -1, 97, 775, -1, + 69, 807, -1, 553, -1, 101, 807, -1, + 214, 772, -1, 555, -1, 246, 772, -1, + 213, 772, -1, 557, -1, 245, 772, -1, + 79, 775, -1, 559, -1, 111, 775, -1, + 558, 772, -1, 561, -1, 559, 772, -1, + 89, 772, -1, 563, -1, 121, 772, -1, + 11365, -1, 572, -1, 410, -1, 11366, -1, + 578, -1, 384, -1, 649, -1, 652, -1, + 583, -1, 585, -1, 587, -1, 589, -1, + 591, -1, 614, -1, 633, -1, 635, -1, + 641, -1, 32, 774, -1, 32, 775, -1, + 32, 778, -1, 32, 808, -1, 32, 771, + -1, 32, 779, -1, 661, -1, 768, -1, + 769, -1, 787, -1, 776, 769, -1, 953, + -1, 697, -1, 32, 837, -1, 59, -1, + 168, 769, -1, 913, 769, -1, 940, -1, + 183, -1, 917, 769, -1, 941, -1, 919, + 769, -1, 942, -1, 921, 769, -1, 943, + -1, 927, 769, -1, 972, -1, 933, 769, + -1, 973, -1, 937, 769, -1, 974, -1, + 970, 769, -1, 953, 776, 769, -1, 945, + -1, 946, -1, 947, -1, 948, -1, 949, + -1, 950, -1, 951, -1, 952, -1, 954, + -1, 955, -1, 957, -1, 958, -1, 959, + -1, 960, -1, 961, -1, 963, -1, 964, + -1, 965, -1, 966, -1, 967, -1, 968, + -1, 969, -1, 921, 776, -1, 970, -1, + 933, 776, -1, 971, -1, 945, 769, -1, + 949, 769, -1, 951, 769, -1, 953, 769, + -1, 971, 769, -1, 965, 776, 769, -1, + 953, 776, -1, 965, 776, -1, 959, 769, + -1, 965, 769, -1, 969, 769, -1, 933, + -1, 978, 769, -1, 978, 776, -1, 985, + -1, 987, -1, 989, -1, 991, -1, 993, + -1, 995, -1, 997, -1, 999, -1, 1001, + -1, 1003, -1, 1005, -1, 1007, -1, 962, + -1, 920, -1, 1016, -1, 931, -1, 1010, + -1, 1019, -1, 891, -1, 892, -1, 893, + -1, 1045, 768, -1, 1104, -1, 1045, 776, + -1, 1105, -1, 1106, -1, 1043, 769, -1, + 1107, -1, 1108, -1, 1109, -1, 1110, -1, + 1030, 776, -1, 1111, -1, 1112, -1, 1113, + -1, 1114, -1, 1115, -1, 1050, 769, -1, + 1116, -1, 1048, 768, -1, 1117, -1, 1059, + 774, -1, 1118, -1, 1119, -1, 1072, -1, + 1073, -1, 1074, -1, 1075, -1, 1076, -1, + 1077, -1, 1078, -1, 1079, -1, 1080, -1, + 1048, 774, -1, 1081, -1, 1082, -1, 1083, + -1, 1084, -1, 1085, -1, 1086, -1, 1087, + -1, 1088, -1, 1089, -1, 1090, -1, 1091, + -1, 1092, -1, 1093, -1, 1094, -1, 1095, + -1, 1096, -1, 1097, -1, 1098, -1, 1099, + -1, 1100, -1, 1101, -1, 1102, -1, 1103, + -1, 1080, 774, -1, 1077, 768, -1, 1077, + 776, -1, 1075, 769, -1, 1110, 776, -1, + 1082, 769, -1, 1080, 768, -1, 1091, 774, + -1, 1121, -1, 1123, -1, 1125, -1, 1127, + -1, 1129, -1, 1131, -1, 1133, -1, 1135, + -1, 1137, -1, 1139, -1, 1141, -1, 1140, + 783, -1, 1143, -1, 1141, 783, -1, 1145, + -1, 1147, -1, 1149, -1, 1151, -1, 1153, + -1, 1163, -1, 1165, -1, 1167, -1, 1169, + -1, 1171, -1, 1173, -1, 1175, -1, 1177, + -1, 1179, -1, 1181, -1, 1183, -1, 1185, + -1, 1187, -1, 1189, -1, 1191, -1, 1193, + -1, 1195, -1, 1197, -1, 1199, -1, 1201, + -1, 1203, -1, 1205, -1, 1207, -1, 1209, + -1, 1211, -1, 1213, -1, 1215, -1, 1231, + -1, 1046, 774, -1, 1218, -1, 1078, 774, + -1, 1220, -1, 1222, -1, 1224, -1, 1226, + -1, 1228, -1, 1230, -1, 1040, 774, -1, + 1233, -1, 1072, 774, -1, 1040, 776, -1, + 1235, -1, 1072, 776, -1, 1237, -1, 1045, + 774, -1, 1239, -1, 1077, 774, -1, 1241, + -1, 1240, 776, -1, 1243, -1, 1241, 776, + -1, 1046, 776, -1, 1245, -1, 1078, 776, + -1, 1047, 776, -1, 1247, -1, 1079, 776, + -1, 1249, -1, 1048, 772, -1, 1251, -1, + 1080, 772, -1, 1048, 776, -1, 1253, -1, + 1080, 776, -1, 1054, 776, -1, 1255, -1, + 1086, 776, -1, 1257, -1, 1256, 776, -1, + 1259, -1, 1257, 776, -1, 1069, 776, -1, + 1261, -1, 1101, 776, -1, 1059, 772, -1, + 1263, -1, 1091, 772, -1, 1059, 776, -1, + 1265, -1, 1091, 776, -1, 1059, 779, -1, + 1267, -1, 1091, 779, -1, 1063, 776, -1, + 1269, -1, 1095, 776, -1, 1271, -1, 1067, + 776, -1, 1273, -1, 1099, 776, -1, 1275, + -1, 1277, -1, 1279, -1, 1281, -1, 1283, + -1, 1285, -1, 1287, -1, 1289, -1, 1291, + -1, 1293, -1, 1295, -1, 1297, -1, 1299, + -1, 1377, -1, 1378, -1, 1379, -1, 1380, + -1, 1381, -1, 1382, -1, 1383, -1, 1384, + -1, 1385, -1, 1386, -1, 1387, -1, 1388, + -1, 1389, -1, 1390, -1, 1391, -1, 1392, + -1, 1393, -1, 1394, -1, 1395, -1, 1396, + -1, 1397, -1, 1398, -1, 1399, -1, 1400, + -1, 1401, -1, 1402, -1, 1403, -1, 1404, + -1, 1405, -1, 1406, -1, 1407, -1, 1408, + -1, 1409, -1, 1410, -1, 1411, -1, 1412, + -1, 1413, -1, 1414, -1, 1381, 1410, -1, + 1575, 1619, -1, 1575, 1620, -1, 1608, 1620, + -1, 1575, 1621, -1, 1610, 1620, -1, 1575, + 1652, -1, 1608, 1652, -1, 1735, 1652, -1, + 1610, 1652, -1, 1749, 1620, -1, 1729, 1620, + -1, 1746, 1620, -1, 2344, 2364, -1, 2352, + 2364, -1, 2355, 2364, -1, 2325, 2364, -1, + 2326, 2364, -1, 2327, 2364, -1, 2332, 2364, + -1, 2337, 2364, -1, 2338, 2364, -1, 2347, + 2364, -1, 2351, 2364, -1, 2503, 2494, -1, + 2503, 2519, -1, 2465, 2492, -1, 2466, 2492, + -1, 2479, 2492, -1, 2610, 2620, -1, 2616, + 2620, -1, 2582, 2620, -1, 2583, 2620, -1, + 2588, 2620, -1, 2603, 2620, -1, 2887, 2902, + -1, 2887, 2878, -1, 2887, 2903, -1, 2849, + 2876, -1, 2850, 2876, -1, 2962, 3031, -1, + 3014, 3006, -1, 3015, 3006, -1, 3014, 3031, + -1, 3142, 3158, -1, 3263, 3285, -1, 3270, + 3285, -1, 3270, 3286, -1, 3270, 3266, -1, + 3274, 3285, -1, 3398, 3390, -1, 3399, 3390, + -1, 3398, 3415, -1, 3545, 3530, -1, 3545, + 3535, -1, 3548, 3530, -1, 3545, 3551, -1, + 3661, 3634, -1, 3789, 3762, -1, 3755, 3737, + -1, 3755, 3745, -1, 3851, -1, 3906, 4023, + -1, 3916, 4023, -1, 3921, 4023, -1, 3926, + 4023, -1, 3931, 4023, -1, 3904, 4021, -1, + 3953, 3954, -1, 3953, 3956, -1, 4018, 3968, + -1, 4018, 3969, -1, 4019, 3968, -1, 4019, + 3969, -1, 3953, 3968, -1, 3986, 4023, -1, + 3996, 4023, -1, 4001, 4023, -1, 4006, 4023, + -1, 4011, 4023, -1, 3984, 4021, -1, 4133, + 4142, -1, 11520, -1, 11521, -1, 11522, -1, + 11523, -1, 11524, -1, 11525, -1, 11526, -1, + 11527, -1, 11528, -1, 11529, -1, 11530, -1, + 11531, -1, 11532, -1, 11533, -1, 11534, -1, + 11535, -1, 11536, -1, 11537, -1, 11538, -1, + 11539, -1, 11540, -1, 11541, -1, 11542, -1, + 11543, -1, 11544, -1, 11545, -1, 11546, -1, + 11547, -1, 11548, -1, 11549, -1, 11550, -1, + 11551, -1, 11552, -1, 11553, -1, 11554, -1, + 11555, -1, 11556, -1, 11557, -1, 4316, -1, + 6917, 6965, -1, 6919, 6965, -1, 6921, 6965, + -1, 6923, 6965, -1, 6925, 6965, -1, 6929, + 6965, -1, 6970, 6965, -1, 6972, 6965, -1, + 6974, 6965, -1, 6975, 6965, -1, 6978, 6965, + -1, 65, -1, 198, -1, 66, -1, 68, + -1, 69, -1, 398, -1, 71, -1, 72, + -1, 73, -1, 74, -1, 75, -1, 76, + -1, 77, -1, 78, -1, 79, -1, 546, + -1, 80, -1, 82, -1, 84, -1, 85, + -1, 87, -1, 592, -1, 593, -1, 7426, + -1, 604, -1, 7446, -1, 7447, -1, 7453, + -1, 7461, -1, 594, -1, 597, -1, 607, + -1, 609, -1, 613, -1, 618, -1, 7547, + -1, 669, -1, 621, -1, 7557, -1, 671, + -1, 625, -1, 624, -1, 627, -1, 628, + -1, 632, -1, 642, -1, 427, -1, 7452, + -1, 656, -1, 657, -1, 65, 805, -1, + 7681, -1, 97, 805, -1, 66, 775, -1, + 7683, -1, 98, 775, -1, 66, 803, -1, + 7685, -1, 98, 803, -1, 66, 817, -1, + 7687, -1, 98, 817, -1, 199, 769, -1, + 7689, -1, 231, 769, -1, 68, 775, -1, + 7691, -1, 100, 775, -1, 68, 803, -1, + 7693, -1, 100, 803, -1, 68, 817, -1, + 7695, -1, 100, 817, -1, 68, 807, -1, + 7697, -1, 100, 807, -1, 68, 813, -1, + 7699, -1, 100, 813, -1, 274, 768, -1, + 7701, -1, 275, 768, -1, 274, 769, -1, + 7703, -1, 275, 769, -1, 69, 813, -1, + 7705, -1, 101, 813, -1, 69, 816, -1, + 7707, -1, 101, 816, -1, 552, 774, -1, + 7709, -1, 553, 774, -1, 70, 775, -1, + 7711, -1, 102, 775, -1, 71, 772, -1, + 7713, -1, 103, 772, -1, 72, 775, -1, + 7715, -1, 104, 775, -1, 72, 803, -1, + 7717, -1, 104, 803, -1, 72, 776, -1, + 7719, -1, 104, 776, -1, 72, 807, -1, + 7721, -1, 104, 807, -1, 72, 814, -1, + 7723, -1, 104, 814, -1, 73, 816, -1, + 7725, -1, 105, 816, -1, 207, 769, -1, + 7727, -1, 239, 769, -1, 75, 769, -1, + 7729, -1, 107, 769, -1, 75, 803, -1, + 7731, -1, 107, 803, -1, 75, 817, -1, + 7733, -1, 107, 817, -1, 76, 803, -1, + 7735, -1, 108, 803, -1, 7734, 772, -1, + 7737, -1, 7735, 772, -1, 76, 817, -1, + 7739, -1, 108, 817, -1, 76, 813, -1, + 7741, -1, 108, 813, -1, 77, 769, -1, + 7743, -1, 109, 769, -1, 77, 775, -1, + 7745, -1, 109, 775, -1, 77, 803, -1, + 7747, -1, 109, 803, -1, 78, 775, -1, + 7749, -1, 110, 775, -1, 78, 803, -1, + 7751, -1, 110, 803, -1, 78, 817, -1, + 7753, -1, 110, 817, -1, 78, 813, -1, + 7755, -1, 110, 813, -1, 213, 769, -1, + 7757, -1, 245, 769, -1, 213, 776, -1, + 7759, -1, 245, 776, -1, 332, 768, -1, + 7761, -1, 333, 768, -1, 332, 769, -1, + 7763, -1, 333, 769, -1, 80, 769, -1, + 7765, -1, 112, 769, -1, 80, 775, -1, + 7767, -1, 112, 775, -1, 82, 775, -1, + 7769, -1, 114, 775, -1, 82, 803, -1, + 7771, -1, 114, 803, -1, 7770, 772, -1, + 7773, -1, 7771, 772, -1, 82, 817, -1, + 7775, -1, 114, 817, -1, 83, 775, -1, + 7777, -1, 115, 775, -1, 83, 803, -1, + 7779, -1, 115, 803, -1, 346, 775, -1, + 7781, -1, 347, 775, -1, 352, 775, -1, + 7783, -1, 353, 775, -1, 7778, 775, -1, + 7785, -1, 7779, 775, -1, 84, 775, -1, + 7787, -1, 116, 775, -1, 84, 803, -1, + 7789, -1, 116, 803, -1, 84, 817, -1, + 7791, -1, 116, 817, -1, 84, 813, -1, + 7793, -1, 116, 813, -1, 85, 804, -1, + 7795, -1, 117, 804, -1, 85, 816, -1, + 7797, -1, 117, 816, -1, 85, 813, -1, + 7799, -1, 117, 813, -1, 360, 769, -1, + 7801, -1, 361, 769, -1, 362, 776, -1, + 7803, -1, 363, 776, -1, 86, 771, -1, + 7805, -1, 118, 771, -1, 86, 803, -1, + 7807, -1, 118, 803, -1, 87, 768, -1, + 7809, -1, 119, 768, -1, 87, 769, -1, + 7811, -1, 119, 769, -1, 87, 776, -1, + 7813, -1, 119, 776, -1, 87, 775, -1, + 7815, -1, 119, 775, -1, 87, 803, -1, + 7817, -1, 119, 803, -1, 88, 775, -1, + 7819, -1, 120, 775, -1, 88, 776, -1, + 7821, -1, 120, 776, -1, 89, 775, -1, + 7823, -1, 121, 775, -1, 90, 770, -1, + 7825, -1, 122, 770, -1, 90, 803, -1, + 7827, -1, 122, 803, -1, 90, 817, -1, + 7829, -1, 122, 817, -1, 104, 817, -1, + 116, 776, -1, 119, 778, -1, 121, 778, + -1, 97, 702, -1, 383, 775, -1, 65, + 803, -1, 7841, -1, 97, 803, -1, 65, + 777, -1, 7843, -1, 97, 777, -1, 194, + 769, -1, 7845, -1, 226, 769, -1, 194, + 768, -1, 7847, -1, 226, 768, -1, 194, + 777, -1, 7849, -1, 226, 777, -1, 194, + 771, -1, 7851, -1, 226, 771, -1, 7840, + 770, -1, 7853, -1, 7841, 770, -1, 258, + 769, -1, 7855, -1, 259, 769, -1, 258, + 768, -1, 7857, -1, 259, 768, -1, 258, + 777, -1, 7859, -1, 259, 777, -1, 258, + 771, -1, 7861, -1, 259, 771, -1, 7840, + 774, -1, 7863, -1, 7841, 774, -1, 69, + 803, -1, 7865, -1, 101, 803, -1, 69, + 777, -1, 7867, -1, 101, 777, -1, 69, + 771, -1, 7869, -1, 101, 771, -1, 202, + 769, -1, 7871, -1, 234, 769, -1, 202, + 768, -1, 7873, -1, 234, 768, -1, 202, + 777, -1, 7875, -1, 234, 777, -1, 202, + 771, -1, 7877, -1, 234, 771, -1, 7864, + 770, -1, 7879, -1, 7865, 770, -1, 73, + 777, -1, 7881, -1, 105, 777, -1, 73, + 803, -1, 7883, -1, 105, 803, -1, 79, + 803, -1, 7885, -1, 111, 803, -1, 79, + 777, -1, 7887, -1, 111, 777, -1, 212, + 769, -1, 7889, -1, 244, 769, -1, 212, + 768, -1, 7891, -1, 244, 768, -1, 212, + 777, -1, 7893, -1, 244, 777, -1, 212, + 771, -1, 7895, -1, 244, 771, -1, 7884, + 770, -1, 7897, -1, 7885, 770, -1, 416, + 769, -1, 7899, -1, 417, 769, -1, 416, + 768, -1, 7901, -1, 417, 768, -1, 416, + 777, -1, 7903, -1, 417, 777, -1, 416, + 771, -1, 7905, -1, 417, 771, -1, 416, + 803, -1, 7907, -1, 417, 803, -1, 85, + 803, -1, 7909, -1, 117, 803, -1, 85, + 777, -1, 7911, -1, 117, 777, -1, 431, + 769, -1, 7913, -1, 432, 769, -1, 431, + 768, -1, 7915, -1, 432, 768, -1, 431, + 777, -1, 7917, -1, 432, 777, -1, 431, + 771, -1, 7919, -1, 432, 771, -1, 431, + 803, -1, 7921, -1, 432, 803, -1, 89, + 768, -1, 7923, -1, 121, 768, -1, 89, + 803, -1, 7925, -1, 121, 803, -1, 89, + 777, -1, 7927, -1, 121, 777, -1, 89, + 771, -1, 7929, -1, 121, 771, -1, 945, + 787, -1, 945, 788, -1, 7936, 768, -1, + 7937, 768, -1, 7936, 769, -1, 7937, 769, + -1, 7936, 834, -1, 7937, 834, -1, 913, + 787, -1, 7936, -1, 913, 788, -1, 7937, + -1, 7944, 768, -1, 7938, -1, 7945, 768, + -1, 7939, -1, 7944, 769, -1, 7940, -1, + 7945, 769, -1, 7941, -1, 7944, 834, -1, + 7942, -1, 7945, 834, -1, 7943, -1, 949, + 787, -1, 949, 788, -1, 7952, 768, -1, + 7953, 768, -1, 7952, 769, -1, 7953, 769, + -1, 917, 787, -1, 7952, -1, 917, 788, + -1, 7953, -1, 7960, 768, -1, 7954, -1, + 7961, 768, -1, 7955, -1, 7960, 769, -1, + 7956, -1, 7961, 769, -1, 7957, -1, 951, + 787, -1, 951, 788, -1, 7968, 768, -1, + 7969, 768, -1, 7968, 769, -1, 7969, 769, + -1, 7968, 834, -1, 7969, 834, -1, 919, + 787, -1, 7968, -1, 919, 788, -1, 7969, + -1, 7976, 768, -1, 7970, -1, 7977, 768, + -1, 7971, -1, 7976, 769, -1, 7972, -1, + 7977, 769, -1, 7973, -1, 7976, 834, -1, + 7974, -1, 7977, 834, -1, 7975, -1, 953, + 787, -1, 953, 788, -1, 7984, 768, -1, + 7985, 768, -1, 7984, 769, -1, 7985, 769, + -1, 7984, 834, -1, 7985, 834, -1, 921, + 787, -1, 7984, -1, 921, 788, -1, 7985, + -1, 7992, 768, -1, 7986, -1, 7993, 768, + -1, 7987, -1, 7992, 769, -1, 7988, -1, + 7993, 769, -1, 7989, -1, 7992, 834, -1, + 7990, -1, 7993, 834, -1, 7991, -1, 959, + 787, -1, 959, 788, -1, 8000, 768, -1, + 8001, 768, -1, 8000, 769, -1, 8001, 769, + -1, 927, 787, -1, 8000, -1, 927, 788, + -1, 8001, -1, 8008, 768, -1, 8002, -1, + 8009, 768, -1, 8003, -1, 8008, 769, -1, + 8004, -1, 8009, 769, -1, 8005, -1, 965, + 787, -1, 965, 788, -1, 8016, 768, -1, + 965, 787, 768, -1, 8017, 768, -1, 8016, + 769, -1, 965, 787, 769, -1, 8017, 769, + -1, 8016, 834, -1, 965, 787, 834, -1, + 8017, 834, -1, 933, 788, -1, 8017, -1, + 8025, 768, -1, 8019, -1, 8025, 769, -1, + 8021, -1, 8025, 834, -1, 8023, -1, 969, + 787, -1, 969, 788, -1, 8032, 768, -1, + 8033, 768, -1, 8032, 769, -1, 8033, 769, + -1, 8032, 834, -1, 8033, 834, -1, 937, + 787, -1, 8032, -1, 937, 788, -1, 8033, + -1, 8040, 768, -1, 8034, -1, 8041, 768, + -1, 8035, -1, 8040, 769, -1, 8036, -1, + 8041, 769, -1, 8037, -1, 8040, 834, -1, + 8038, -1, 8041, 834, -1, 8039, -1, 945, + 768, -1, 949, 768, -1, 951, 768, -1, + 953, 768, -1, 959, 768, -1, 965, 768, + -1, 969, 768, -1, 7936, 837, -1, 7936, + 953, -1, 7937, 837, -1, 7937, 953, -1, + 7938, 837, -1, 7938, 953, -1, 7939, 837, + -1, 7939, 953, -1, 7940, 837, -1, 7940, + 953, -1, 7941, 837, -1, 7941, 953, -1, + 7942, 837, -1, 7942, 953, -1, 7943, 837, + -1, 7943, 953, -1, 7944, 837, -1, 8064, + -1, 7945, 837, -1, 8065, -1, 7946, 837, + -1, 8066, -1, 7947, 837, -1, 8067, -1, + 7948, 837, -1, 8068, -1, 7949, 837, -1, + 8069, -1, 7950, 837, -1, 8070, -1, 7951, + 837, -1, 8071, -1, 7968, 837, -1, 7968, + 953, -1, 7969, 837, -1, 7969, 953, -1, + 7970, 837, -1, 7970, 953, -1, 7971, 837, + -1, 7971, 953, -1, 7972, 837, -1, 7972, + 953, -1, 7973, 837, -1, 7973, 953, -1, + 7974, 837, -1, 7974, 953, -1, 7975, 837, + -1, 7975, 953, -1, 7976, 837, -1, 8080, + -1, 7977, 837, -1, 8081, -1, 7978, 837, + -1, 8082, -1, 7979, 837, -1, 8083, -1, + 7980, 837, -1, 8084, -1, 7981, 837, -1, + 8085, -1, 7982, 837, -1, 8086, -1, 7983, + 837, -1, 8087, -1, 8032, 837, -1, 8032, + 953, -1, 8033, 837, -1, 8033, 953, -1, + 8034, 837, -1, 8034, 953, -1, 8035, 837, + -1, 8035, 953, -1, 8036, 837, -1, 8036, + 953, -1, 8037, 837, -1, 8037, 953, -1, + 8038, 837, -1, 8038, 953, -1, 8039, 837, + -1, 8039, 953, -1, 8040, 837, -1, 8096, + -1, 8041, 837, -1, 8097, -1, 8042, 837, + -1, 8098, -1, 8043, 837, -1, 8099, -1, + 8044, 837, -1, 8100, -1, 8045, 837, -1, + 8101, -1, 8046, 837, -1, 8102, -1, 8047, + 837, -1, 8103, -1, 945, 774, -1, 945, + 772, -1, 8048, 837, -1, 8048, 953, -1, + 945, 837, -1, 945, 953, -1, 940, 837, + -1, 940, 953, -1, 945, 834, -1, 8118, + 837, -1, 945, 834, 953, -1, 913, 774, + -1, 8112, -1, 913, 772, -1, 8113, -1, + 913, 768, -1, 8048, -1, 902, -1, 8049, + -1, 913, 837, -1, 8115, -1, 32, 787, + -1, 32, 834, -1, 168, 834, -1, 8052, + 837, -1, 8052, 953, -1, 951, 837, -1, + 951, 953, -1, 942, 837, -1, 942, 953, + -1, 951, 834, -1, 8134, 837, -1, 951, + 834, 953, -1, 917, 768, -1, 8050, -1, + 904, -1, 8051, -1, 919, 768, -1, 8052, + -1, 905, -1, 8053, -1, 919, 837, -1, + 8131, -1, 8127, 768, -1, 8127, 769, -1, + 8127, 834, -1, 953, 774, -1, 953, 772, + -1, 970, 768, -1, 953, 776, 768, -1, + 912, -1, 953, 834, -1, 970, 834, -1, + 953, 776, 834, -1, 921, 774, -1, 8144, + -1, 921, 772, -1, 8145, -1, 921, 768, + -1, 8054, -1, 906, -1, 8055, -1, 8190, + 768, -1, 8190, 769, -1, 8190, 834, -1, + 965, 774, -1, 965, 772, -1, 971, 768, + -1, 965, 776, 768, -1, 944, -1, 961, + 787, -1, 961, 788, -1, 965, 834, -1, + 971, 834, -1, 965, 776, 834, -1, 933, + 774, -1, 8160, -1, 933, 772, -1, 8161, + -1, 933, 768, -1, 8058, -1, 910, -1, + 8059, -1, 929, 788, -1, 8165, -1, 168, + 768, -1, 901, -1, 96, -1, 8060, 837, + -1, 8060, 953, -1, 969, 837, -1, 969, + 953, -1, 974, 837, -1, 974, 953, -1, + 969, 834, -1, 8182, 837, -1, 969, 834, + 953, -1, 927, 768, -1, 8056, -1, 908, + -1, 8057, -1, 937, 768, -1, 8060, -1, + 911, -1, 8061, -1, 937, 837, -1, 8179, + -1, 180, -1, 32, 788, -1, 8194, -1, + 8195, -1, 8208, -1, 32, 819, -1, 46, + -1, 46, 46, -1, 46, 46, 46, -1, + 8242, 8242, -1, 8242, 8242, 8242, -1, 8245, + 8245, -1, 8245, 8245, 8245, -1, 33, 33, + -1, 32, 773, -1, 63, 63, -1, 63, + 33, -1, 33, 63, -1, 8242, 8242, 8242, + 8242, -1, 48, -1, 52, -1, 53, -1, + 54, -1, 55, -1, 56, -1, 57, -1, + 43, -1, 8722, -1, 61, -1, 40, -1, + 41, -1, 82, 115, -1, 97, 47, 99, + -1, 97, 47, 115, -1, 67, -1, 176, + 67, -1, 99, 47, 111, -1, 99, 47, + 117, -1, 400, -1, 176, 70, -1, 78, + 111, -1, 81, -1, 83, 77, -1, 84, + 69, 76, -1, 84, 77, -1, 90, -1, + 937, -1, 197, -1, 70, -1, 8526, -1, + 1488, -1, 1489, -1, 1490, -1, 1491, -1, + 70, 65, 88, -1, 915, -1, 928, -1, + 8721, -1, 49, 8260, 51, -1, 50, 8260, + 51, -1, 49, 8260, 53, -1, 50, 8260, + 53, -1, 51, 8260, 53, -1, 52, 8260, + 53, -1, 49, 8260, 54, -1, 53, 8260, + 54, -1, 49, 8260, 56, -1, 51, 8260, + 56, -1, 53, 8260, 56, -1, 55, 8260, + 56, -1, 49, 8260, -1, 8560, -1, 73, + 73, -1, 8561, -1, 73, 73, 73, -1, + 8562, -1, 73, 86, -1, 8563, -1, 86, + -1, 8564, -1, 86, 73, -1, 8565, -1, + 86, 73, 73, -1, 8566, -1, 86, 73, + 73, 73, -1, 8567, -1, 73, 88, -1, + 8568, -1, 88, -1, 8569, -1, 88, 73, + -1, 8570, -1, 88, 73, 73, -1, 8571, + -1, 8572, -1, 8573, -1, 8574, -1, 8575, + -1, 105, 105, -1, 105, 105, 105, -1, + 105, 118, -1, 118, 105, -1, 118, 105, + 105, -1, 118, 105, 105, 105, -1, 105, + 120, -1, 120, 105, -1, 120, 105, 105, + -1, 8580, -1, 8592, 824, -1, 8594, 824, + -1, 8596, 824, -1, 8656, 824, -1, 8660, + 824, -1, 8658, 824, -1, 8707, 824, -1, + 8712, 824, -1, 8715, 824, -1, 8739, 824, + -1, 8741, 824, -1, 8747, 8747, -1, 8747, + 8747, 8747, -1, 8750, 8750, -1, 8750, 8750, + 8750, -1, 8764, 824, -1, 8771, 824, -1, + 8773, 824, -1, 8776, 824, -1, 61, 824, + -1, 8801, 824, -1, 8781, 824, -1, 60, + 824, -1, 62, 824, -1, 8804, 824, -1, + 8805, 824, -1, 8818, 824, -1, 8819, 824, + -1, 8822, 824, -1, 8823, 824, -1, 8826, + 824, -1, 8827, 824, -1, 8834, 824, -1, + 8835, 824, -1, 8838, 824, -1, 8839, 824, + -1, 8866, 824, -1, 8872, 824, -1, 8873, + 824, -1, 8875, 824, -1, 8828, 824, -1, + 8829, 824, -1, 8849, 824, -1, 8850, 824, + -1, 8882, 824, -1, 8883, 824, -1, 8884, + 824, -1, 8885, 824, -1, 12296, -1, 12297, + -1, 49, 48, -1, 49, 49, -1, 49, + 50, -1, 49, 51, -1, 49, 52, -1, + 49, 53, -1, 49, 54, -1, 49, 55, + -1, 49, 56, -1, 49, 57, -1, 50, + 48, -1, 40, 49, 41, -1, 40, 50, + 41, -1, 40, 51, 41, -1, 40, 52, + 41, -1, 40, 53, 41, -1, 40, 54, + 41, -1, 40, 55, 41, -1, 40, 56, + 41, -1, 40, 57, 41, -1, 40, 49, + 48, 41, -1, 40, 49, 49, 41, -1, + 40, 49, 50, 41, -1, 40, 49, 51, + 41, -1, 40, 49, 52, 41, -1, 40, + 49, 53, 41, -1, 40, 49, 54, 41, + -1, 40, 49, 55, 41, -1, 40, 49, + 56, 41, -1, 40, 49, 57, 41, -1, + 40, 50, 48, 41, -1, 49, 46, -1, + 50, 46, -1, 51, 46, -1, 52, 46, + -1, 53, 46, -1, 54, 46, -1, 55, + 46, -1, 56, 46, -1, 57, 46, -1, + 49, 48, 46, -1, 49, 49, 46, -1, + 49, 50, 46, -1, 49, 51, 46, -1, + 49, 52, 46, -1, 49, 53, 46, -1, + 49, 54, 46, -1, 49, 55, 46, -1, + 49, 56, 46, -1, 49, 57, 46, -1, + 50, 48, 46, -1, 40, 97, 41, -1, + 40, 98, 41, -1, 40, 99, 41, -1, + 40, 100, 41, -1, 40, 101, 41, -1, + 40, 102, 41, -1, 40, 103, 41, -1, + 40, 104, 41, -1, 40, 105, 41, -1, + 40, 106, 41, -1, 40, 107, 41, -1, + 40, 108, 41, -1, 40, 109, 41, -1, + 40, 110, 41, -1, 40, 111, 41, -1, + 40, 112, 41, -1, 40, 113, 41, -1, + 40, 114, 41, -1, 40, 115, 41, -1, + 40, 116, 41, -1, 40, 117, 41, -1, + 40, 118, 41, -1, 40, 119, 41, -1, + 40, 120, 41, -1, 40, 121, 41, -1, + 40, 122, 41, -1, 9424, -1, 9425, -1, + 9426, -1, 9427, -1, 9428, -1, 9429, -1, + 9430, -1, 9431, -1, 9432, -1, 9433, -1, + 9434, -1, 9435, -1, 9436, -1, 9437, -1, + 9438, -1, 9439, -1, 9440, -1, 9441, -1, + 83, -1, 9442, -1, 9443, -1, 9444, -1, + 9445, -1, 9446, -1, 9447, -1, 89, -1, + 9448, -1, 9449, -1, 8747, 8747, 8747, 8747, + -1, 58, 58, 61, -1, 61, 61, -1, + 61, 61, 61, -1, 10973, 824, -1, 11312, + -1, 11313, -1, 11314, -1, 11315, -1, 11316, + -1, 11317, -1, 11318, -1, 11319, -1, 11320, + -1, 11321, -1, 11322, -1, 11323, -1, 11324, + -1, 11325, -1, 11326, -1, 11327, -1, 11328, + -1, 11329, -1, 11330, -1, 11331, -1, 11332, + -1, 11333, -1, 11334, -1, 11335, -1, 11336, + -1, 11337, -1, 11338, -1, 11339, -1, 11340, + -1, 11341, -1, 11342, -1, 11343, -1, 11344, + -1, 11345, -1, 11346, -1, 11347, -1, 11348, + -1, 11349, -1, 11350, -1, 11351, -1, 11352, + -1, 11353, -1, 11354, -1, 11355, -1, 11356, + -1, 11357, -1, 11358, -1, 11361, -1, 619, + -1, 7549, -1, 637, -1, 11368, -1, 11370, + -1, 11372, -1, 11382, -1, 11393, -1, 11395, + -1, 11397, -1, 11399, -1, 11401, -1, 11403, + -1, 11405, -1, 11407, -1, 11409, -1, 11411, + -1, 11413, -1, 11415, -1, 11417, -1, 11419, + -1, 11421, -1, 11423, -1, 11425, -1, 11427, + -1, 11429, -1, 11431, -1, 11433, -1, 11435, + -1, 11437, -1, 11439, -1, 11441, -1, 11443, + -1, 11445, -1, 11447, -1, 11449, -1, 11451, + -1, 11453, -1, 11455, -1, 11457, -1, 11459, + -1, 11461, -1, 11463, -1, 11465, -1, 11467, + -1, 11469, -1, 11471, -1, 11473, -1, 11475, + -1, 11477, -1, 11479, -1, 11481, -1, 11483, + -1, 11485, -1, 11487, -1, 11489, -1, 11491, + -1, 11617, -1, 27597, -1, 40863, -1, 19968, + -1, 20008, -1, 20022, -1, 20031, -1, 20057, + -1, 20101, -1, 20108, -1, 20128, -1, 20154, + -1, 20799, -1, 20837, -1, 20843, -1, 20866, + -1, 20886, -1, 20907, -1, 20960, -1, 20981, + -1, 20992, -1, 21147, -1, 21241, -1, 21269, + -1, 21274, -1, 21304, -1, 21313, -1, 21340, + -1, 21353, -1, 21378, -1, 21430, -1, 21448, + -1, 21475, -1, 22231, -1, 22303, -1, 22763, + -1, 22786, -1, 22794, -1, 22805, -1, 22823, + -1, 22899, -1, 23376, -1, 23424, -1, 23544, + -1, 23567, -1, 23586, -1, 23608, -1, 23662, + -1, 23665, -1, 24027, -1, 24037, -1, 24049, + -1, 24062, -1, 24178, -1, 24186, -1, 24191, + -1, 24308, -1, 24318, -1, 24331, -1, 24339, + -1, 24400, -1, 24417, -1, 24435, -1, 24515, + -1, 25096, -1, 25142, -1, 25163, -1, 25903, + -1, 25908, -1, 25991, -1, 26007, -1, 26020, + -1, 26041, -1, 26080, -1, 26085, -1, 26352, + -1, 26376, -1, 26408, -1, 27424, -1, 27490, + -1, 27513, -1, 27571, -1, 27595, -1, 27604, + -1, 27611, -1, 27663, -1, 27668, -1, 27700, + -1, 28779, -1, 29226, -1, 29238, -1, 29243, + -1, 29247, -1, 29255, -1, 29273, -1, 29275, + -1, 29356, -1, 29572, -1, 29577, -1, 29916, + -1, 29926, -1, 29976, -1, 29983, -1, 29992, + -1, 30000, -1, 30091, -1, 30098, -1, 30326, + -1, 30333, -1, 30382, -1, 30399, -1, 30446, + -1, 30683, -1, 30690, -1, 30707, -1, 31034, + -1, 31160, -1, 31166, -1, 31348, -1, 31435, + -1, 31481, -1, 31859, -1, 31992, -1, 32566, + -1, 32593, -1, 32650, -1, 32701, -1, 32769, + -1, 32780, -1, 32786, -1, 32819, -1, 32895, + -1, 32905, -1, 33251, -1, 33258, -1, 33267, + -1, 33276, -1, 33292, -1, 33307, -1, 33311, + -1, 33390, -1, 33394, -1, 33400, -1, 34381, + -1, 34411, -1, 34880, -1, 34892, -1, 34915, + -1, 35198, -1, 35211, -1, 35282, -1, 35328, + -1, 35895, -1, 35910, -1, 35925, -1, 35960, + -1, 35997, -1, 36196, -1, 36208, -1, 36275, + -1, 36523, -1, 36554, -1, 36763, -1, 36784, + -1, 36789, -1, 37009, -1, 37193, -1, 37318, + -1, 37324, -1, 37329, -1, 38263, -1, 38272, + -1, 38428, -1, 38582, -1, 38585, -1, 38632, + -1, 38737, -1, 38750, -1, 38754, -1, 38761, + -1, 38859, -1, 38893, -1, 38899, -1, 38913, + -1, 39080, -1, 39131, -1, 39135, -1, 39318, + -1, 39321, -1, 39340, -1, 39592, -1, 39640, + -1, 39647, -1, 39717, -1, 39727, -1, 39730, + -1, 39740, -1, 39770, -1, 40165, -1, 40565, + -1, 40575, -1, 40613, -1, 40635, -1, 40643, + -1, 40653, -1, 40657, -1, 40697, -1, 40701, + -1, 40718, -1, 40723, -1, 40736, -1, 40763, + -1, 40778, -1, 40786, -1, 40845, -1, 40860, + -1, 40864, -1, 12306, -1, 21316, -1, 21317, + -1, 12363, 12441, -1, 12365, 12441, -1, 12367, + 12441, -1, 12369, 12441, -1, 12371, 12441, -1, + 12373, 12441, -1, 12375, 12441, -1, 12377, 12441, + -1, 12379, 12441, -1, 12381, 12441, -1, 12383, + 12441, -1, 12385, 12441, -1, 12388, 12441, -1, + 12390, 12441, -1, 12392, 12441, -1, 12399, 12441, + -1, 12399, 12442, -1, 12402, 12441, -1, 12402, + 12442, -1, 12405, 12441, -1, 12405, 12442, -1, + 12408, 12441, -1, 12408, 12442, -1, 12411, 12441, + -1, 12411, 12442, -1, 12358, 12441, -1, 32, + 12441, -1, 32, 12442, -1, 12445, 12441, -1, + 12424, 12426, -1, 12459, 12441, -1, 12461, 12441, + -1, 12463, 12441, -1, 12465, 12441, -1, 12467, + 12441, -1, 12469, 12441, -1, 12471, 12441, -1, + 12473, 12441, -1, 12475, 12441, -1, 12477, 12441, + -1, 12479, 12441, -1, 12481, 12441, -1, 12484, + 12441, -1, 12486, 12441, -1, 12488, 12441, -1, + 12495, 12441, -1, 12495, 12442, -1, 12498, 12441, + -1, 12498, 12442, -1, 12501, 12441, -1, 12501, + 12442, -1, 12504, 12441, -1, 12504, 12442, -1, + 12507, 12441, -1, 12507, 12442, -1, 12454, 12441, + -1, 12527, 12441, -1, 12528, 12441, -1, 12529, + 12441, -1, 12530, 12441, -1, 12541, 12441, -1, + 12467, 12488, -1, 4352, -1, 4353, -1, 4522, + -1, 4354, -1, 4524, -1, 4525, -1, 4355, + -1, 4356, -1, 4357, -1, 4528, -1, 4529, + -1, 4530, -1, 4531, -1, 4532, -1, 4533, + -1, 4378, -1, 4358, -1, 4359, -1, 4360, + -1, 4385, -1, 4361, -1, 4362, -1, 4363, + -1, 4364, -1, 4365, -1, 4366, -1, 4367, + -1, 4368, -1, 4369, -1, 4370, -1, 4449, + -1, 4450, -1, 4451, -1, 4452, -1, 4453, + -1, 4454, -1, 4455, -1, 4456, -1, 4457, + -1, 4458, -1, 4459, -1, 4460, -1, 4461, + -1, 4462, -1, 4463, -1, 4464, -1, 4465, + -1, 4466, -1, 4467, -1, 4468, -1, 4469, + -1, 4448, -1, 4372, -1, 4373, -1, 4551, + -1, 4552, -1, 4556, -1, 4558, -1, 4563, + -1, 4567, -1, 4569, -1, 4380, -1, 4573, + -1, 4575, -1, 4381, -1, 4382, -1, 4384, + -1, 4386, -1, 4387, -1, 4391, -1, 4393, + -1, 4395, -1, 4396, -1, 4397, -1, 4398, + -1, 4399, -1, 4402, -1, 4406, -1, 4416, + -1, 4423, -1, 4428, -1, 4593, -1, 4594, + -1, 4439, -1, 4440, -1, 4441, -1, 4484, + -1, 4485, -1, 4488, -1, 4497, -1, 4498, + -1, 4500, -1, 4510, -1, 4513, -1, 19977, + -1, 22235, -1, 19978, -1, 20013, -1, 19979, + -1, 30002, -1, 19993, -1, 19969, -1, 22825, + -1, 22320, -1, 40, 4352, 41, -1, 40, + 4354, 41, -1, 40, 4355, 41, -1, 40, + 4357, 41, -1, 40, 4358, 41, -1, 40, + 4359, 41, -1, 40, 4361, 41, -1, 40, + 4363, 41, -1, 40, 4364, 41, -1, 40, + 4366, 41, -1, 40, 4367, 41, -1, 40, + 4368, 41, -1, 40, 4369, 41, -1, 40, + 4370, 41, -1, 40, 4352, 4449, 41, -1, + 40, 4354, 4449, 41, -1, 40, 4355, 4449, + 41, -1, 40, 4357, 4449, 41, -1, 40, + 4358, 4449, 41, -1, 40, 4359, 4449, 41, + -1, 40, 4361, 4449, 41, -1, 40, 4363, + 4449, 41, -1, 40, 4364, 4449, 41, -1, + 40, 4366, 4449, 41, -1, 40, 4367, 4449, + 41, -1, 40, 4368, 4449, 41, -1, 40, + 4369, 4449, 41, -1, 40, 4370, 4449, 41, + -1, 40, 4364, 4462, 41, -1, 40, 4363, + 4457, 4364, 4453, 4523, 41, -1, 40, 4363, + 4457, 4370, 4462, 41, -1, 40, 19968, 41, + -1, 40, 20108, 41, -1, 40, 19977, 41, + -1, 40, 22235, 41, -1, 40, 20116, 41, + -1, 40, 20845, 41, -1, 40, 19971, 41, + -1, 40, 20843, 41, -1, 40, 20061, 41, + -1, 40, 21313, 41, -1, 40, 26376, 41, + -1, 40, 28779, 41, -1, 40, 27700, 41, + -1, 40, 26408, 41, -1, 40, 37329, 41, + -1, 40, 22303, 41, -1, 40, 26085, 41, + -1, 40, 26666, 41, -1, 40, 26377, 41, + -1, 40, 31038, 41, -1, 40, 21517, 41, + -1, 40, 29305, 41, -1, 40, 36001, 41, + -1, 40, 31069, 41, -1, 40, 21172, 41, + -1, 40, 20195, 41, -1, 40, 21628, 41, + -1, 40, 23398, 41, -1, 40, 30435, 41, + -1, 40, 20225, 41, -1, 40, 36039, 41, + -1, 40, 21332, 41, -1, 40, 31085, 41, + -1, 40, 20241, 41, -1, 40, 33258, 41, + -1, 40, 33267, 41, -1, 80, 84, 69, + -1, 50, 49, -1, 50, 50, -1, 50, + 51, -1, 50, 52, -1, 50, 53, -1, + 50, 54, -1, 50, 55, -1, 50, 56, + -1, 50, 57, -1, 51, 48, -1, 51, + 49, -1, 51, 50, -1, 51, 51, -1, + 51, 52, -1, 51, 53, -1, 4352, 4449, + -1, 4354, 4449, -1, 4355, 4449, -1, 4357, + 4449, -1, 4358, 4449, -1, 4359, 4449, -1, + 4361, 4449, -1, 4363, 4449, -1, 4364, 4449, + -1, 4366, 4449, -1, 4367, 4449, -1, 4368, + 4449, -1, 4369, 4449, -1, 4370, 4449, -1, + 4366, 4449, 4535, 4352, 4457, -1, 4364, 4462, + 4363, 4468, -1, 4363, 4462, -1, 20116, -1, + 20845, -1, 19971, -1, 20061, -1, 26666, -1, + 26377, -1, 31038, -1, 21517, -1, 29305, -1, + 36001, -1, 31069, -1, 21172, -1, 31192, -1, + 30007, -1, 36969, -1, 20778, -1, 21360, -1, + 27880, -1, 38917, -1, 20241, -1, 20889, -1, + 27491, -1, 24038, -1, 21491, -1, 21307, -1, + 23447, -1, 23398, -1, 30435, -1, 20225, -1, + 36039, -1, 21332, -1, 22812, -1, 51, 54, + -1, 51, 55, -1, 51, 56, -1, 51, + 57, -1, 52, 48, -1, 52, 49, -1, + 52, 50, -1, 52, 51, -1, 52, 52, + -1, 52, 53, -1, 52, 54, -1, 52, + 55, -1, 52, 56, -1, 52, 57, -1, + 53, 48, -1, 49, 26376, -1, 50, 26376, + -1, 51, 26376, -1, 52, 26376, -1, 53, + 26376, -1, 54, 26376, -1, 55, 26376, -1, + 56, 26376, -1, 57, 26376, -1, 49, 48, + 26376, -1, 49, 49, 26376, -1, 49, 50, + 26376, -1, 72, 103, -1, 101, 114, 103, + -1, 101, 86, -1, 76, 84, 68, -1, + 12450, -1, 12452, -1, 12454, -1, 12456, -1, + 12458, -1, 12459, -1, 12461, -1, 12463, -1, + 12465, -1, 12467, -1, 12469, -1, 12471, -1, + 12473, -1, 12475, -1, 12477, -1, 12479, -1, + 12481, -1, 12484, -1, 12486, -1, 12488, -1, + 12490, -1, 12491, -1, 12492, -1, 12493, -1, + 12494, -1, 12495, -1, 12498, -1, 12501, -1, + 12504, -1, 12507, -1, 12510, -1, 12511, -1, + 12512, -1, 12513, -1, 12514, -1, 12516, -1, + 12518, -1, 12520, -1, 12521, -1, 12522, -1, + 12523, -1, 12524, -1, 12525, -1, 12527, -1, + 12528, -1, 12529, -1, 12530, -1, 12450, 12497, + 12540, 12488, -1, 12450, 12523, 12501, 12449, -1, + 12450, 12531, 12506, 12450, -1, 12450, 12540, 12523, + -1, 12452, 12491, 12531, 12464, -1, 12452, 12531, + 12481, -1, 12454, 12457, 12531, -1, 12456, 12473, + 12463, 12540, 12489, -1, 12456, 12540, 12459, 12540, + -1, 12458, 12531, 12473, -1, 12458, 12540, 12512, + -1, 12459, 12452, 12522, -1, 12459, 12521, 12483, + 12488, -1, 12459, 12525, 12522, 12540, -1, 12460, + 12525, 12531, -1, 12460, 12531, 12510, -1, 12462, + 12460, -1, 12462, 12491, 12540, -1, 12461, 12517, + 12522, 12540, -1, 12462, 12523, 12480, 12540, -1, + 12461, 12525, -1, 12461, 12525, 12464, 12521, 12512, + -1, 12461, 12525, 12513, 12540, 12488, 12523, -1, + 12461, 12525, 12527, 12483, 12488, -1, 12464, 12521, + 12512, -1, 12464, 12521, 12512, 12488, 12531, -1, + 12463, 12523, 12476, 12452, 12525, -1, 12463, 12525, + 12540, 12493, -1, 12465, 12540, 12473, -1, 12467, + 12523, 12490, -1, 12467, 12540, 12509, -1, 12469, + 12452, 12463, 12523, -1, 12469, 12531, 12481, 12540, + 12512, -1, 12471, 12522, 12531, 12464, -1, 12475, + 12531, 12481, -1, 12475, 12531, 12488, -1, 12480, + 12540, 12473, -1, 12487, 12471, -1, 12489, 12523, + -1, 12488, 12531, -1, 12490, 12494, -1, 12494, + 12483, 12488, -1, 12495, 12452, 12484, -1, 12497, + 12540, 12475, 12531, 12488, -1, 12497, 12540, 12484, + -1, 12496, 12540, 12524, 12523, -1, 12500, 12450, + 12473, 12488, 12523, -1, 12500, 12463, 12523, -1, + 12500, 12467, -1, 12499, 12523, -1, 12501, 12449, + 12521, 12483, 12489, -1, 12501, 12451, 12540, 12488, + -1, 12502, 12483, 12471, 12455, 12523, -1, 12501, + 12521, 12531, -1, 12504, 12463, 12479, 12540, 12523, + -1, 12506, 12477, -1, 12506, 12491, 12498, -1, + 12504, 12523, 12484, -1, 12506, 12531, 12473, -1, + 12506, 12540, 12472, -1, 12505, 12540, 12479, -1, + 12509, 12452, 12531, 12488, -1, 12508, 12523, 12488, + -1, 12507, 12531, -1, 12509, 12531, 12489, -1, + 12507, 12540, 12523, -1, 12507, 12540, 12531, -1, + 12510, 12452, 12463, 12525, -1, 12510, 12452, 12523, + -1, 12510, 12483, 12495, -1, 12510, 12523, 12463, + -1, 12510, 12531, 12471, 12519, 12531, -1, 12511, + 12463, 12525, 12531, -1, 12511, 12522, -1, 12511, + 12522, 12496, 12540, 12523, -1, 12513, 12460, -1, + 12513, 12460, 12488, 12531, -1, 12513, 12540, 12488, + 12523, -1, 12516, 12540, 12489, -1, 12516, 12540, + 12523, -1, 12518, 12450, 12531, -1, 12522, 12483, + 12488, 12523, -1, 12522, 12521, -1, 12523, 12500, + 12540, -1, 12523, 12540, 12502, 12523, -1, 12524, + 12512, -1, 12524, 12531, 12488, 12466, 12531, -1, + 12527, 12483, 12488, -1, 48, 28857, -1, 49, + 28857, -1, 50, 28857, -1, 51, 28857, -1, + 52, 28857, -1, 53, 28857, -1, 54, 28857, + -1, 55, 28857, -1, 56, 28857, -1, 57, + 28857, -1, 49, 48, 28857, -1, 49, 49, + 28857, -1, 49, 50, 28857, -1, 49, 51, + 28857, -1, 49, 52, 28857, -1, 49, 53, + 28857, -1, 49, 54, 28857, -1, 49, 55, + 28857, -1, 49, 56, 28857, -1, 49, 57, + 28857, -1, 50, 48, 28857, -1, 50, 49, + 28857, -1, 50, 50, 28857, -1, 50, 51, + 28857, -1, 50, 52, 28857, -1, 104, 80, + 97, -1, 100, 97, -1, 65, 85, -1, + 98, 97, 114, -1, 111, 86, -1, 112, + 99, -1, 100, 109, -1, 100, 109, 178, + -1, 100, 109, 179, -1, 73, 85, -1, + 24179, 25104, -1, 26157, 21644, -1, 22823, 27491, + -1, 26126, 27835, -1, 26666, 24335, 20250, 31038, + -1, 112, 65, -1, 110, 65, -1, 956, + 65, -1, 109, 65, -1, 107, 65, -1, + 75, 66, -1, 77, 66, -1, 71, 66, + -1, 99, 97, 108, -1, 107, 99, 97, + 108, -1, 112, 70, -1, 110, 70, -1, + 956, 70, -1, 956, 103, -1, 109, 103, + -1, 107, 103, -1, 72, 122, -1, 107, + 72, 122, -1, 77, 72, 122, -1, 71, + 72, 122, -1, 84, 72, 122, -1, 956, + 8467, -1, 109, 8467, -1, 100, 8467, -1, + 107, 8467, -1, 102, 109, -1, 110, 109, + -1, 956, 109, -1, 109, 109, -1, 99, + 109, -1, 107, 109, -1, 109, 109, 178, + -1, 99, 109, 178, -1, 109, 178, -1, + 107, 109, 178, -1, 109, 109, 179, -1, + 99, 109, 179, -1, 109, 179, -1, 107, + 109, 179, -1, 109, 8725, 115, -1, 109, + 8725, 115, 178, -1, 80, 97, -1, 107, + 80, 97, -1, 77, 80, 97, -1, 71, + 80, 97, -1, 114, 97, 100, -1, 114, + 97, 100, 8725, 115, -1, 114, 97, 100, + 8725, 115, 178, -1, 112, 115, -1, 110, + 115, -1, 956, 115, -1, 109, 115, -1, + 112, 86, -1, 110, 86, -1, 956, 86, + -1, 109, 86, -1, 107, 86, -1, 77, + 86, -1, 112, 87, -1, 110, 87, -1, + 956, 87, -1, 109, 87, -1, 107, 87, + -1, 77, 87, -1, 107, 937, -1, 77, + 937, -1, 97, 46, 109, 46, -1, 66, + 113, -1, 99, 99, -1, 99, 100, -1, + 67, 8725, 107, 103, -1, 67, 111, 46, + -1, 100, 66, -1, 71, 121, -1, 104, + 97, -1, 72, 80, -1, 105, 110, -1, + 75, 75, -1, 75, 77, -1, 107, 116, + -1, 108, 109, -1, 108, 110, -1, 108, + 111, 103, -1, 108, 120, -1, 109, 98, + -1, 109, 105, 108, -1, 109, 111, 108, + -1, 80, 72, -1, 112, 46, 109, 46, + -1, 80, 80, 77, -1, 80, 82, -1, + 115, 114, -1, 83, 118, -1, 87, 98, + -1, 86, 8725, 109, -1, 65, 8725, 109, + -1, 49, 26085, -1, 50, 26085, -1, 51, + 26085, -1, 52, 26085, -1, 53, 26085, -1, + 54, 26085, -1, 55, 26085, -1, 56, 26085, + -1, 57, 26085, -1, 49, 48, 26085, -1, + 49, 49, 26085, -1, 49, 50, 26085, -1, + 49, 51, 26085, -1, 49, 52, 26085, -1, + 49, 53, 26085, -1, 49, 54, 26085, -1, + 49, 55, 26085, -1, 49, 56, 26085, -1, + 49, 57, 26085, -1, 50, 48, 26085, -1, + 50, 49, 26085, -1, 50, 50, 26085, -1, + 50, 51, 26085, -1, 50, 52, 26085, -1, + 50, 53, 26085, -1, 50, 54, 26085, -1, + 50, 55, 26085, -1, 50, 56, 26085, -1, + 50, 57, 26085, -1, 51, 48, 26085, -1, + 51, 49, 26085, -1, 103, 97, 108, -1, + 35912, -1, 26356, -1, 36040, -1, 28369, -1, + 20018, -1, 21477, -1, 22865, -1, 21895, -1, + 22856, -1, 25078, -1, 30313, -1, 32645, -1, + 34367, -1, 34746, -1, 35064, -1, 37007, -1, + 27138, -1, 27931, -1, 28889, -1, 29662, -1, + 33853, -1, 37226, -1, 39409, -1, 20098, -1, + 21365, -1, 27396, -1, 29211, -1, 34349, -1, + 40478, -1, 23888, -1, 28651, -1, 34253, -1, + 35172, -1, 25289, -1, 33240, -1, 34847, -1, + 24266, -1, 26391, -1, 28010, -1, 29436, -1, + 37070, -1, 20358, -1, 20919, -1, 21214, -1, + 25796, -1, 27347, -1, 29200, -1, 30439, -1, + 34310, -1, 34396, -1, 36335, -1, 38706, -1, + 39791, -1, 40442, -1, 30860, -1, 31103, -1, + 32160, -1, 33737, -1, 37636, -1, 35542, -1, + 22751, -1, 24324, -1, 31840, -1, 32894, -1, + 29282, -1, 30922, -1, 36034, -1, 38647, -1, + 22744, -1, 23650, -1, 27155, -1, 28122, -1, + 28431, -1, 32047, -1, 32311, -1, 38475, -1, + 21202, -1, 32907, -1, 20956, -1, 20940, -1, + 31260, -1, 32190, -1, 33777, -1, 38517, -1, + 35712, -1, 25295, -1, 35582, -1, 20025, -1, + 23527, -1, 24594, -1, 29575, -1, 30064, -1, + 21271, -1, 30971, -1, 20415, -1, 24489, -1, + 19981, -1, 27852, -1, 25976, -1, 32034, -1, + 21443, -1, 22622, -1, 30465, -1, 33865, -1, + 35498, -1, 27578, -1, 27784, -1, 25342, -1, + 33509, -1, 25504, -1, 30053, -1, 20142, -1, + 20841, -1, 20937, -1, 26753, -1, 31975, -1, + 33391, -1, 35538, -1, 37327, -1, 21237, -1, + 21570, -1, 24300, -1, 26053, -1, 28670, -1, + 31018, -1, 38317, -1, 39530, -1, 40599, -1, + 40654, -1, 26310, -1, 27511, -1, 36706, -1, + 24180, -1, 24976, -1, 25088, -1, 25754, -1, + 28451, -1, 29001, -1, 29833, -1, 31178, -1, + 32244, -1, 32879, -1, 36646, -1, 34030, -1, + 36899, -1, 37706, -1, 21015, -1, 21155, -1, + 21693, -1, 28872, -1, 35010, -1, 24265, -1, + 24565, -1, 25467, -1, 27566, -1, 31806, -1, + 29557, -1, 20196, -1, 22265, -1, 23994, -1, + 24604, -1, 29618, -1, 29801, -1, 32666, -1, + 32838, -1, 37428, -1, 38646, -1, 38728, -1, + 38936, -1, 20363, -1, 31150, -1, 37300, -1, + 38584, -1, 24801, -1, 20102, -1, 20698, -1, + 23534, -1, 23615, -1, 26009, -1, 29134, -1, + 30274, -1, 34044, -1, 36988, -1, 26248, -1, + 38446, -1, 21129, -1, 26491, -1, 26611, -1, + 27969, -1, 28316, -1, 29705, -1, 30041, -1, + 30827, -1, 32016, -1, 39006, -1, 25134, -1, + 38520, -1, 20523, -1, 23833, -1, 28138, -1, + 36650, -1, 24459, -1, 24900, -1, 26647, -1, + 38534, -1, 21033, -1, 21519, -1, 23653, -1, + 26131, -1, 26446, -1, 26792, -1, 27877, -1, + 29702, -1, 30178, -1, 32633, -1, 35023, -1, + 35041, -1, 38626, -1, 21311, -1, 28346, -1, + 21533, -1, 29136, -1, 29848, -1, 34298, -1, + 38563, -1, 40023, -1, 40607, -1, 26519, -1, + 28107, -1, 33256, -1, 31520, -1, 31890, -1, + 29376, -1, 28825, -1, 35672, -1, 20160, -1, + 33590, -1, 21050, -1, 20999, -1, 24230, -1, + 25299, -1, 31958, -1, 23429, -1, 27934, -1, + 26292, -1, 36667, -1, 38477, -1, 24275, -1, + 20800, -1, 21952, -1, 22618, -1, 26228, -1, + 20958, -1, 29482, -1, 30410, -1, 31036, -1, + 31070, -1, 31077, -1, 31119, -1, 38742, -1, + 31934, -1, 34322, -1, 35576, -1, 36920, -1, + 37117, -1, 39151, -1, 39164, -1, 39208, -1, + 40372, -1, 20398, -1, 20711, -1, 20813, -1, + 21193, -1, 21220, -1, 21329, -1, 21917, -1, + 22022, -1, 22120, -1, 22592, -1, 22696, -1, + 23652, -1, 24724, -1, 24936, -1, 24974, -1, + 25074, -1, 25935, -1, 26082, -1, 26257, -1, + 26757, -1, 28023, -1, 28186, -1, 28450, -1, + 29038, -1, 29227, -1, 29730, -1, 30865, -1, + 31049, -1, 31048, -1, 31056, -1, 31062, -1, + 31117, -1, 31118, -1, 31296, -1, 31361, -1, + 31680, -1, 32265, -1, 32321, -1, 32626, -1, + 32773, -1, 33261, -1, 33401, -1, 33879, -1, + 35088, -1, 35222, -1, 35585, -1, 35641, -1, + 36051, -1, 36104, -1, 36790, -1, 38627, -1, + 38911, -1, 38971, -1, 20006, -1, 20917, -1, + 20840, -1, 20352, -1, 20805, -1, 20864, -1, + 21191, -1, 21242, -1, 21845, -1, 21913, -1, + 21986, -1, 22707, -1, 22852, -1, 22868, -1, + 23138, -1, 23336, -1, 24274, -1, 24281, -1, + 24425, -1, 24493, -1, 24792, -1, 24910, -1, + 24840, -1, 24928, -1, 25140, -1, 25540, -1, + 25628, -1, 25682, -1, 25942, -1, 26395, -1, + 26454, -1, 28379, -1, 28363, -1, 28702, -1, + 30631, -1, 29237, -1, 29359, -1, 29809, -1, + 29958, -1, 30011, -1, 30237, -1, 30239, -1, + 30427, -1, 30452, -1, 30538, -1, 30528, -1, + 30924, -1, 31409, -1, 31867, -1, 32091, -1, + 32574, -1, 33618, -1, 33775, -1, 34681, -1, + 35137, -1, 35206, -1, 35519, -1, 35531, -1, + 35565, -1, 35722, -1, 36664, -1, 36978, -1, + 37273, -1, 37494, -1, 38524, -1, 38875, -1, + 38923, -1, 39698, -1, 141386, -1, 141380, -1, + 144341, -1, 15261, -1, 16408, -1, 16441, -1, + 152137, -1, 154832, -1, 163539, -1, 40771, -1, + 40846, -1, 102, 102, -1, 102, 105, -1, + 102, 108, -1, 102, 102, 105, -1, 102, + 102, 108, -1, 383, 116, -1, 115, 116, + -1, 1396, 1398, -1, 1396, 1381, -1, 1396, + 1387, -1, 1406, 1398, -1, 1396, 1389, -1, + 1497, 1460, -1, 1522, 1463, -1, 1506, -1, + 1492, -1, 1499, -1, 1500, -1, 1501, -1, + 1512, -1, 1514, -1, 1513, 1473, -1, 1513, + 1474, -1, 64329, 1473, -1, 64329, 1474, -1, + 1488, 1463, -1, 1488, 1464, -1, 1488, 1468, + -1, 1489, 1468, -1, 1490, 1468, -1, 1491, + 1468, -1, 1492, 1468, -1, 1493, 1468, -1, + 1494, 1468, -1, 1496, 1468, -1, 1497, 1468, + -1, 1498, 1468, -1, 1499, 1468, -1, 1500, + 1468, -1, 1502, 1468, -1, 1504, 1468, -1, + 1505, 1468, -1, 1507, 1468, -1, 1508, 1468, + -1, 1510, 1468, -1, 1511, 1468, -1, 1512, + 1468, -1, 1513, 1468, -1, 1514, 1468, -1, + 1493, 1465, -1, 1489, 1471, -1, 1499, 1471, + -1, 1508, 1471, -1, 1488, 1500, -1, 1649, + -1, 1659, -1, 1662, -1, 1664, -1, 1658, + -1, 1663, -1, 1657, -1, 1700, -1, 1702, + -1, 1668, -1, 1667, -1, 1670, -1, 1671, + -1, 1677, -1, 1676, -1, 1678, -1, 1672, + -1, 1688, -1, 1681, -1, 1705, -1, 1711, + -1, 1715, -1, 1713, -1, 1722, -1, 1723, + -1, 1728, -1, 1729, -1, 1726, -1, 1746, + -1, 1747, -1, 1709, -1, 1735, -1, 1734, + -1, 1736, -1, 1655, -1, 1739, -1, 1733, + -1, 1737, -1, 1744, -1, 1609, -1, 1574, + 1575, -1, 1574, 1749, -1, 1574, 1608, -1, + 1574, 1735, -1, 1574, 1734, -1, 1574, 1736, + -1, 1574, 1744, -1, 1574, 1609, -1, 1740, + -1, 1574, 1580, -1, 1574, 1581, -1, 1574, + 1605, -1, 1574, 1610, -1, 1576, 1580, -1, + 1576, 1581, -1, 1576, 1582, -1, 1576, 1605, + -1, 1576, 1609, -1, 1576, 1610, -1, 1578, + 1580, -1, 1578, 1581, -1, 1578, 1582, -1, + 1578, 1605, -1, 1578, 1609, -1, 1578, 1610, + -1, 1579, 1580, -1, 1579, 1605, -1, 1579, + 1609, -1, 1579, 1610, -1, 1580, 1581, -1, + 1580, 1605, -1, 1581, 1580, -1, 1581, 1605, + -1, 1582, 1580, -1, 1582, 1581, -1, 1582, + 1605, -1, 1587, 1580, -1, 1587, 1581, -1, + 1587, 1582, -1, 1587, 1605, -1, 1589, 1581, + -1, 1589, 1605, -1, 1590, 1580, -1, 1590, + 1581, -1, 1590, 1582, -1, 1590, 1605, -1, + 1591, 1581, -1, 1591, 1605, -1, 1592, 1605, + -1, 1593, 1580, -1, 1593, 1605, -1, 1594, + 1580, -1, 1594, 1605, -1, 1601, 1580, -1, + 1601, 1581, -1, 1601, 1582, -1, 1601, 1605, + -1, 1601, 1609, -1, 1601, 1610, -1, 1602, + 1581, -1, 1602, 1605, -1, 1602, 1609, -1, + 1602, 1610, -1, 1603, 1575, -1, 1603, 1580, + -1, 1603, 1581, -1, 1603, 1582, -1, 1603, + 1604, -1, 1603, 1605, -1, 1603, 1609, -1, + 1603, 1610, -1, 1604, 1580, -1, 1604, 1581, + -1, 1604, 1582, -1, 1604, 1605, -1, 1604, + 1609, -1, 1604, 1610, -1, 1605, 1580, -1, + 1605, 1581, -1, 1605, 1582, -1, 1605, 1605, + -1, 1605, 1609, -1, 1605, 1610, -1, 1606, + 1580, -1, 1606, 1581, -1, 1606, 1582, -1, + 1606, 1605, -1, 1606, 1609, -1, 1606, 1610, + -1, 1607, 1580, -1, 1607, 1605, -1, 1607, + 1609, -1, 1607, 1610, -1, 1610, 1580, -1, + 1610, 1581, -1, 1610, 1582, -1, 1610, 1605, + -1, 1610, 1609, -1, 1610, 1610, -1, 1584, + 1648, -1, 1585, 1648, -1, 1609, 1648, -1, + 32, 1612, 1617, -1, 32, 1613, 1617, -1, + 32, 1614, 1617, -1, 32, 1615, 1617, -1, + 32, 1616, 1617, -1, 32, 1617, 1648, -1, + 1574, 1585, -1, 1574, 1586, -1, 1574, 1606, + -1, 1576, 1585, -1, 1576, 1586, -1, 1576, + 1606, -1, 1578, 1585, -1, 1578, 1586, -1, + 1578, 1606, -1, 1579, 1585, -1, 1579, 1586, + -1, 1579, 1606, -1, 1605, 1575, -1, 1606, + 1585, -1, 1606, 1586, -1, 1606, 1606, -1, + 1610, 1585, -1, 1610, 1586, -1, 1610, 1606, + -1, 1574, 1582, -1, 1574, 1607, -1, 1576, + 1607, -1, 1578, 1607, -1, 1589, 1582, -1, + 1604, 1607, -1, 1606, 1607, -1, 1607, 1648, + -1, 1610, 1607, -1, 1579, 1607, -1, 1587, + 1607, -1, 1588, 1605, -1, 1588, 1607, -1, + 1600, 1614, 1617, -1, 1600, 1615, 1617, -1, + 1600, 1616, 1617, -1, 1591, 1609, -1, 1591, + 1610, -1, 1593, 1609, -1, 1593, 1610, -1, + 1594, 1609, -1, 1594, 1610, -1, 1587, 1609, + -1, 1587, 1610, -1, 1588, 1609, -1, 1588, + 1610, -1, 1581, 1609, -1, 1581, 1610, -1, + 1580, 1609, -1, 1580, 1610, -1, 1582, 1609, + -1, 1582, 1610, -1, 1589, 1609, -1, 1589, + 1610, -1, 1590, 1609, -1, 1590, 1610, -1, + 1588, 1580, -1, 1588, 1581, -1, 1588, 1582, + -1, 1588, 1585, -1, 1587, 1585, -1, 1589, + 1585, -1, 1590, 1585, -1, 1575, 1611, -1, + 1578, 1580, 1605, -1, 1578, 1581, 1580, -1, + 1578, 1581, 1605, -1, 1578, 1582, 1605, -1, + 1578, 1605, 1580, -1, 1578, 1605, 1581, -1, + 1578, 1605, 1582, -1, 1580, 1605, 1581, -1, + 1581, 1605, 1610, -1, 1581, 1605, 1609, -1, + 1587, 1581, 1580, -1, 1587, 1580, 1581, -1, + 1587, 1580, 1609, -1, 1587, 1605, 1581, -1, + 1587, 1605, 1580, -1, 1587, 1605, 1605, -1, + 1589, 1581, 1581, -1, 1589, 1605, 1605, -1, + 1588, 1581, 1605, -1, 1588, 1580, 1610, -1, + 1588, 1605, 1582, -1, 1588, 1605, 1605, -1, + 1590, 1581, 1609, -1, 1590, 1582, 1605, -1, + 1591, 1605, 1581, -1, 1591, 1605, 1605, -1, + 1591, 1605, 1610, -1, 1593, 1580, 1605, -1, + 1593, 1605, 1605, -1, 1593, 1605, 1609, -1, + 1594, 1605, 1605, -1, 1594, 1605, 1610, -1, + 1594, 1605, 1609, -1, 1601, 1582, 1605, -1, + 1602, 1605, 1581, -1, 1602, 1605, 1605, -1, + 1604, 1581, 1605, -1, 1604, 1581, 1610, -1, + 1604, 1581, 1609, -1, 1604, 1580, 1580, -1, + 1604, 1582, 1605, -1, 1604, 1605, 1581, -1, + 1605, 1581, 1580, -1, 1605, 1581, 1605, -1, + 1605, 1581, 1610, -1, 1605, 1580, 1581, -1, + 1605, 1580, 1605, -1, 1605, 1582, 1580, -1, + 1605, 1582, 1605, -1, 1605, 1580, 1582, -1, + 1607, 1605, 1580, -1, 1607, 1605, 1605, -1, + 1606, 1581, 1605, -1, 1606, 1581, 1609, -1, + 1606, 1580, 1605, -1, 1606, 1580, 1609, -1, + 1606, 1605, 1610, -1, 1606, 1605, 1609, -1, + 1610, 1605, 1605, -1, 1576, 1582, 1610, -1, + 1578, 1580, 1610, -1, 1578, 1580, 1609, -1, + 1578, 1582, 1610, -1, 1578, 1582, 1609, -1, + 1578, 1605, 1610, -1, 1578, 1605, 1609, -1, + 1580, 1605, 1610, -1, 1580, 1581, 1609, -1, + 1580, 1605, 1609, -1, 1587, 1582, 1609, -1, + 1589, 1581, 1610, -1, 1588, 1581, 1610, -1, + 1590, 1581, 1610, -1, 1604, 1580, 1610, -1, + 1604, 1605, 1610, -1, 1610, 1581, 1610, -1, + 1610, 1580, 1610, -1, 1610, 1605, 1610, -1, + 1605, 1605, 1610, -1, 1602, 1605, 1610, -1, + 1606, 1581, 1610, -1, 1593, 1605, 1610, -1, + 1603, 1605, 1610, -1, 1606, 1580, 1581, -1, + 1605, 1582, 1610, -1, 1604, 1580, 1605, -1, + 1603, 1605, 1605, -1, 1580, 1581, 1610, -1, + 1581, 1580, 1610, -1, 1605, 1580, 1610, -1, + 1601, 1605, 1610, -1, 1576, 1581, 1610, -1, + 1587, 1582, 1610, -1, 1606, 1580, 1610, -1, + 1589, 1604, 1746, -1, 1602, 1604, 1746, -1, + 1575, 1604, 1604, 1607, -1, 1575, 1603, 1576, + 1585, -1, 1605, 1581, 1605, 1583, -1, 1589, + 1604, 1593, 1605, -1, 1585, 1587, 1608, 1604, + -1, 1593, 1604, 1610, 1607, -1, 1608, 1587, + 1604, 1605, -1, 1589, 1604, 1609, -1, 1589, + 1604, 1609, 32, 1575, 1604, 1604, 1607, 32, + 1593, 1604, 1610, 1607, 32, 1608, 1587, 1604, + 1605, -1, 1580, 1604, 32, 1580, 1604, 1575, + 1604, 1607, -1, 1585, 1740, 1575, 1604, -1, + 44, -1, 12289, -1, 12290, -1, 58, -1, + 33, -1, 63, -1, 12310, -1, 12311, -1, + 8230, -1, 8229, -1, 8212, -1, 8211, -1, + 95, -1, 123, -1, 125, -1, 12308, -1, + 12309, -1, 12304, -1, 12305, -1, 12298, -1, + 12299, -1, 12300, -1, 12301, -1, 12302, -1, + 12303, -1, 91, -1, 93, -1, 8254, -1, + 35, -1, 38, -1, 42, -1, 45, -1, + 60, -1, 62, -1, 92, -1, 36, -1, + 37, -1, 64, -1, 32, 1611, -1, 1600, + 1611, -1, 32, 1612, -1, 32, 1613, -1, + 32, 1614, -1, 1600, 1614, -1, 32, 1615, + -1, 1600, 1615, -1, 32, 1616, -1, 1600, + 1616, -1, 32, 1617, -1, 1600, 1617, -1, + 32, 1618, -1, 1600, 1618, -1, 1569, -1, + 1570, -1, 1571, -1, 1572, -1, 1573, -1, + 1574, -1, 1575, -1, 1576, -1, 1577, -1, + 1578, -1, 1579, -1, 1580, -1, 1581, -1, + 1582, -1, 1583, -1, 1584, -1, 1585, -1, + 1586, -1, 1587, -1, 1588, -1, 1589, -1, + 1590, -1, 1591, -1, 1592, -1, 1593, -1, + 1594, -1, 1601, -1, 1602, -1, 1603, -1, + 1604, -1, 1605, -1, 1606, -1, 1607, -1, + 1608, -1, 1610, -1, 1604, 1570, -1, 1604, + 1571, -1, 1604, 1573, -1, 1604, 1575, -1, + 34, -1, 39, -1, 47, -1, 65345, -1, + 65346, -1, 65347, -1, 65348, -1, 65349, -1, + 65350, -1, 65351, -1, 65352, -1, 65353, -1, + 65354, -1, 65355, -1, 65356, -1, 65357, -1, + 65358, -1, 65359, -1, 65360, -1, 65361, -1, + 65362, -1, 65363, -1, 65364, -1, 65365, -1, + 65366, -1, 65367, -1, 65368, -1, 65369, -1, + 65370, -1, 94, -1, 124, -1, 126, -1, + 10629, -1, 10630, -1, 12539, -1, 12449, -1, + 12451, -1, 12453, -1, 12455, -1, 12457, -1, + 12515, -1, 12517, -1, 12519, -1, 12483, -1, + 12540, -1, 12531, -1, 12441, -1, 12442, -1, + 12644, -1, 12593, -1, 12594, -1, 12595, -1, + 12596, -1, 12597, -1, 12598, -1, 12599, -1, + 12600, -1, 12601, -1, 12602, -1, 12603, -1, + 12604, -1, 12605, -1, 12606, -1, 12607, -1, + 12608, -1, 12609, -1, 12610, -1, 12611, -1, + 12612, -1, 12613, -1, 12614, -1, 12615, -1, + 12616, -1, 12617, -1, 12618, -1, 12619, -1, + 12620, -1, 12621, -1, 12622, -1, 12623, -1, + 12624, -1, 12625, -1, 12626, -1, 12627, -1, + 12628, -1, 12629, -1, 12630, -1, 12631, -1, + 12632, -1, 12633, -1, 12634, -1, 12635, -1, + 12636, -1, 12637, -1, 12638, -1, 12639, -1, + 12640, -1, 12641, -1, 12642, -1, 12643, -1, + 162, -1, 163, -1, 172, -1, 175, -1, + 166, -1, 165, -1, 8361, -1, 9474, -1, + 8592, -1, 8593, -1, 8594, -1, 8595, -1, + 9632, -1, 9675, -1, 66600, -1, 66601, -1, + 66602, -1, 66603, -1, 66604, -1, 66605, -1, + 66606, -1, 66607, -1, 66608, -1, 66609, -1, + 66610, -1, 66611, -1, 66612, -1, 66613, -1, + 66614, -1, 66615, -1, 66616, -1, 66617, -1, + 66618, -1, 66619, -1, 66620, -1, 66621, -1, + 66622, -1, 66623, -1, 66624, -1, 66625, -1, + 66626, -1, 66627, -1, 66628, -1, 66629, -1, + 66630, -1, 66631, -1, 66632, -1, 66633, -1, + 66634, -1, 66635, -1, 66636, -1, 66637, -1, + 66638, -1, 66639, -1, 119127, 119141, -1, 119128, + 119141, -1, 119135, 119150, -1, 119135, 119151, -1, + 119135, 119152, -1, 119135, 119153, -1, 119135, 119154, + -1, 119225, 119141, -1, 119226, 119141, -1, 119227, + 119150, -1, 119228, 119150, -1, 119227, 119151, -1, + 119228, 119151, -1, 305, -1, 567, -1, 913, + -1, 914, -1, 916, -1, 917, -1, 918, + -1, 919, -1, 921, -1, 922, -1, 923, + -1, 924, -1, 925, -1, 926, -1, 927, + -1, 929, -1, 1012, -1, 932, -1, 934, + -1, 935, -1, 936, -1, 8711, -1, 8706, + -1, 1013, -1, 977, -1, 1008, -1, 981, + -1, 1009, -1, 982, -1, 988, -1, 20029, + -1, 20024, -1, 20033, -1, 131362, -1, 20320, + -1, 20411, -1, 20482, -1, 20602, -1, 20633, + -1, 20687, -1, 13470, -1, 132666, -1, 20820, + -1, 20836, -1, 20855, -1, 132380, -1, 13497, + -1, 20839, -1, 20877, -1, 132427, -1, 20887, + -1, 20900, -1, 20172, -1, 20908, -1, 168415, + -1, 20995, -1, 13535, -1, 21051, -1, 21062, + -1, 21106, -1, 21111, -1, 13589, -1, 21253, + -1, 21254, -1, 21321, -1, 21338, -1, 21363, + -1, 21373, -1, 21375, -1, 133676, -1, 28784, + -1, 21450, -1, 21471, -1, 133987, -1, 21483, + -1, 21489, -1, 21510, -1, 21662, -1, 21560, + -1, 21576, -1, 21608, -1, 21666, -1, 21750, + -1, 21776, -1, 21843, -1, 21859, -1, 21892, + -1, 21931, -1, 21939, -1, 21954, -1, 22294, + -1, 22295, -1, 22097, -1, 22132, -1, 22766, + -1, 22478, -1, 22516, -1, 22541, -1, 22411, + -1, 22578, -1, 22577, -1, 22700, -1, 136420, + -1, 22770, -1, 22775, -1, 22790, -1, 22810, + -1, 22818, -1, 22882, -1, 136872, -1, 136938, + -1, 23020, -1, 23067, -1, 23079, -1, 23000, + -1, 23142, -1, 14062, -1, 14076, -1, 23304, + -1, 23358, -1, 137672, -1, 23491, -1, 23512, + -1, 23539, -1, 138008, -1, 23551, -1, 23558, + -1, 24403, -1, 14209, -1, 23648, -1, 23744, + -1, 23693, -1, 138724, -1, 23875, -1, 138726, + -1, 23918, -1, 23915, -1, 23932, -1, 24033, + -1, 24034, -1, 14383, -1, 24061, -1, 24104, + -1, 24125, -1, 24169, -1, 14434, -1, 139651, + -1, 14460, -1, 24240, -1, 24243, -1, 24246, + -1, 172946, -1, 140081, -1, 33281, -1, 24354, + -1, 14535, -1, 144056, -1, 156122, -1, 24418, + -1, 24427, -1, 14563, -1, 24474, -1, 24525, + -1, 24535, -1, 24569, -1, 24705, -1, 14650, + -1, 14620, -1, 141012, -1, 24775, -1, 24904, + -1, 24908, -1, 24954, -1, 25010, -1, 24996, + -1, 25007, -1, 25054, -1, 25104, -1, 25115, + -1, 25181, -1, 25265, -1, 25300, -1, 25424, + -1, 142092, -1, 25405, -1, 25340, -1, 25448, + -1, 25475, -1, 25572, -1, 142321, -1, 25634, + -1, 25541, -1, 25513, -1, 14894, -1, 25705, + -1, 25726, -1, 25757, -1, 25719, -1, 14956, + -1, 25964, -1, 143370, -1, 26083, -1, 26360, + -1, 26185, -1, 15129, -1, 15112, -1, 15076, + -1, 20882, -1, 20885, -1, 26368, -1, 26268, + -1, 32941, -1, 17369, -1, 26401, -1, 26462, + -1, 26451, -1, 144323, -1, 15177, -1, 26618, + -1, 26501, -1, 26706, -1, 144493, -1, 26766, + -1, 26655, -1, 26900, -1, 26946, -1, 27043, + -1, 27114, -1, 27304, -1, 145059, -1, 27355, + -1, 15384, -1, 27425, -1, 145575, -1, 27476, + -1, 15438, -1, 27506, -1, 27551, -1, 27579, + -1, 146061, -1, 138507, -1, 146170, -1, 27726, + -1, 146620, -1, 27839, -1, 27853, -1, 27751, + -1, 27926, -1, 27966, -1, 28009, -1, 28024, + -1, 28037, -1, 146718, -1, 27956, -1, 28207, + -1, 28270, -1, 15667, -1, 28359, -1, 147153, + -1, 28153, -1, 28526, -1, 147294, -1, 147342, + -1, 28614, -1, 28729, -1, 28699, -1, 15766, + -1, 28746, -1, 28797, -1, 28791, -1, 28845, + -1, 132389, -1, 28997, -1, 148067, -1, 29084, + -1, 148395, -1, 29224, -1, 29264, -1, 149000, + -1, 29312, -1, 29333, -1, 149301, -1, 149524, + -1, 29562, -1, 29579, -1, 16044, -1, 29605, + -1, 16056, -1, 29767, -1, 29788, -1, 29829, + -1, 29898, -1, 16155, -1, 29988, -1, 150582, + -1, 30014, -1, 150674, -1, 139679, -1, 30224, + -1, 151457, -1, 151480, -1, 151620, -1, 16380, + -1, 16392, -1, 151795, -1, 151794, -1, 151833, + -1, 151859, -1, 30494, -1, 30495, -1, 30603, + -1, 16454, -1, 16534, -1, 152605, -1, 30798, + -1, 16611, -1, 153126, -1, 153242, -1, 153285, + -1, 31211, -1, 16687, -1, 31306, -1, 31311, + -1, 153980, -1, 154279, -1, 31470, -1, 16898, + -1, 154539, -1, 31686, -1, 31689, -1, 16935, + -1, 154752, -1, 31954, -1, 17056, -1, 31976, + -1, 31971, -1, 32000, -1, 155526, -1, 32099, + -1, 17153, -1, 32199, -1, 32258, -1, 32325, + -1, 17204, -1, 156200, -1, 156231, -1, 17241, + -1, 156377, -1, 32634, -1, 156478, -1, 32661, + -1, 32762, -1, 156890, -1, 156963, -1, 32864, + -1, 157096, -1, 32880, -1, 144223, -1, 17365, + -1, 32946, -1, 33027, -1, 17419, -1, 33086, + -1, 23221, -1, 157607, -1, 157621, -1, 144275, + -1, 144284, -1, 33284, -1, 36766, -1, 17515, + -1, 33425, -1, 33419, -1, 33437, -1, 21171, + -1, 33457, -1, 33459, -1, 33469, -1, 33510, + -1, 158524, -1, 33565, -1, 33635, -1, 33709, + -1, 33571, -1, 33725, -1, 33767, -1, 33619, + -1, 33738, -1, 33740, -1, 33756, -1, 158774, + -1, 159083, -1, 158933, -1, 17707, -1, 34033, + -1, 34035, -1, 34070, -1, 160714, -1, 34148, + -1, 159532, -1, 17757, -1, 17761, -1, 159665, + -1, 159954, -1, 17771, -1, 34384, -1, 34407, + -1, 34409, -1, 34473, -1, 34440, -1, 34574, + -1, 34530, -1, 34600, -1, 34667, -1, 34694, + -1, 17879, -1, 34785, -1, 34817, -1, 17913, + -1, 34912, -1, 161383, -1, 35031, -1, 35038, + -1, 17973, -1, 35066, -1, 13499, -1, 161966, + -1, 162150, -1, 18110, -1, 18119, -1, 35488, + -1, 162984, -1, 36011, -1, 36033, -1, 36123, + -1, 36215, -1, 163631, -1, 133124, -1, 36299, + -1, 36284, -1, 36336, -1, 133342, -1, 36564, + -1, 165330, -1, 165357, -1, 37012, -1, 37105, + -1, 37137, -1, 165678, -1, 37147, -1, 37432, + -1, 37591, -1, 37592, -1, 37500, -1, 37881, + -1, 37909, -1, 166906, -1, 38283, -1, 18837, + -1, 38327, -1, 167287, -1, 18918, -1, 38595, + -1, 23986, -1, 38691, -1, 168261, -1, 168474, + -1, 19054, -1, 19062, -1, 38880, -1, 168970, + -1, 19122, -1, 169110, -1, 38953, -1, 169398, + -1, 39138, -1, 19251, -1, 39209, -1, 39335, + -1, 39362, -1, 39422, -1, 19406, -1, 170800, + -1, 40000, -1, 40189, -1, 19662, -1, 19693, + -1, 40295, -1, 172238, -1, 19704, -1, 172293, + -1, 172558, -1, 172689, -1, 19798, -1, 40702, + -1, 40709, -1, 40719, -1, 40726, -1, 173568, + -1, }; + +const uint16_t utf8proc_stage1table[] = { + 0, 256, 512, 768, 1024, 1280, 1536, + 1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584, + 3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632, + 5888, 6144, 6400, 6656, 6912, 2048, 7168, 7424, + 7680, 7936, 8192, 8448, 8704, 8960, 9216, 9472, + 9728, 9984, 10240, 10496, 10752, 11008, 11264, 11520, + 11776, 12032, 12288, 12544, 12800, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 13056, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 13312, 13568, 5376, 5376, 5376, 13824, 2048, 2048, + 14080, 14336, 2048, 2048, 2048, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 14592, 14848, 14848, 14848, 14848, 14848, 14848, 14848, + 14848, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15360, 15616, 15872, 16128, 16384, 16640, + 16896, 17152, 17408, 2048, 17664, 17920, 2048, 2048, + 2048, 18176, 18432, 18688, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 5376, 5376, 5376, 18944, 19200, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 19456, 19712, 19968, 20224, 20480, 20736, 20992, + 21248, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 5376, + 5376, 5376, 5376, 5376, 5376, 5376, 5376, 21504, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 21760, 22016, 22272, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 22528, 22784, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 2048, 2048, 2048, 2048, 2048, 2048, 2048, + 2048, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 23040, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 15104, 15104, 15104, 15104, 15104, 15104, 15104, 15104, + 23040, }; + +const uint16_t utf8proc_stage2table[] = { + 1, 1, 1, 1, 1, 1, 1, + 1, 1, 2, 3, 2, 4, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 5, 5, 5, + 6, 7, 8, 8, 9, 10, 9, 8, + 8, 11, 12, 8, 13, 14, 15, 14, + 14, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 14, 8, 17, 18, 19, + 8, 8, 20, 21, 22, 23, 24, 25, + 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, + 42, 43, 44, 45, 11, 8, 12, 46, + 47, 46, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, + 62, 63, 64, 65, 66, 67, 68, 69, + 70, 71, 72, 73, 11, 74, 12, 74, + 1, 1, 1, 1, 1, 1, 3, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 75, 8, 10, 10, 10, 10, 76, + 76, 77, 76, 78, 79, 74, 80, 76, + 81, 82, 83, 84, 85, 86, 87, 76, + 8, 88, 89, 90, 91, 92, 93, 94, + 8, 95, 96, 97, 98, 99, 100, 101, + 102, 103, 104, 105, 106, 107, 108, 109, + 110, 111, 112, 113, 114, 115, 116, 117, + 74, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, + 133, 134, 135, 136, 137, 138, 139, 140, + 141, 142, 143, 144, 145, 146, 147, 148, + 74, 149, 150, 151, 152, 153, 154, 155, + 156, 157, 158, 159, 160, 161, 162, 163, + 164, 165, 166, 167, 168, 169, 170, 171, + 172, 173, 174, 175, 176, 177, 178, 179, + 180, 181, 182, 183, 184, 185, 186, 187, + 188, 189, 190, 191, 192, 193, 194, 195, + 196, 197, 198, 199, 200, 201, 202, 203, + 204, 205, 206, 207, 208, 209, 210, 211, + 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, + 228, 229, 230, 231, 232, 233, 234, 235, + 236, 237, 238, 239, 240, 241, 242, 243, + 244, 245, 246, 247, 248, 249, 250, 251, + 252, 253, 254, 255, 256, 257, 258, 259, + 260, 261, 262, 263, 264, 265, 266, 267, + 268, 269, 270, 271, 272, 273, 274, 275, + 276, 277, 278, 279, 280, 281, 282, 283, + 284, 285, 286, 287, 288, 289, 290, 291, + 292, 293, 294, 295, 296, 297, 213, 298, + 299, 300, 301, 302, 303, 304, 305, 306, + 307, 308, 309, 310, 213, 311, 312, 313, + 314, 315, 316, 317, 318, 319, 320, 321, + 322, 323, 324, 213, 213, 325, 326, 327, + 328, 329, 330, 331, 332, 333, 334, 335, + 336, 337, 338, 213, 339, 340, 341, 213, + 342, 339, 339, 339, 339, 343, 344, 345, + 346, 347, 348, 349, 350, 351, 352, 353, + 354, 355, 356, 357, 358, 359, 360, 361, + 362, 363, 364, 365, 366, 367, 368, 369, + 370, 371, 372, 373, 374, 375, 376, 377, + 378, 379, 380, 381, 382, 383, 384, 385, + 386, 387, 388, 389, 390, 391, 392, 393, + 394, 395, 396, 397, 398, 399, 400, 401, + 402, 403, 404, 405, 406, 407, 408, 409, + 410, 411, 412, 413, 414, 415, 416, 417, + 418, 419, 420, 421, 422, 423, 424, 425, + 426, 427, 428, 429, 430, 431, 432, 433, + 434, 435, 213, 436, 437, 438, 439, 440, + 441, 442, 443, 444, 445, 446, 447, 448, + 449, 450, 451, 452, 453, 213, 213, 213, + 213, 213, 213, 454, 455, 456, 457, 458, + 213, 213, 459, 460, 461, 462, 463, 464, + 465, 466, 467, 468, 469, 470, 471, 472, + 473, 213, 213, 213, 474, 475, 213, 476, + 477, 213, 478, 213, 479, 213, 213, 213, + 213, 480, 213, 213, 481, 213, 213, 213, + 213, 482, 483, 213, 484, 213, 213, 213, + 485, 213, 213, 486, 213, 213, 487, 213, + 213, 213, 213, 213, 213, 213, 488, 213, + 213, 489, 213, 213, 490, 213, 213, 213, + 213, 491, 492, 493, 494, 495, 213, 213, + 213, 213, 213, 496, 213, 339, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 497, 498, 499, 500, 501, 502, 503, + 504, 505, 506, 506, 507, 507, 507, 507, + 507, 507, 507, 46, 46, 46, 46, 506, + 506, 506, 506, 506, 506, 506, 506, 506, + 506, 507, 507, 46, 46, 46, 46, 46, + 46, 508, 509, 510, 511, 512, 513, 46, + 46, 514, 515, 516, 517, 518, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 507, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 519, 520, 521, 522, 523, 524, 525, + 526, 527, 528, 529, 530, 531, 524, 524, + 532, 524, 533, 524, 534, 535, 536, 537, + 537, 537, 537, 536, 538, 537, 537, 537, + 537, 537, 539, 539, 540, 541, 542, 543, + 544, 545, 537, 537, 537, 537, 546, 547, + 537, 548, 549, 537, 537, 550, 550, 550, + 550, 551, 537, 537, 537, 537, 524, 524, + 524, 552, 553, 554, 555, 556, 557, 524, + 537, 537, 537, 524, 524, 524, 537, 537, + 558, 524, 524, 524, 537, 537, 537, 537, + 524, 536, 537, 537, 524, 559, 560, 560, + 559, 560, 560, 559, 524, 524, 524, 524, + 524, 524, 524, 524, 524, 524, 524, 524, + 524, 0, 0, 0, 0, 561, 46, 0, + 0, 0, 0, 562, 563, 564, 565, 566, + 0, 0, 0, 0, 0, 86, 567, 568, + 569, 570, 571, 572, 0, 573, 0, 574, + 575, 576, 577, 578, 579, 580, 581, 582, + 583, 584, 585, 586, 587, 588, 589, 590, + 591, 592, 593, 0, 594, 595, 596, 597, + 598, 599, 600, 601, 602, 603, 604, 605, + 606, 607, 608, 609, 610, 611, 612, 613, + 614, 615, 616, 617, 618, 619, 620, 621, + 622, 623, 624, 625, 626, 627, 628, 629, + 630, 631, 632, 633, 634, 635, 636, 637, + 0, 638, 639, 640, 641, 642, 643, 644, + 213, 645, 646, 647, 648, 649, 650, 651, + 652, 653, 654, 655, 656, 657, 658, 659, + 660, 661, 662, 663, 664, 665, 666, 667, + 668, 669, 670, 671, 213, 672, 673, 74, + 674, 675, 676, 677, 678, 213, 679, 680, + 681, 682, 683, 684, 685, 686, 687, 688, + 689, 690, 691, 692, 693, 694, 695, 696, + 697, 698, 699, 700, 701, 702, 703, 704, + 705, 706, 707, 708, 709, 710, 711, 712, + 713, 714, 715, 716, 717, 718, 719, 720, + 721, 722, 723, 724, 725, 726, 727, 728, + 729, 730, 731, 732, 733, 734, 735, 736, + 737, 738, 739, 740, 741, 742, 743, 744, + 745, 746, 747, 748, 749, 750, 751, 752, + 753, 754, 755, 756, 757, 758, 759, 760, + 761, 762, 763, 764, 765, 766, 767, 768, + 769, 770, 771, 772, 773, 774, 775, 776, + 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 789, 790, 791, 792, + 793, 794, 795, 796, 797, 798, 799, 800, + 801, 802, 803, 804, 805, 806, 807, 808, + 809, 810, 811, 812, 524, 524, 524, 524, + 0, 813, 813, 814, 815, 816, 817, 818, + 819, 820, 821, 822, 823, 824, 825, 826, + 827, 828, 829, 830, 831, 832, 833, 834, + 835, 836, 837, 838, 839, 840, 841, 842, + 843, 844, 845, 846, 847, 848, 849, 850, + 851, 852, 853, 854, 855, 856, 857, 858, + 859, 860, 861, 862, 863, 864, 865, 866, + 867, 868, 869, 870, 871, 872, 873, 874, + 875, 876, 877, 878, 879, 880, 881, 882, + 883, 884, 885, 886, 887, 888, 889, 890, + 891, 892, 893, 894, 895, 896, 897, 898, + 899, 900, 901, 902, 903, 904, 905, 906, + 907, 908, 909, 910, 911, 912, 913, 914, + 915, 916, 917, 918, 919, 920, 921, 922, + 923, 924, 925, 926, 927, 928, 929, 930, + 931, 932, 933, 934, 935, 936, 937, 938, + 939, 940, 941, 942, 943, 944, 945, 946, + 947, 948, 949, 950, 951, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 952, 953, 954, 955, 956, 957, + 958, 959, 960, 961, 962, 963, 964, 965, + 966, 967, 968, 969, 970, 971, 972, 973, + 974, 975, 976, 977, 978, 979, 980, 981, + 982, 983, 984, 985, 986, 987, 988, 989, + 0, 0, 507, 990, 990, 990, 990, 990, + 990, 0, 991, 992, 993, 994, 995, 996, + 997, 998, 999, 1000, 1001, 1002, 1003, 1004, + 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, + 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020, + 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, + 1029, 0, 990, 1030, 0, 0, 0, 0, + 0, 0, 537, 524, 524, 524, 524, 537, + 524, 524, 524, 1031, 537, 524, 524, 524, + 524, 524, 524, 537, 537, 537, 537, 537, + 537, 524, 524, 537, 524, 524, 1031, 1032, + 524, 1033, 1034, 1035, 1036, 1037, 1038, 1039, + 1040, 1041, 1042, 1042, 1043, 1044, 1045, 1046, + 1047, 1046, 1048, 1049, 1046, 524, 537, 1046, + 1041, 0, 0, 0, 0, 0, 0, 0, + 0, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 0, 0, 0, 0, + 0, 1050, 1050, 1050, 1046, 1046, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1051, 1051, 1051, 1051, 0, 0, 0, + 0, 0, 0, 0, 1052, 14, 1053, 76, + 76, 524, 524, 524, 524, 524, 524, 0, + 0, 0, 0, 0, 1053, 0, 0, 1053, + 1053, 0, 1054, 1055, 1056, 1057, 1058, 1059, + 1060, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 0, 0, 0, 0, + 0, 1061, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1062, 1054, 1063, 1064, 1065, 1066, 1067, + 1068, 1069, 1070, 1071, 1072, 1073, 1074, 537, + 524, 524, 524, 524, 524, 537, 524, 524, + 0, 1075, 1075, 1075, 1075, 1075, 1075, 1075, + 1075, 1075, 1075, 9, 1076, 1076, 1053, 1054, + 1054, 1077, 1054, 1054, 1054, 1054, 1078, 1079, + 1080, 1081, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1082, 1083, 1084, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1085, 1086, 1053, 1087, 524, + 524, 524, 524, 524, 524, 524, 1051, 813, + 524, 524, 524, 524, 537, 524, 1061, 1061, + 524, 524, 76, 537, 524, 524, 537, 1054, + 1054, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 1054, 1054, 1054, 1088, 1088, + 1054, 1053, 1053, 1053, 1053, 1053, 1053, 1053, + 1053, 1053, 1053, 1053, 1053, 1053, 1053, 0, + 80, 1054, 1089, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 524, 537, 524, 524, 537, 524, 524, + 537, 537, 537, 524, 537, 537, 524, 537, + 524, 524, 524, 537, 524, 537, 524, 537, + 524, 537, 524, 524, 0, 0, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1054, + 1054, 1054, 1054, 1054, 1054, 1054, 1054, 1090, + 1090, 1090, 1090, 1090, 1090, 1090, 1090, 1090, + 1090, 1090, 1054, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1091, 1091, 1091, 1091, 1091, 1091, 1091, + 1091, 1091, 1091, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 524, 524, 524, 524, + 524, 524, 524, 537, 524, 1092, 1092, 76, + 8, 8, 8, 1092, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1090, 1090, 1093, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 1094, 1095, 339, 339, 339, 339, 339, + 339, 1096, 1097, 339, 1098, 1099, 339, 339, + 339, 339, 339, 0, 0, 1100, 339, 1093, + 1093, 1093, 1090, 1090, 1090, 1090, 1090, 1090, + 1090, 1090, 1093, 1093, 1093, 1093, 1101, 0, + 0, 339, 524, 537, 524, 524, 0, 0, + 0, 1102, 1103, 1104, 1105, 1106, 1107, 1108, + 1109, 339, 339, 1090, 1090, 990, 990, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 990, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 339, 339, 339, 339, + 339, 0, 1090, 1093, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 0, + 339, 339, 0, 0, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 0, 0, 0, 339, + 339, 339, 339, 0, 0, 1111, 339, 1112, + 1093, 1093, 1090, 1090, 1090, 1090, 0, 0, + 1113, 1093, 0, 0, 1114, 1115, 1101, 339, + 0, 0, 0, 0, 0, 0, 0, 0, + 1116, 0, 0, 0, 0, 1117, 1118, 0, + 1119, 339, 339, 1090, 1090, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 339, 339, 10, 10, 1120, 1120, 1120, + 1120, 1120, 1120, 812, 0, 0, 0, 0, + 0, 0, 1090, 1090, 1093, 0, 339, 339, + 339, 339, 339, 339, 0, 0, 0, 0, + 339, 339, 0, 0, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 1121, 0, 339, 1122, + 0, 339, 339, 0, 0, 1111, 0, 1093, + 1093, 1093, 1090, 1090, 0, 0, 0, 0, + 1090, 1090, 0, 0, 1090, 1090, 1101, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1123, 1124, 1125, 339, 0, 1126, + 0, 0, 0, 0, 0, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1090, 1090, 339, 339, 339, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1090, 1090, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 339, 339, 339, 0, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 0, 339, 339, + 339, 339, 339, 0, 0, 1111, 339, 1093, + 1093, 1093, 1090, 1090, 1090, 1090, 1090, 0, + 1090, 1090, 1093, 0, 1093, 1093, 1101, 0, + 0, 339, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 1090, 1090, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 0, 10, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 1090, 1093, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 0, + 339, 339, 0, 0, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 0, 339, 339, + 339, 339, 339, 0, 0, 1111, 339, 1127, + 1090, 1093, 1090, 1090, 1090, 0, 0, 0, + 1128, 1129, 0, 0, 1130, 1131, 1101, 0, + 0, 0, 0, 0, 0, 0, 0, 1132, + 1133, 0, 0, 0, 0, 1134, 1135, 0, + 339, 339, 339, 0, 0, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 812, 339, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1090, 339, 0, 339, 339, + 339, 339, 339, 339, 0, 0, 0, 339, + 339, 339, 0, 1136, 339, 1137, 339, 0, + 0, 0, 339, 339, 0, 339, 0, 339, + 339, 0, 0, 0, 339, 339, 0, 0, + 0, 339, 339, 339, 0, 0, 0, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 0, 0, 0, 1138, + 1093, 1090, 1093, 1093, 0, 0, 0, 1139, + 1140, 1093, 0, 1141, 1142, 1143, 1101, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1144, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1120, 1120, 1120, 76, 76, 76, 76, + 76, 76, 10, 76, 0, 0, 0, 0, + 0, 0, 1093, 1093, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 339, 339, + 339, 339, 339, 0, 0, 0, 0, 1090, + 1090, 1090, 1093, 1093, 1093, 1093, 0, 1145, + 1090, 1146, 0, 1090, 1090, 1090, 1101, 0, + 0, 0, 0, 0, 0, 0, 1147, 1148, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 0, 0, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1093, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 339, 339, + 339, 339, 339, 0, 0, 1111, 339, 1093, + 1149, 1150, 1093, 1151, 1093, 1093, 0, 1152, + 1153, 1154, 0, 1155, 1156, 1090, 1101, 0, + 0, 0, 0, 0, 0, 0, 1157, 1158, + 0, 0, 0, 0, 0, 0, 0, 339, + 0, 339, 339, 1090, 1090, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 0, 76, 76, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1093, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 0, 0, 0, 1159, + 1093, 1093, 1090, 1090, 1090, 0, 0, 1160, + 1161, 1093, 0, 1162, 1163, 1164, 1101, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1165, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 0, 0, 0, 0, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1093, 1093, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 1166, 0, 0, 0, 0, + 1167, 1093, 1093, 1090, 1090, 1090, 0, 1090, + 0, 1093, 1168, 1169, 1093, 1170, 1171, 1172, + 1173, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 1093, 1093, 990, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 1090, 339, 1174, 1090, 1090, 1090, + 1090, 1175, 1175, 1101, 0, 0, 0, 0, + 10, 339, 339, 339, 339, 339, 339, 507, + 1090, 1176, 1176, 1176, 1176, 1090, 1090, 1090, + 990, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 990, 990, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 339, 339, 0, 339, 0, 0, + 339, 339, 0, 339, 0, 0, 339, 0, + 0, 0, 0, 0, 0, 339, 339, 339, + 339, 0, 339, 339, 339, 339, 339, 339, + 339, 0, 339, 339, 339, 0, 339, 0, + 339, 0, 0, 339, 339, 0, 339, 339, + 339, 339, 1090, 339, 1177, 1090, 1090, 1090, + 1090, 1178, 1178, 0, 1090, 1090, 339, 0, + 0, 339, 339, 339, 339, 339, 0, 507, + 0, 1179, 1179, 1179, 1179, 1090, 1090, 0, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 0, 0, 1180, 1181, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 812, 812, 812, 990, 990, 990, + 990, 990, 990, 990, 990, 1182, 990, 990, + 990, 990, 990, 990, 812, 812, 812, 812, + 812, 537, 537, 812, 812, 812, 812, 812, + 812, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 812, 537, 812, + 537, 812, 1183, 11, 12, 11, 12, 1093, + 1093, 339, 339, 339, 1184, 339, 339, 339, + 339, 0, 339, 339, 339, 339, 1185, 339, + 339, 339, 339, 1186, 339, 339, 339, 339, + 1187, 339, 339, 339, 339, 1188, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 1189, 339, 0, 0, 0, 0, + 0, 0, 1190, 1191, 1192, 1193, 1194, 1195, + 1196, 1197, 1198, 1191, 1191, 1191, 1191, 1090, + 1093, 1191, 1199, 524, 524, 1101, 990, 524, + 524, 339, 339, 339, 339, 0, 0, 0, + 0, 1090, 1090, 1090, 1200, 1090, 1090, 1090, + 1090, 0, 1090, 1090, 1090, 1090, 1201, 1090, + 1090, 1090, 1090, 1202, 1090, 1090, 1090, 1090, + 1203, 1090, 1090, 1090, 1090, 1204, 1090, 1090, + 1090, 1090, 1090, 1090, 1090, 1090, 1090, 1090, + 1090, 1090, 1205, 1090, 1090, 1090, 0, 812, + 812, 812, 812, 812, 812, 812, 812, 537, + 812, 812, 812, 812, 812, 812, 0, 0, + 812, 990, 990, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 339, 339, 1206, 1207, + 339, 0, 339, 339, 0, 1093, 1090, 1208, + 1090, 1090, 1093, 1090, 0, 0, 0, 1090, + 1111, 1093, 1101, 0, 0, 0, 0, 0, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 990, 990, 990, 990, 990, + 990, 339, 339, 339, 339, 339, 339, 1093, + 1093, 1090, 1090, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1209, 1210, 1211, 1212, 1213, 1214, 1215, + 1216, 1217, 1218, 1219, 1220, 1221, 1222, 1223, + 1224, 1225, 1226, 1227, 1228, 1229, 1230, 1231, + 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, + 1240, 1241, 1242, 1243, 1244, 1245, 1246, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 990, 1247, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 0, 0, 0, 0, + 1248, 1248, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 0, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 0, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 0, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 0, 0, 0, 0, + 524, 812, 990, 990, 990, 990, 990, 990, + 990, 990, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 990, 990, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 7, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 11, 12, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 990, 990, 990, 1249, + 1249, 1249, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 339, + 339, 339, 339, 1090, 1090, 1101, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 1090, 1090, 1101, 990, 990, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 1090, 1090, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 339, + 339, 339, 0, 1090, 1090, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 1250, 1250, 1093, + 1090, 1090, 1090, 1090, 1090, 1090, 1090, 1093, + 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1090, + 1093, 1093, 1090, 1090, 1090, 1090, 1090, 1090, + 1090, 1090, 1090, 1101, 1090, 990, 990, 990, + 507, 990, 990, 990, 10, 339, 524, 0, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 0, 0, 0, 0, 0, + 0, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 1251, 1251, 0, 0, 0, 0, 0, + 0, 8, 8, 8, 8, 8, 8, 1030, + 8, 8, 8, 8, 558, 558, 558, 7, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 507, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 1032, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 0, + 0, 1090, 1090, 1090, 1093, 1093, 1093, 1093, + 1090, 1090, 1252, 1252, 1252, 0, 0, 0, + 0, 1093, 1093, 1090, 1093, 1093, 1093, 1093, + 1093, 1093, 1031, 524, 537, 0, 0, 0, + 0, 76, 0, 0, 0, 8, 8, 1110, + 1110, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 0, 0, 0, 0, 0, + 0, 1093, 1093, 1093, 1093, 1093, 1093, 1093, + 1093, 1093, 1093, 1093, 1093, 1093, 1093, 1093, + 1093, 1093, 339, 339, 339, 339, 339, 339, + 339, 1093, 1093, 0, 0, 0, 0, 0, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 0, 0, 0, 0, 8, + 8, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 524, 537, 1093, 1093, 1093, 0, 0, 990, + 990, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1090, 1090, 1090, 1090, 1093, 1253, 1254, + 1255, 1256, 1257, 1258, 1259, 1260, 1261, 1262, + 339, 339, 1263, 1264, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 1111, 1265, 1090, + 1090, 1090, 1090, 1266, 1267, 1268, 1269, 1270, + 1271, 1272, 1273, 1274, 1275, 1276, 339, 339, + 339, 339, 339, 339, 339, 0, 0, 0, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 990, 990, 990, 990, 990, + 990, 990, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 524, 537, 524, 524, + 524, 524, 524, 524, 524, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 1277, 1278, 1279, + 507, 1280, 1281, 1282, 1283, 1284, 1285, 1286, + 1287, 1288, 1289, 1290, 507, 1291, 1292, 1293, + 1294, 1295, 1296, 1297, 1298, 1299, 1300, 1301, + 1302, 1303, 1304, 1305, 1306, 1307, 1308, 507, + 1309, 1310, 1311, 1312, 1313, 1314, 1315, 1316, + 1317, 1318, 1319, 1320, 1321, 1322, 1323, 1324, + 1325, 1326, 1327, 1328, 1329, 1330, 1331, 1332, + 1333, 1334, 1335, 1336, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 1337, 213, 213, 213, 213, 1338, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 213, 213, 213, 213, + 213, 213, 213, 213, 1339, 1340, 1341, 1342, + 1307, 1343, 1344, 1345, 1346, 1347, 1348, 1349, + 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, + 1358, 1359, 1360, 1361, 1362, 1363, 1364, 1365, + 1366, 1367, 1368, 1369, 1370, 1371, 1372, 1373, + 1374, 524, 524, 537, 524, 524, 524, 524, + 524, 524, 524, 537, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 524, + 537, 1375, 1376, 1377, 1378, 1379, 1380, 1381, + 1382, 1383, 1384, 1385, 1386, 1387, 1388, 1389, + 1390, 1391, 1392, 1393, 1394, 1395, 1396, 1397, + 1398, 1399, 1400, 1401, 1402, 1403, 1404, 1405, + 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, + 1414, 1415, 1416, 1417, 1418, 1419, 1420, 1421, + 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, + 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, + 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, + 1446, 1447, 1448, 1449, 1450, 1451, 1452, 1453, + 1454, 1455, 1456, 1457, 1458, 1459, 1460, 1461, + 1462, 1463, 1464, 1465, 1466, 1467, 1468, 1469, + 1470, 1471, 1472, 1473, 1474, 1475, 1476, 1477, + 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1485, + 1486, 1487, 1488, 1489, 1490, 1491, 1492, 1493, + 1494, 1495, 1496, 1497, 1498, 1499, 1500, 1501, + 1502, 1503, 1504, 1505, 1506, 1507, 1508, 1509, + 1510, 1511, 1512, 1513, 1514, 1515, 1516, 1517, + 1518, 1519, 1520, 1521, 1522, 1523, 1524, 1525, + 1526, 1527, 1528, 1529, 1530, 0, 0, 0, + 0, 1531, 1532, 1533, 1534, 1535, 1536, 1537, + 1538, 1539, 1540, 1541, 1542, 1543, 1544, 1545, + 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, + 1554, 1555, 1556, 1557, 1558, 1559, 1560, 1561, + 1562, 1563, 1564, 1565, 1566, 1567, 1568, 1569, + 1570, 1571, 1572, 1573, 1574, 1575, 1576, 1577, + 1578, 1579, 1580, 1581, 1582, 1583, 1584, 1585, + 1586, 1587, 1588, 1589, 1590, 1591, 1592, 1593, + 1594, 1595, 1596, 1597, 1598, 1599, 1600, 1601, + 1602, 1603, 1604, 1605, 1606, 1607, 1608, 1609, + 1610, 1611, 1612, 1613, 1614, 1615, 1616, 1617, + 1618, 1619, 1620, 0, 0, 0, 0, 0, + 0, 1621, 1622, 1623, 1624, 1625, 1626, 1627, + 1628, 1629, 1630, 1631, 1632, 1633, 1634, 1635, + 1636, 1637, 1638, 1639, 1640, 1641, 1642, 0, + 0, 1643, 1644, 1645, 1646, 1647, 1648, 0, + 0, 1649, 1650, 1651, 1652, 1653, 1654, 1655, + 1656, 1657, 1658, 1659, 1660, 1661, 1662, 1663, + 1664, 1665, 1666, 1667, 1668, 1669, 1670, 1671, + 1672, 1673, 1674, 1675, 1676, 1677, 1678, 1679, + 1680, 1681, 1682, 1683, 1684, 1685, 1686, 0, + 0, 1687, 1688, 1689, 1690, 1691, 1692, 0, + 0, 1693, 1694, 1695, 1696, 1697, 1698, 1699, + 1700, 0, 1701, 0, 1702, 0, 1703, 0, + 1704, 1705, 1706, 1707, 1708, 1709, 1710, 1711, + 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, + 1720, 1721, 1722, 1723, 1724, 1725, 1726, 1727, + 1728, 1729, 1730, 1731, 1732, 1733, 1734, 0, + 0, 1735, 1736, 1737, 1738, 1739, 1740, 1741, + 1742, 1743, 1744, 1745, 1746, 1747, 1748, 1749, + 1750, 1751, 1752, 1753, 1754, 1755, 1756, 1757, + 1758, 1759, 1760, 1761, 1762, 1763, 1764, 1765, + 1766, 1767, 1768, 1769, 1770, 1771, 1772, 1773, + 1774, 1775, 1776, 1777, 1778, 1779, 1780, 1781, + 1782, 1783, 1784, 1785, 1786, 1787, 0, 1788, + 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, + 1797, 1798, 1799, 1800, 1801, 1802, 0, 1803, + 1804, 1805, 1806, 1807, 1808, 1809, 1810, 1811, + 1812, 1813, 1814, 1815, 1816, 0, 0, 1817, + 1818, 1819, 1820, 1821, 1822, 0, 1823, 1824, + 1825, 1826, 1827, 1828, 1829, 1830, 1831, 1832, + 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, + 1841, 0, 0, 1842, 1843, 1844, 0, 1845, + 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, + 0, 1854, 1855, 1856, 1856, 1856, 1856, 1856, + 1857, 1856, 1856, 1856, 80, 1858, 1858, 1250, + 1859, 1030, 1860, 1030, 1030, 1030, 1030, 8, + 1861, 79, 91, 11, 79, 79, 91, 11, + 79, 8, 8, 8, 8, 1862, 1863, 1864, + 8, 1865, 1866, 1867, 1868, 1869, 1870, 1871, + 75, 9, 9, 9, 1872, 1873, 8, 1874, + 1875, 8, 79, 91, 8, 1876, 8, 1877, + 47, 47, 8, 8, 8, 1878, 11, 12, + 1879, 1880, 1881, 8, 8, 8, 8, 8, + 8, 8, 8, 74, 8, 47, 8, 8, + 1882, 8, 8, 8, 8, 8, 8, 8, + 1856, 80, 80, 80, 80, 0, 0, 0, + 0, 0, 0, 80, 80, 80, 80, 80, + 80, 1883, 1884, 0, 0, 1885, 1886, 1887, + 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1895, + 1896, 1897, 1898, 1899, 1900, 1901, 1902, 1903, + 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, + 0, 1912, 1913, 1914, 1915, 1916, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 10, 10, 10, 10, 10, 10, 10, + 10, 1917, 10, 10, 10, 10, 10, 10, + 10, 10, 10, 10, 10, 10, 10, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 524, 524, 550, 550, 524, 524, 524, + 524, 550, 550, 550, 524, 524, 813, 813, + 813, 813, 524, 813, 813, 813, 550, 550, + 524, 537, 524, 550, 550, 537, 537, 537, + 537, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1918, 1919, 1920, 1921, 76, 1922, 1923, + 1924, 76, 1925, 1926, 1927, 1927, 1927, 1928, + 1929, 1930, 1930, 1931, 1932, 76, 1933, 1934, + 76, 76, 1935, 1936, 1937, 1937, 1937, 76, + 76, 1938, 1939, 1940, 76, 1941, 76, 1942, + 76, 1941, 76, 1943, 1944, 1945, 1920, 82, + 1946, 1947, 1948, 1949, 1950, 1951, 1952, 1953, + 1954, 1955, 1956, 76, 1957, 1958, 1959, 1960, + 1961, 1962, 74, 74, 74, 74, 1963, 1964, + 1946, 1956, 1965, 76, 74, 76, 76, 1966, + 0, 0, 0, 0, 1967, 1968, 1969, 1970, + 1971, 1972, 1973, 1974, 1975, 1976, 1977, 1978, + 1979, 1980, 1981, 1982, 1983, 1984, 1985, 1986, + 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, + 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, + 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, + 2011, 1249, 1249, 1249, 2012, 2013, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2014, 74, 2015, 74, 2016, 76, 76, + 76, 76, 76, 2017, 2018, 76, 76, 76, + 76, 74, 76, 76, 74, 76, 76, 74, + 76, 76, 76, 76, 76, 76, 76, 2019, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 2020, 2021, + 2022, 2023, 76, 2024, 76, 2025, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 2026, 2026, 2027, 2028, 74, 74, + 74, 2029, 2030, 2026, 2031, 2032, 2026, 74, + 74, 74, 2026, 13, 83, 74, 2026, 2026, + 74, 74, 74, 2026, 2026, 2026, 2026, 74, + 2026, 2026, 2026, 2026, 2033, 2034, 2035, 2036, + 74, 74, 74, 74, 2026, 2037, 2038, 2026, + 2039, 2040, 2026, 2026, 2026, 74, 74, 74, + 74, 74, 2026, 74, 2026, 2041, 2026, 2026, + 2026, 2026, 2042, 2026, 2043, 2044, 2045, 2026, + 2046, 2047, 2048, 2026, 2026, 2026, 2049, 74, + 74, 74, 74, 2026, 2026, 2026, 2026, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 2026, 2050, 2051, 2052, 74, 2053, 2054, 2026, + 2026, 2026, 2026, 2026, 2026, 74, 2055, 2056, + 2057, 2058, 2059, 2060, 2061, 2062, 2063, 2064, + 2065, 2066, 2067, 2068, 2069, 2070, 2071, 2026, + 2026, 2072, 2073, 2074, 2075, 2076, 2077, 2078, + 2079, 2080, 2081, 2026, 2026, 2026, 74, 74, + 2026, 2026, 2082, 2083, 74, 74, 74, 74, + 74, 2026, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 2084, 2026, 74, 74, 2026, + 2026, 2085, 2086, 2026, 2087, 2088, 2089, 2090, + 2091, 2026, 2026, 2092, 2093, 2094, 2095, 2026, + 2026, 2026, 74, 74, 74, 74, 74, 2026, + 2026, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 2026, 2026, 2026, 2026, 2026, 74, + 74, 2026, 2026, 74, 74, 74, 74, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2096, 2097, 2098, 2099, 2026, 2026, 2026, + 2026, 2026, 2026, 2100, 2101, 2102, 2103, 74, + 74, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 76, 76, 76, 76, 76, 76, 76, + 76, 2026, 2026, 2026, 2026, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 2026, 2026, 76, 76, 76, 76, 76, + 76, 76, 2104, 2105, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 76, 74, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 812, 76, + 76, 76, 76, 76, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 74, 74, 74, + 74, 74, 74, 76, 76, 76, 76, 76, + 76, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2106, 2107, 2108, 2109, 2110, 2111, 2112, + 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, + 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, + 2129, 2130, 2131, 2132, 2133, 2134, 2135, 2136, + 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, + 2145, 2146, 2147, 2148, 2149, 2150, 2151, 2152, + 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, + 2161, 2162, 2163, 2164, 2165, 2166, 2167, 2168, + 2169, 2170, 2171, 2172, 2173, 2174, 2175, 2176, + 2177, 2178, 2179, 2180, 2181, 2182, 2183, 2184, + 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, + 2193, 2194, 2195, 2196, 2197, 2198, 2199, 2200, + 2201, 2202, 2203, 2204, 2205, 2206, 2207, 2208, + 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, + 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, + 2225, 2226, 2227, 2228, 2229, 2230, 2231, 2232, + 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, + 2241, 2242, 2243, 2244, 1251, 1251, 1251, 1251, + 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 74, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 74, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 74, 74, 74, 74, 74, 74, 74, + 74, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 74, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 812, 76, 76, + 76, 76, 76, 76, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 76, 76, 76, 76, 0, 76, + 76, 76, 76, 0, 0, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 0, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 0, 76, 0, + 76, 76, 76, 76, 0, 0, 0, 76, + 0, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 76, 76, 76, 76, 76, 76, + 76, 11, 12, 11, 12, 11, 12, 11, + 12, 11, 12, 11, 12, 11, 12, 1251, + 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 1251, 1251, 1251, 1251, 1251, 1251, 1251, + 1251, 1251, 1251, 1251, 1251, 76, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 0, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 0, 2026, 74, 74, 2026, 2026, 11, 12, + 74, 74, 74, 74, 0, 0, 0, 0, + 0, 74, 74, 74, 2026, 2026, 2026, 2026, + 74, 74, 74, 74, 74, 2026, 2026, 2026, + 74, 74, 74, 2026, 2026, 2026, 2026, 11, + 12, 11, 12, 11, 12, 0, 0, 0, + 0, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 11, 12, 11, 12, + 11, 12, 11, 12, 11, 12, 11, 12, + 11, 12, 11, 12, 11, 12, 11, 12, + 11, 12, 74, 74, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 74, 74, 74, 74, 74, 74, 74, + 74, 2026, 74, 74, 74, 74, 74, 74, + 74, 2026, 2026, 2026, 2026, 2026, 2026, 74, + 74, 74, 2026, 74, 74, 74, 74, 2026, + 2026, 2026, 2026, 2026, 74, 2026, 2026, 74, + 74, 11, 12, 11, 12, 2026, 74, 74, + 74, 74, 2026, 74, 2026, 2026, 2026, 74, + 74, 2026, 2026, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 2026, 2026, 2026, + 2026, 2026, 2026, 74, 74, 11, 12, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 2026, 2026, 2245, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 74, 2026, + 2026, 2026, 2026, 74, 74, 2026, 74, 2026, + 74, 74, 2026, 74, 2026, 2026, 2026, 2026, + 74, 74, 74, 74, 74, 2026, 2026, 74, + 74, 74, 74, 74, 74, 2026, 2026, 2026, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 74, 74, 74, + 2026, 2026, 74, 74, 74, 74, 74, 74, + 74, 74, 74, 74, 74, 2026, 2026, 74, + 74, 74, 74, 2026, 2026, 2026, 2026, 74, + 2026, 2026, 74, 74, 2026, 2246, 2247, 2248, + 74, 74, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 74, 74, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 74, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 2026, 2026, 2026, 2026, 2026, 2026, 2026, 2026, + 74, 74, 74, 74, 74, 2249, 2250, 2026, + 74, 74, 74, 2026, 2026, 2026, 2026, 2026, + 74, 74, 74, 74, 74, 2026, 2026, 2026, + 74, 74, 74, 74, 2026, 74, 74, 74, + 2026, 2026, 2026, 2026, 2026, 74, 2026, 74, + 74, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2251, 2252, 2253, 2254, 2255, 2256, 2257, + 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, + 2266, 2267, 2268, 2269, 2270, 2271, 2272, 2273, + 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, + 2282, 2283, 2284, 2285, 2286, 2287, 2288, 2289, + 2290, 2291, 2292, 2293, 2294, 2295, 2296, 2297, + 0, 2298, 2299, 2300, 2301, 2302, 2303, 2304, + 2305, 2306, 2307, 2308, 2309, 2310, 2311, 2312, + 2313, 2314, 2315, 2316, 2317, 2318, 2319, 2320, + 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2328, + 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2336, + 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, + 0, 2345, 2346, 2347, 2348, 2349, 2350, 2351, + 2352, 2353, 2354, 2355, 2356, 2357, 0, 0, + 0, 0, 0, 0, 0, 213, 2358, 2359, + 213, 0, 0, 0, 0, 0, 0, 0, + 0, 2360, 2361, 2362, 2363, 2364, 2365, 2366, + 2367, 2368, 2369, 2370, 2371, 2372, 2373, 2374, + 2375, 2376, 2377, 2378, 2379, 2380, 2381, 2382, + 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, + 2391, 2392, 2393, 2394, 2395, 2396, 2397, 2398, + 2399, 2400, 2401, 2402, 2403, 2404, 2405, 2406, + 2407, 2408, 2409, 2410, 2411, 2412, 2413, 2414, + 2415, 2416, 2417, 2418, 2419, 2420, 2421, 2422, + 2423, 2424, 2425, 2426, 2427, 2428, 2429, 2430, + 2431, 2432, 2433, 2434, 2435, 2436, 2437, 2438, + 2439, 2440, 2441, 2442, 2443, 2444, 2445, 2446, + 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454, + 2455, 2456, 2457, 2458, 2459, 213, 76, 76, + 76, 76, 76, 76, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 8, 8, 8, 8, 1251, 8, + 8, 2460, 2461, 2462, 2463, 2464, 2465, 2466, + 2467, 2468, 2469, 2470, 2471, 2472, 2473, 2474, + 2475, 2476, 2477, 2478, 2479, 2480, 2481, 2482, + 2483, 2484, 2485, 2486, 2487, 2488, 2489, 2490, + 2491, 2492, 2493, 2494, 2495, 2496, 2497, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 2498, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 8, 8, 79, 91, 79, 91, 8, + 8, 8, 79, 91, 8, 79, 91, 8, + 8, 8, 8, 8, 8, 8, 8, 8, + 1030, 0, 0, 0, 0, 79, 91, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 0, 76, 76, 76, 76, + 2499, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 2500, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 2501, 2502, 2503, 2504, 2505, 2506, 2507, + 2508, 2509, 2510, 2511, 2512, 2513, 2514, 2515, + 2516, 2517, 2518, 2519, 2520, 2521, 2522, 2523, + 2524, 2525, 2526, 2527, 2528, 2529, 2530, 2531, + 2532, 2533, 2534, 2535, 2536, 2537, 2538, 2539, + 2540, 2541, 2542, 2543, 2544, 2545, 2546, 2547, + 2548, 2549, 2550, 2551, 2552, 2553, 2554, 2555, + 2556, 2557, 2558, 2559, 2560, 2561, 2562, 2563, + 2564, 2565, 2566, 2567, 2568, 2569, 2570, 2571, + 2572, 2573, 2574, 2575, 2576, 2577, 2578, 2579, + 2580, 2581, 2582, 2583, 2584, 2585, 2586, 2587, + 2588, 2589, 2590, 2591, 2592, 2593, 2594, 2595, + 2596, 2597, 2598, 2599, 2600, 2601, 2602, 2603, + 2604, 2605, 2606, 2607, 2608, 2609, 2610, 2611, + 2612, 2613, 2614, 2615, 2616, 2617, 2618, 2619, + 2620, 2621, 2622, 2623, 2624, 2625, 2626, 2627, + 2628, 2629, 2630, 2631, 2632, 2633, 2634, 2635, + 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, + 2644, 2645, 2646, 2647, 2648, 2649, 2650, 2651, + 2652, 2653, 2654, 2655, 2656, 2657, 2658, 2659, + 2660, 2661, 2662, 2663, 2664, 2665, 2666, 2667, + 2668, 2669, 2670, 2671, 2672, 2673, 2674, 2675, + 2676, 2677, 2678, 2679, 2680, 2681, 2682, 2683, + 2684, 2685, 2686, 2687, 2688, 2689, 2690, 2691, + 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, + 2700, 2701, 2702, 2703, 2704, 2705, 2706, 2707, + 2708, 2709, 2710, 2711, 2712, 2713, 2714, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 0, 0, 0, + 0, 2715, 8, 8, 8, 76, 507, 339, + 1249, 11, 12, 11, 12, 11, 12, 11, + 12, 11, 12, 76, 76, 11, 12, 11, + 12, 11, 12, 11, 12, 1030, 11, 12, + 12, 76, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 2716, 1032, 536, 1031, 2717, + 2717, 1030, 507, 507, 507, 507, 507, 2718, + 76, 2719, 2720, 2721, 507, 339, 8, 76, + 76, 0, 339, 339, 339, 339, 339, 2722, + 339, 339, 339, 339, 2723, 2724, 2725, 2726, + 2727, 2728, 2729, 2730, 2731, 2732, 2733, 2734, + 2735, 2736, 2737, 2738, 2739, 2740, 2741, 2742, + 2743, 2744, 2745, 2746, 339, 2747, 2748, 2749, + 2750, 2751, 2752, 339, 339, 339, 339, 339, + 2753, 2754, 2755, 2756, 2757, 2758, 2759, 2760, + 2761, 2762, 2763, 2764, 2765, 2766, 2767, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 2768, 339, 339, + 0, 0, 2769, 2770, 2771, 2772, 2773, 2774, + 2775, 1030, 339, 339, 339, 339, 339, 2776, + 339, 339, 339, 339, 2777, 2778, 2779, 2780, + 2781, 2782, 2783, 2784, 2785, 2786, 2787, 2788, + 2789, 2790, 2791, 2792, 2793, 2794, 2795, 2796, + 2797, 2798, 2799, 2800, 339, 2801, 2802, 2803, + 2804, 2805, 2806, 339, 339, 339, 339, 339, + 2807, 2808, 2809, 2810, 2811, 2812, 2813, 2814, + 2815, 2816, 2817, 2818, 2819, 2820, 2821, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 2822, 2823, 2824, 2825, 339, 2826, 339, 339, + 2827, 2828, 2829, 2830, 8, 507, 2831, 2832, + 2833, 0, 0, 0, 0, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 0, + 0, 0, 2834, 2835, 2836, 2837, 2838, 2839, + 2840, 2841, 2842, 2843, 2844, 2845, 2846, 2847, + 2848, 2849, 2850, 2851, 2852, 2853, 2854, 2855, + 2856, 2857, 2858, 2859, 2860, 2861, 2862, 2863, + 2864, 2865, 2866, 2867, 2868, 2869, 2870, 2871, + 2872, 2873, 2874, 2875, 2876, 2877, 2878, 2879, + 2880, 2881, 2882, 2883, 2884, 2885, 2886, 2887, + 2888, 2889, 2890, 2891, 2892, 2893, 2894, 2895, + 2896, 2897, 2898, 2899, 2900, 2901, 2902, 2903, + 2904, 2905, 2906, 2907, 2908, 2909, 2910, 2911, + 2912, 2913, 2914, 2915, 2916, 2917, 2918, 2919, + 2920, 2921, 2922, 2923, 2924, 2925, 2926, 2927, + 0, 812, 812, 2928, 2929, 2930, 2931, 2932, + 2933, 2934, 2935, 2936, 2937, 2938, 2939, 2940, + 2941, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 2942, 2943, 2944, 2945, 2946, 2947, 2948, + 2949, 2950, 2951, 2952, 2953, 2954, 2955, 2956, + 2957, 2958, 2959, 2960, 2961, 2962, 2963, 2964, + 2965, 2966, 2967, 2968, 2969, 2970, 2971, 2972, + 0, 2973, 2974, 2975, 2976, 2977, 2978, 2979, + 2980, 2981, 2982, 2983, 2984, 2985, 2986, 2987, + 2988, 2989, 2990, 2991, 2992, 2993, 2994, 2995, + 2996, 2997, 2998, 2999, 3000, 3001, 3002, 3003, + 3004, 3005, 3006, 3007, 3008, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3009, 3010, 3011, 3012, 3013, 3014, 3015, + 3016, 3017, 3018, 3019, 3020, 3021, 3022, 3023, + 3024, 3025, 3026, 3027, 3028, 3029, 3030, 3031, + 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, + 3040, 3041, 3042, 3043, 3044, 3045, 3046, 3047, + 3048, 3049, 3050, 3051, 3052, 3053, 3054, 3055, + 812, 3056, 3057, 3058, 3059, 3060, 3061, 3062, + 3063, 3064, 3065, 3066, 3067, 3068, 3069, 3070, + 3071, 3072, 3073, 3074, 3075, 3076, 3077, 3078, + 3079, 3080, 3081, 3082, 3083, 3084, 3085, 3086, + 3087, 3088, 3089, 3090, 3091, 3092, 3093, 3094, + 3095, 3096, 3097, 3098, 3099, 3100, 3101, 3102, + 3103, 3104, 3105, 3106, 3107, 3108, 3109, 3110, + 3111, 3112, 3113, 3114, 3115, 3116, 3117, 3118, + 3119, 3120, 3121, 3122, 3123, 3124, 3125, 3126, + 3127, 3128, 3129, 3130, 3131, 3132, 3133, 3134, + 3135, 3136, 3137, 3138, 3139, 3140, 3141, 3142, + 3143, 3144, 3145, 3146, 3147, 3148, 3149, 3150, + 3151, 3152, 3153, 3154, 3155, 3156, 3157, 3158, + 3159, 3160, 3161, 3162, 3163, 3164, 3165, 3166, + 3167, 3168, 3169, 3170, 3171, 3172, 3173, 3174, + 3175, 3176, 3177, 3178, 3179, 3180, 3181, 3182, + 0, 3183, 3184, 3185, 3186, 3187, 3188, 3189, + 3190, 3191, 3192, 3193, 3194, 3195, 3196, 3197, + 3198, 3199, 3200, 3201, 3202, 3203, 3204, 3205, + 3206, 3207, 3208, 3209, 3210, 3211, 3212, 3213, + 3214, 3215, 3216, 3217, 3218, 3219, 3220, 3221, + 3222, 3223, 3224, 3225, 3226, 3227, 3228, 3229, + 3230, 3231, 3232, 3233, 3234, 3235, 3236, 3237, + 3238, 3239, 3240, 3241, 3242, 3243, 3244, 3245, + 3246, 3247, 3248, 3249, 3250, 3251, 3252, 3253, + 3254, 3255, 3256, 3257, 3258, 3259, 3260, 3261, + 3262, 3263, 3264, 3265, 3266, 3267, 3268, 3269, + 3270, 3271, 3272, 3273, 3274, 3275, 3276, 3277, + 3278, 3279, 3280, 3281, 3282, 3283, 3284, 3285, + 3286, 3287, 3288, 3289, 3290, 3291, 3292, 3293, + 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, + 3302, 3303, 3304, 3305, 3306, 3307, 3308, 3309, + 3310, 3311, 3312, 3313, 3314, 3315, 3316, 3317, + 3318, 3319, 3320, 3321, 3322, 3323, 3324, 3325, + 3326, 3327, 3328, 3329, 3330, 3331, 3332, 3333, + 3334, 3335, 3336, 3337, 3338, 3339, 3340, 3341, + 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, + 3350, 3351, 3352, 3353, 3354, 3355, 3356, 3357, + 3358, 3359, 3360, 3361, 3362, 3363, 3364, 3365, + 3366, 3367, 3368, 3369, 3370, 3371, 3372, 3373, + 3374, 3375, 3376, 3377, 3378, 3379, 3380, 3381, + 3382, 3383, 3384, 3385, 3386, 3387, 3388, 3389, + 3390, 3391, 3392, 3393, 3394, 3395, 3396, 3397, + 3398, 3399, 3400, 3401, 3402, 3403, 3404, 3405, + 3406, 3407, 3408, 3409, 3410, 3411, 3412, 3413, + 3414, 3415, 3416, 3417, 3418, 3419, 3420, 3421, + 3422, 3423, 3424, 3425, 3426, 3427, 3428, 3429, + 3430, 3431, 3432, 3433, 3434, 3435, 3436, 3437, + 3438, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 507, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 46, 46, 46, 46, 46, 46, 46, 46, + 506, 506, 506, 506, 0, 0, 0, 0, + 0, 46, 46, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 1252, 339, 339, 339, 1101, + 339, 339, 339, 339, 1090, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 1093, 1093, 1090, 1090, + 1093, 76, 76, 76, 76, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 8, 8, 8, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3439, 3439, 3439, 3439, 3439, 3439, 3439, + 3439, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3441, 3442, 3443, 3444, 3445, 3446, 3447, + 3448, 3448, 3449, 3450, 3451, 3452, 3453, 3454, + 3455, 3456, 3457, 3458, 3459, 3460, 3461, 3462, + 3463, 3464, 3465, 3466, 3467, 3468, 3469, 3470, + 3471, 3472, 3473, 3474, 3475, 3476, 3477, 3478, + 3479, 3480, 3481, 3482, 3483, 3484, 3485, 3486, + 3487, 3488, 3489, 3490, 3491, 3492, 3493, 3494, + 3495, 3496, 3497, 3498, 3499, 3500, 3501, 3502, + 3503, 3504, 3505, 3506, 3507, 3508, 3509, 3510, + 3511, 3512, 3513, 3514, 3515, 3516, 3517, 3518, + 3519, 3520, 3521, 3522, 3523, 3524, 3525, 3526, + 3527, 3528, 3529, 3530, 3531, 3460, 3532, 3533, + 3534, 3535, 3536, 3537, 3538, 3539, 3540, 3541, + 3542, 3543, 3544, 3545, 3546, 3547, 3548, 3549, + 3550, 3551, 3552, 3553, 3554, 3555, 3556, 3557, + 3558, 3559, 3560, 3561, 3562, 3563, 3564, 3565, + 3566, 3567, 3568, 3569, 3570, 3571, 3572, 3573, + 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3581, + 3582, 3583, 3584, 3585, 3586, 3587, 3588, 3589, + 3590, 3591, 3592, 3593, 3594, 3595, 3596, 3597, + 3598, 3599, 3550, 3600, 3601, 3602, 3603, 3604, + 3605, 3606, 3607, 3534, 3608, 3609, 3610, 3611, + 3612, 3613, 3614, 3615, 3616, 3617, 3618, 3619, + 3620, 3621, 3622, 3623, 3624, 3625, 3626, 3627, + 3460, 3628, 3629, 3630, 3631, 3632, 3633, 3634, + 3635, 3636, 3637, 3638, 3639, 3640, 3641, 3642, + 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, + 3651, 3652, 3653, 3654, 3536, 3655, 3656, 3657, + 3658, 3659, 3660, 3661, 3662, 3663, 3664, 3665, + 3666, 3667, 3668, 3669, 3670, 3671, 3672, 3673, + 3674, 3675, 3676, 3677, 3678, 3679, 3680, 3681, + 3682, 3683, 3684, 3685, 3686, 3687, 3688, 3689, + 3690, 3691, 3692, 3693, 3694, 3695, 3696, 3697, + 3698, 3699, 3700, 3701, 3702, 3703, 3704, 339, + 339, 3705, 339, 3706, 339, 339, 3707, 3708, + 3709, 3710, 3711, 3712, 3713, 3714, 3715, 3716, + 339, 3717, 339, 3718, 339, 339, 3719, 3720, + 339, 339, 339, 3721, 3722, 3723, 3724, 0, + 0, 3725, 3726, 3727, 3728, 3729, 3730, 3731, + 3732, 3733, 3734, 3735, 3736, 3737, 3738, 3739, + 3740, 3741, 3742, 3743, 3744, 3745, 3746, 3747, + 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, + 3756, 3757, 3758, 3759, 3760, 3761, 3762, 3763, + 3589, 3764, 3765, 3766, 3767, 3768, 3769, 3769, + 3770, 3771, 3772, 3773, 3774, 3775, 3776, 3777, + 3719, 3778, 3779, 3780, 0, 0, 0, 0, + 0, 3781, 3782, 3783, 3784, 3785, 3786, 3787, + 3788, 3731, 3789, 3790, 3791, 3705, 3792, 3793, + 3794, 3795, 3796, 3797, 3798, 3799, 3800, 3801, + 3802, 3803, 3740, 3804, 3741, 3805, 3806, 3807, + 3808, 3809, 3706, 3481, 3810, 3811, 3812, 3551, + 3638, 3813, 3814, 3748, 3815, 3749, 3816, 3817, + 3818, 3708, 3819, 3820, 3821, 3822, 3823, 3709, + 3824, 3825, 3826, 3827, 3828, 3829, 3763, 3830, + 3831, 3589, 3832, 3767, 3833, 3834, 3835, 3836, + 3837, 3772, 3838, 3718, 3839, 3773, 3532, 3840, + 3774, 3841, 3776, 3842, 3843, 3844, 3845, 3846, + 3778, 3714, 3847, 3779, 3848, 3780, 3849, 3448, + 3850, 3851, 3852, 3853, 3854, 3855, 3856, 3857, + 3858, 3859, 3860, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3861, 3862, 3863, 3864, 3865, 3866, 3867, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 3868, 3869, 3870, 3871, + 3872, 0, 0, 0, 0, 0, 3873, 3874, + 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, + 3883, 3884, 3885, 3886, 3887, 3888, 3889, 3890, + 3891, 3892, 3893, 3894, 3895, 3896, 3897, 3898, + 0, 3899, 3900, 3901, 3902, 3903, 0, 3904, + 0, 3905, 3906, 0, 3907, 3908, 0, 3909, + 3910, 3911, 3912, 3913, 3914, 3915, 3916, 3917, + 3918, 3919, 3920, 3921, 3922, 3923, 3924, 3925, + 3926, 3927, 3928, 3929, 3930, 3931, 3932, 3933, + 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, + 3942, 3943, 3944, 3945, 3946, 3947, 3948, 3949, + 3950, 3951, 3952, 3953, 3954, 3955, 3956, 3957, + 3958, 3959, 3960, 3961, 3962, 3963, 3964, 3965, + 3966, 3967, 3968, 3969, 3970, 3971, 3972, 3973, + 3974, 3975, 3976, 3977, 3978, 3979, 3980, 3981, + 3982, 3983, 3984, 3985, 3986, 3987, 3988, 3989, + 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, + 3998, 3999, 4000, 4001, 4002, 4003, 4004, 4005, + 4006, 4007, 4008, 4009, 4010, 4011, 4012, 4013, + 4014, 4015, 4016, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 4017, 4018, 4019, 4020, + 4021, 4022, 4023, 4024, 4025, 4026, 4027, 4028, + 4029, 4030, 4031, 4032, 4033, 4034, 4035, 4036, + 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, + 4045, 4046, 4047, 4048, 4049, 4050, 4051, 4052, + 4053, 4054, 4055, 4056, 4057, 4058, 4059, 4060, + 4061, 4062, 4063, 4064, 4055, 4065, 4066, 4067, + 4068, 4069, 4070, 4071, 4072, 4073, 4074, 4075, + 4076, 4077, 4078, 4079, 4080, 4081, 4082, 4083, + 4084, 4085, 4086, 4087, 4088, 4089, 4090, 4091, + 4092, 4093, 4094, 4095, 4096, 4097, 4098, 4099, + 4100, 4101, 4102, 4103, 4104, 4105, 4106, 4107, + 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, + 4116, 4117, 4118, 4119, 4120, 4121, 4122, 4123, + 4124, 4125, 4126, 4127, 4128, 4129, 4130, 4131, + 4132, 4133, 4134, 4135, 4136, 4137, 4138, 4139, + 4140, 4141, 4142, 4143, 4144, 4145, 4146, 4147, + 4148, 4149, 4150, 4151, 4152, 4153, 4154, 4155, + 4156, 4157, 4158, 4159, 4160, 4161, 4162, 4163, + 4164, 4056, 4165, 4166, 4167, 4168, 4169, 4170, + 4171, 4172, 4173, 4174, 4175, 4176, 4177, 4178, + 4179, 4180, 4181, 4182, 4183, 4184, 4185, 4186, + 4187, 4188, 4189, 4190, 4191, 4192, 4193, 4194, + 4195, 4196, 4197, 4198, 4199, 4200, 4201, 4202, + 4203, 4204, 4205, 4206, 4207, 4208, 4209, 4210, + 4211, 4212, 4213, 4214, 4215, 4216, 4217, 4218, + 4219, 4220, 4221, 4222, 4223, 4224, 4225, 4226, + 4227, 4228, 4229, 4230, 4231, 4232, 4233, 4234, + 4235, 4236, 4237, 4238, 4239, 4240, 4241, 4242, + 4243, 4244, 4245, 4246, 4247, 4248, 4249, 4250, + 4251, 4252, 4253, 4254, 4255, 4256, 4257, 4258, + 4259, 4260, 4261, 4262, 4263, 4264, 4265, 4266, + 4267, 4268, 4269, 4270, 4271, 4272, 4273, 4274, + 4275, 4276, 4277, 4278, 4279, 4280, 4281, 4282, + 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, + 4291, 4292, 4293, 4294, 4295, 4296, 4297, 4298, + 4299, 4300, 4301, 4302, 4303, 4304, 4305, 4306, + 4307, 4308, 4309, 4310, 4311, 4312, 4313, 4314, + 4315, 4316, 4317, 4318, 4319, 4320, 4321, 4322, + 4323, 4324, 4325, 4326, 4327, 4328, 4329, 4330, + 4331, 4332, 4333, 4334, 4335, 4336, 4337, 4338, + 4339, 4340, 4341, 4342, 4343, 4344, 4345, 4346, + 4347, 4348, 4349, 4350, 4351, 4352, 4353, 4354, + 4355, 4356, 4357, 4358, 4359, 4360, 4361, 4362, + 4363, 4364, 4365, 4366, 4367, 4368, 4369, 4370, + 4371, 4372, 4373, 4374, 4375, 4376, 4377, 4378, + 4379, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4380, 4381, 4382, 4383, 4384, 4385, 4386, + 4387, 4388, 4389, 4390, 4391, 4392, 4393, 4394, + 4395, 4396, 4397, 4398, 4399, 4400, 4401, 4402, + 4403, 4404, 4405, 4406, 4407, 4408, 4409, 4410, + 4411, 4412, 4413, 4414, 4415, 4416, 4417, 4418, + 4419, 4420, 4421, 4422, 4423, 4424, 4425, 4426, + 4427, 4428, 4429, 4430, 4431, 4432, 4433, 4434, + 4435, 4436, 4437, 4438, 4439, 4440, 4441, 4442, + 4443, 0, 0, 4444, 4445, 4446, 4447, 4448, + 4449, 4450, 4451, 4452, 4453, 4454, 4455, 4456, + 4457, 4458, 4459, 4460, 4461, 4462, 4463, 4464, + 4465, 4466, 4467, 4468, 4469, 4470, 4471, 4472, + 4473, 4474, 4475, 4476, 4477, 4478, 4479, 4480, + 4481, 4482, 4483, 4484, 4485, 4486, 4487, 4488, + 4489, 4490, 4491, 4492, 4493, 4494, 4495, 4496, + 4497, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4498, 4499, 4500, 4501, 4502, 4503, 4504, + 4505, 4506, 4507, 4508, 4509, 4510, 76, 0, + 0, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 4511, 4512, 4513, 4514, 4515, 4516, 4517, + 4518, 4519, 4520, 0, 0, 0, 0, 0, + 0, 524, 524, 524, 524, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4521, 4522, 4523, 4524, 4524, 4525, 4526, + 4527, 4528, 4529, 4530, 4531, 4532, 4533, 4534, + 4535, 4536, 4537, 4538, 4539, 4540, 8, 8, + 4541, 4542, 4543, 4543, 4543, 4543, 4544, 4544, + 4544, 4545, 4546, 4547, 0, 4548, 4549, 4550, + 4551, 4552, 4553, 4554, 4555, 4556, 4557, 4558, + 4559, 4560, 4561, 4562, 4563, 4564, 4565, 4566, + 0, 4567, 4568, 4569, 4570, 0, 0, 0, + 0, 4571, 4572, 4573, 1054, 4574, 0, 4575, + 4576, 4577, 4578, 4579, 4580, 4581, 4582, 4583, + 4584, 4585, 4586, 4587, 4588, 4589, 4590, 4591, + 4592, 4593, 4594, 4595, 4596, 4597, 4598, 4599, + 4600, 4601, 4602, 4603, 4604, 4605, 4606, 4607, + 4608, 4609, 4610, 4611, 4612, 4613, 4614, 4615, + 4616, 4617, 4618, 4619, 4620, 4621, 4622, 4623, + 4624, 4625, 4626, 4627, 4628, 4629, 4630, 4631, + 4632, 4633, 4634, 4635, 4636, 4637, 4638, 4639, + 4640, 4641, 4642, 4643, 4644, 4645, 4646, 4647, + 4648, 4649, 4650, 4651, 4652, 4653, 4654, 4655, + 4656, 4657, 4658, 4659, 4660, 4661, 4662, 4663, + 4664, 4665, 4666, 4667, 4668, 4669, 4670, 4671, + 4672, 4673, 4674, 4675, 4676, 4677, 4678, 4679, + 4680, 4681, 4682, 4683, 4684, 4685, 4686, 4687, + 4688, 4689, 4690, 4691, 4692, 4693, 4694, 4695, + 4696, 4697, 4698, 4699, 4700, 4701, 4702, 4703, + 4704, 4705, 4706, 4707, 4708, 4709, 0, 0, + 80, 0, 4710, 4711, 4712, 4713, 4714, 4715, + 4716, 4717, 4718, 4719, 4720, 4721, 4722, 4723, + 4724, 4725, 4726, 4727, 4728, 4729, 4730, 4731, + 4732, 4733, 4734, 4735, 4736, 4737, 4738, 4739, + 4740, 4741, 4742, 4743, 4744, 4745, 4746, 4747, + 4748, 4749, 4750, 4751, 4752, 4753, 4754, 4755, + 4756, 4757, 4758, 4759, 4760, 4761, 4762, 4763, + 4764, 4765, 4766, 4767, 4768, 4769, 4770, 4771, + 4772, 4773, 4774, 4775, 4776, 4777, 4778, 4779, + 4780, 4781, 4782, 4783, 4784, 4785, 4786, 4787, + 4788, 4789, 4790, 4791, 4792, 4793, 4794, 4795, + 4796, 4797, 4798, 4799, 4800, 4801, 4802, 4803, + 4804, 4805, 4806, 4807, 4808, 4809, 4810, 4811, + 4812, 4813, 4814, 4815, 4816, 4817, 4818, 4819, + 4820, 4821, 4822, 4823, 4824, 4825, 4826, 4827, + 4828, 4829, 4830, 4831, 4832, 4833, 4834, 4835, + 4836, 4837, 4838, 4839, 4840, 4841, 4842, 4843, + 4844, 4845, 4846, 4847, 4848, 4849, 4850, 4851, + 4852, 4853, 4854, 4855, 4856, 4857, 4858, 4859, + 4860, 4861, 4862, 4863, 4864, 4865, 4866, 4867, + 4868, 4869, 4870, 4871, 4872, 4873, 4874, 4875, + 4876, 4877, 4878, 4879, 4880, 4881, 4882, 4883, + 4884, 4885, 4886, 4887, 4888, 4889, 4890, 4891, + 4892, 4893, 4894, 4895, 4896, 4897, 4898, 4899, + 0, 0, 0, 4900, 4901, 4902, 4903, 4904, + 4905, 0, 0, 4906, 4907, 4908, 4909, 4910, + 4911, 0, 0, 4912, 4913, 4914, 4915, 4916, + 4917, 0, 0, 4918, 4919, 4920, 0, 0, + 0, 4921, 4922, 4923, 4924, 4925, 4926, 4927, + 0, 4928, 4929, 4930, 4931, 4932, 4933, 4934, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 4935, 4935, 4935, 76, 76, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 0, 339, 339, 0, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 0, 0, 0, 0, + 0, 990, 8, 812, 0, 0, 0, 0, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 0, 0, 0, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 4936, 4936, 4936, 4936, 4936, 4936, 4936, + 4936, 4936, 4936, 4936, 4936, 4936, 4936, 4936, + 4936, 4936, 4936, 4936, 4936, 4936, 4936, 4936, + 4936, 4936, 4936, 4936, 4936, 4936, 4936, 4936, + 4936, 4936, 4936, 4936, 4936, 4936, 4936, 4936, + 4936, 4936, 4936, 4936, 4936, 4936, 4936, 4936, + 4936, 4936, 4936, 4936, 4936, 4936, 1251, 1251, + 1251, 1251, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 1251, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 1120, 1120, 1120, 1120, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 1249, 339, 339, 339, 339, 339, + 339, 339, 339, 1249, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 990, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 990, 1249, 1249, 1249, 1249, 1249, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 4937, 4938, 4939, 4940, 4941, 4942, 4943, + 4944, 4945, 4946, 4947, 4948, 4949, 4950, 4951, + 4952, 4953, 4954, 4955, 4956, 4957, 4958, 4959, + 4960, 4961, 4962, 4963, 4964, 4965, 4966, 4967, + 4968, 4969, 4970, 4971, 4972, 4973, 4974, 4975, + 4976, 4977, 4978, 4979, 4980, 4981, 4982, 4983, + 4984, 4985, 4986, 4987, 4988, 4989, 4990, 4991, + 4992, 4993, 4994, 4995, 4996, 4997, 4998, 4999, + 5000, 5001, 5002, 5003, 5004, 5005, 5006, 5007, + 5008, 5009, 5010, 5011, 5012, 5013, 5014, 5015, + 5016, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 0, + 0, 1110, 1110, 1110, 1110, 1110, 1110, 1110, + 1110, 1110, 1110, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1050, 1050, 1050, 1050, 1050, 1050, 0, + 0, 1050, 0, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 0, + 1050, 1050, 0, 0, 0, 1050, 0, 0, + 1050, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 5017, + 5017, 5017, 5017, 0, 0, 0, 0, 0, + 8, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1050, 1090, 1090, 1090, 0, 1090, 1090, + 0, 0, 0, 0, 0, 1090, 537, 1090, + 524, 1050, 1050, 1050, 1050, 0, 1050, 1050, + 1050, 0, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 1050, 1050, 1050, + 1050, 1050, 1050, 1050, 1050, 0, 0, 0, + 0, 524, 550, 537, 0, 0, 0, 0, + 1101, 5017, 5017, 5017, 5017, 5017, 5017, 5017, + 5017, 0, 0, 0, 0, 0, 0, 0, + 0, 1046, 1046, 1046, 1046, 1046, 1046, 1046, + 1046, 1046, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 1249, 1249, 1249, 1249, + 1249, 1249, 1249, 1249, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 990, 990, 990, 990, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 0, 0, 0, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 5018, 5019, 812, 812, 812, 812, 812, 5020, + 5021, 5022, 5023, 5024, 5025, 5026, 5027, 5028, + 550, 550, 550, 812, 812, 812, 5029, 5030, + 5031, 5032, 5033, 5034, 80, 80, 80, 80, + 80, 80, 80, 80, 537, 537, 537, 537, + 537, 537, 537, 537, 812, 812, 524, 524, + 524, 524, 524, 537, 537, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 524, 524, 524, 524, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 5035, 5036, 5037, 5038, 5039, 5040, + 5041, 5042, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 812, + 812, 812, 812, 812, 812, 812, 812, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 524, 524, 524, 76, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 76, 76, 76, 76, 76, 76, 76, 76, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 1120, 1120, 1120, 1120, 1120, + 1120, 1120, 1120, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5043, 1945, 1920, 1963, 1947, 1948, 5044, + 1927, 1930, 5045, 5046, 1931, 1950, 1933, 5047, + 1935, 1936, 1937, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 1941, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5043, 1945, 1920, + 1963, 1947, 1948, 5044, 1927, 1930, 5045, 5046, + 1931, 1950, 1933, 5047, 1935, 1936, 1937, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 1941, 5055, + 5056, 5057, 1964, 1946, 5058, 1926, 0, 1956, + 1965, 5059, 1932, 5060, 5061, 1951, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5043, 1945, 1920, 1963, 1947, 1948, 5044, + 1927, 1930, 5045, 5046, 1931, 1950, 1933, 5047, + 1935, 1936, 1937, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 1941, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5043, 0, 1920, + 1963, 0, 0, 5044, 0, 0, 5045, 5046, + 0, 0, 1933, 5047, 1935, 1936, 0, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 1941, 5055, + 5056, 5057, 1964, 0, 5058, 0, 1928, 1956, + 1965, 5059, 1932, 5060, 5061, 0, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5043, 1945, 1920, 1963, 1947, 1948, 5044, + 1927, 1930, 5045, 5046, 1931, 1950, 1933, 5047, + 1935, 1936, 1937, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 1941, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5043, 1945, 0, + 1963, 1947, 1948, 5044, 0, 0, 5045, 5046, + 1931, 1950, 1933, 5047, 1935, 1936, 0, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 0, 5055, + 5056, 5057, 1964, 1946, 5058, 1926, 1928, 1956, + 1965, 5059, 1932, 5060, 5061, 1951, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5043, 1945, 0, 1963, 1947, 1948, 5044, + 0, 1930, 5045, 5046, 1931, 1950, 0, 5047, + 0, 0, 0, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 0, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5043, 1945, 1920, + 1963, 1947, 1948, 5044, 1927, 1930, 5045, 5046, + 1931, 1950, 1933, 5047, 1935, 1936, 1937, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 1941, 5055, + 5056, 5057, 1964, 1946, 5058, 1926, 1928, 1956, + 1965, 5059, 1932, 5060, 5061, 1951, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5043, 1945, 1920, 1963, 1947, 1948, 5044, + 1927, 1930, 5045, 5046, 1931, 1950, 1933, 5047, + 1935, 1936, 1937, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 1941, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5043, 1945, 1920, + 1963, 1947, 1948, 5044, 1927, 1930, 5045, 5046, + 1931, 1950, 1933, 5047, 1935, 1936, 1937, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 1941, 5055, + 5056, 5057, 1964, 1946, 5058, 1926, 1928, 1956, + 1965, 5059, 1932, 5060, 5061, 1951, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5043, 1945, 1920, 1963, 1947, 1948, 5044, + 1927, 1930, 5045, 5046, 1931, 1950, 1933, 5047, + 1935, 1936, 1937, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 1941, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5043, 1945, 1920, + 1963, 1947, 1948, 5044, 1927, 1930, 5045, 5046, + 1931, 1950, 1933, 5047, 1935, 1936, 1937, 5048, + 5049, 5050, 5051, 5052, 5053, 5054, 1941, 5055, + 5056, 5057, 1964, 1946, 5058, 1926, 1928, 1956, + 1965, 5059, 1932, 5060, 5061, 1951, 5062, 5063, + 5064, 5065, 5066, 5067, 5068, 5069, 5070, 5071, + 5072, 5043, 1945, 1920, 1963, 1947, 1948, 5044, + 1927, 1930, 5045, 5046, 1931, 1950, 1933, 5047, + 1935, 1936, 1937, 5048, 5049, 5050, 5051, 5052, + 5053, 5054, 1941, 5055, 5056, 5057, 1964, 1946, + 5058, 1926, 1928, 1956, 1965, 5059, 1932, 5060, + 5061, 1951, 5062, 5063, 5064, 5065, 5066, 5067, + 5068, 5069, 5070, 5071, 5072, 5073, 5074, 0, + 0, 5075, 5076, 1960, 5077, 5078, 5079, 5080, + 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, + 1961, 5089, 5090, 5091, 5092, 5093, 5094, 5095, + 5096, 5097, 5098, 5099, 5100, 1959, 5101, 5102, + 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, + 5111, 5112, 1958, 5113, 5114, 5115, 5116, 5117, + 5118, 5119, 5120, 5121, 5122, 5123, 5124, 5125, + 5126, 5127, 5128, 5075, 5076, 1960, 5077, 5078, + 5079, 5080, 5081, 5082, 5083, 5084, 5085, 5086, + 5087, 5088, 1961, 5089, 5090, 5091, 5092, 5093, + 5094, 5095, 5096, 5097, 5098, 5099, 5100, 1959, + 5101, 5102, 5103, 5104, 5105, 5106, 5107, 5108, + 5109, 5110, 5111, 5112, 1958, 5113, 5114, 5115, + 5116, 5117, 5118, 5119, 5120, 5121, 5122, 5123, + 5124, 5125, 5126, 5127, 5128, 5075, 5076, 1960, + 5077, 5078, 5079, 5080, 5081, 5082, 5083, 5084, + 5085, 5086, 5087, 5088, 1961, 5089, 5090, 5091, + 5092, 5093, 5094, 5095, 5096, 5097, 5098, 5099, + 5100, 1959, 5101, 5102, 5103, 5104, 5105, 5106, + 5107, 5108, 5109, 5110, 5111, 5112, 1958, 5113, + 5114, 5115, 5116, 5117, 5118, 5119, 5120, 5121, + 5122, 5123, 5124, 5125, 5126, 5127, 5128, 5075, + 5076, 1960, 5077, 5078, 5079, 5080, 5081, 5082, + 5083, 5084, 5085, 5086, 5087, 5088, 1961, 5089, + 5090, 5091, 5092, 5093, 5094, 5095, 5096, 5097, + 5098, 5099, 5100, 1959, 5101, 5102, 5103, 5104, + 5105, 5106, 5107, 5108, 5109, 5110, 5111, 5112, + 1958, 5113, 5114, 5115, 5116, 5117, 5118, 5119, + 5120, 5121, 5122, 5123, 5124, 5125, 5126, 5127, + 5128, 5075, 5076, 1960, 5077, 5078, 5079, 5080, + 5081, 5082, 5083, 5084, 5085, 5086, 5087, 5088, + 1961, 5089, 5090, 5091, 5092, 5093, 5094, 5095, + 5096, 5097, 5098, 5099, 5100, 1959, 5101, 5102, + 5103, 5104, 5105, 5106, 5107, 5108, 5109, 5110, + 5111, 5112, 1958, 5113, 5114, 5115, 5116, 5117, + 5118, 5119, 5120, 5121, 5122, 5123, 5124, 5125, + 5126, 5127, 5128, 5129, 5130, 0, 0, 5131, + 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, + 5140, 5131, 5132, 5133, 5134, 5135, 5136, 5137, + 5138, 5139, 5140, 5131, 5132, 5133, 5134, 5135, + 5136, 5137, 5138, 5139, 5140, 5131, 5132, 5133, + 5134, 5135, 5136, 5137, 5138, 5139, 5140, 5131, + 5132, 5133, 5134, 5135, 5136, 5137, 5138, 5139, + 5140, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 339, 339, 339, 339, 339, 339, 339, 339, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 5141, 5142, 5143, 5144, 5145, 3725, 5146, + 5147, 5148, 5149, 3726, 5150, 5151, 5152, 3727, + 5153, 5154, 5155, 5156, 5157, 5158, 5159, 5160, + 5161, 5162, 5163, 5164, 3782, 5165, 5166, 5167, + 5168, 5169, 5170, 5171, 5172, 5173, 3787, 3728, + 3729, 3788, 5174, 5175, 3538, 5176, 3730, 5177, + 5178, 5179, 5180, 5180, 5180, 5181, 5182, 5183, + 5184, 5185, 5186, 5187, 5188, 5189, 5190, 5191, + 5192, 5193, 5194, 5195, 5196, 5197, 5198, 5198, + 3790, 5199, 5200, 5201, 5202, 3732, 5203, 5204, + 5205, 3691, 5206, 5207, 5208, 5209, 5210, 5211, + 5212, 5213, 5214, 5215, 5216, 5217, 5218, 5219, + 5220, 5221, 5222, 5223, 5224, 5225, 5226, 5227, + 5228, 5229, 5230, 5231, 5231, 5232, 5233, 5234, + 3534, 5235, 5236, 5237, 5238, 5239, 5240, 5241, + 5242, 3737, 5243, 5244, 5245, 5246, 5247, 5248, + 5249, 5250, 5251, 5252, 5253, 5254, 5255, 5256, + 5257, 5258, 5259, 5260, 5261, 5262, 5263, 3480, + 5264, 5265, 5266, 5266, 5267, 5268, 5268, 5269, + 5270, 5271, 5272, 5273, 5274, 5275, 5276, 5277, + 5278, 5279, 5280, 5281, 3738, 5282, 5283, 5284, + 5285, 3802, 5285, 5286, 3740, 5287, 5288, 5289, + 5290, 3741, 3453, 5291, 5292, 5293, 5294, 5295, + 5296, 5297, 5298, 5299, 5300, 5301, 5302, 5303, + 5304, 5305, 5306, 5307, 5308, 5309, 5310, 5311, + 5312, 3742, 5313, 5314, 5315, 5316, 5317, 5318, + 3744, 5319, 5320, 5321, 5322, 5323, 5324, 5325, + 5326, 3481, 3810, 5327, 5328, 5329, 5330, 5331, + 5332, 5333, 5334, 3745, 5335, 5336, 5337, 5338, + 3853, 5339, 5340, 5341, 5342, 5343, 5344, 5345, + 5346, 5347, 5348, 5349, 5350, 5351, 3551, 5352, + 5353, 5354, 5355, 5356, 5357, 5358, 5359, 5360, + 5361, 5362, 3746, 3638, 5363, 5364, 5365, 5366, + 5367, 5368, 5369, 5370, 3814, 5371, 5372, 5373, + 5374, 5375, 5376, 5377, 5378, 3815, 5379, 5380, + 5381, 5382, 5383, 5384, 5385, 5386, 5387, 5388, + 5389, 5390, 3817, 5391, 5392, 5393, 5394, 5395, + 5396, 5397, 5398, 5399, 5400, 5401, 5401, 5402, + 5403, 3819, 5404, 5405, 5406, 5407, 5408, 5409, + 5410, 3537, 5411, 5412, 5413, 5414, 5415, 5416, + 5417, 3825, 5418, 5419, 5420, 5421, 5422, 5423, + 5423, 3826, 3855, 5424, 5425, 5426, 5427, 5428, + 3499, 3828, 5429, 5430, 3757, 5431, 5432, 3713, + 5433, 5434, 3761, 5435, 5436, 5437, 5438, 5438, + 5439, 5440, 5441, 5442, 5443, 5444, 5445, 5446, + 5447, 5448, 5449, 5450, 5451, 5452, 5453, 5454, + 5455, 5456, 5457, 5458, 5459, 5460, 5461, 5462, + 5463, 5464, 5465, 3767, 5466, 5467, 5468, 5469, + 5470, 5471, 5472, 5473, 5474, 5475, 5476, 5477, + 5478, 5479, 5480, 5481, 5267, 5482, 5483, 5484, + 5485, 5486, 5487, 5488, 5489, 5490, 5491, 5492, + 5493, 3555, 5494, 5495, 5496, 5497, 5498, 5499, + 3770, 5500, 5501, 5502, 5503, 5504, 5505, 5506, + 5507, 5508, 5509, 5510, 5511, 5512, 5513, 5514, + 5515, 5516, 5517, 5518, 5519, 3494, 5520, 5521, + 5522, 5523, 5524, 5525, 3835, 5526, 5527, 5528, + 5529, 5530, 5531, 5532, 5533, 5534, 5535, 5536, + 5537, 5538, 5539, 5540, 5541, 5542, 5543, 5544, + 5545, 3840, 3841, 5546, 5547, 5548, 5549, 5550, + 5551, 5552, 5553, 5554, 5555, 5556, 5557, 5558, + 3842, 5559, 5560, 5561, 5562, 5563, 5564, 5565, + 5566, 5567, 5568, 5569, 5570, 5571, 5572, 5573, + 5574, 5575, 5576, 5577, 5578, 5579, 5580, 5581, + 5582, 5583, 5584, 5585, 5586, 5587, 5588, 3848, + 3848, 5589, 5590, 5591, 5592, 5593, 5594, 5595, + 5596, 5597, 5598, 3849, 5599, 5600, 5601, 5602, + 5603, 5604, 5605, 5606, 5607, 5608, 5609, 5610, + 5611, 5612, 5613, 5614, 5615, 5616, 5617, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 80, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 80, 80, 80, 80, 80, 80, 80, + 80, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 558, 558, 558, 558, 558, 558, 558, + 558, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 3440, + 3440, 3440, 3440, 3440, 3440, 3440, 3440, 0, + 0, }; + +const utf8proc_property_t utf8proc_properties[] = { + {0, 0, 0, 0, NULL, false, -1, -1, -1, -1, -1, false}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_S, 0, NULL, false, -1, -1, -1, -1, -1, false, false, true, false, NULL}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, NULL, false, -1, -1, -1, -1, -1, false, false, true, false, NULL}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_WS, 0, NULL, false, -1, -1, -1, -1, -1, false, false, true, false, NULL}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_B, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_S, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17580, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 17400, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17640, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 97, -1, 0, -1, false, false, false, false, utf8proc_sequences + 0}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 98, -1, 8640, -1, false, false, false, false, utf8proc_sequences + 2}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 99, -1, 60, -1, false, false, false, false, utf8proc_sequences + 4}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 100, -1, 960, -1, false, false, false, false, utf8proc_sequences + 6}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 101, -1, 120, -1, false, false, false, false, utf8proc_sequences + 8}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 102, -1, 9120, -1, false, false, false, false, utf8proc_sequences + 10}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 103, -1, 1080, -1, false, false, false, false, utf8proc_sequences + 12}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 104, -1, 1200, -1, false, false, false, false, utf8proc_sequences + 14}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 105, -1, 180, -1, false, false, false, false, utf8proc_sequences + 16}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 106, -1, 1320, -1, false, false, false, false, utf8proc_sequences + 18}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 107, -1, 1440, -1, false, false, false, false, utf8proc_sequences + 20}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 108, -1, 1560, -1, false, false, false, false, utf8proc_sequences + 22}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 109, -1, 9480, -1, false, false, false, false, utf8proc_sequences + 24}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 110, -1, 240, -1, false, false, false, false, utf8proc_sequences + 26}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 111, -1, 300, -1, false, false, false, false, utf8proc_sequences + 28}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 112, -1, 9720, -1, false, false, false, false, utf8proc_sequences + 30}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 113, -1, -1, -1, false, false, false, false, utf8proc_sequences + 32}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 114, -1, 1680, -1, false, false, false, false, utf8proc_sequences + 34}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 115, -1, 1800, -1, false, false, false, false, utf8proc_sequences + 36}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 116, -1, 1920, -1, false, false, false, false, utf8proc_sequences + 38}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 117, -1, 360, -1, false, false, false, false, utf8proc_sequences + 40}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 118, -1, 10560, -1, false, false, false, false, utf8proc_sequences + 42}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 119, -1, 2040, -1, false, false, false, false, utf8proc_sequences + 44}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 120, -1, 10680, -1, false, false, false, false, utf8proc_sequences + 46}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 121, -1, 420, -1, false, false, false, false, utf8proc_sequences + 48}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 122, -1, 2160, -1, false, false, false, false, utf8proc_sequences + 50}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 65, -1, 65, 480, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66, -1, 66, 8700, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 67, -1, 67, 540, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 68, -1, 68, 1020, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 69, -1, 69, 600, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 70, -1, 70, 9180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 71, -1, 71, 1140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 72, -1, 72, 1260, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 73, -1, 73, 660, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 74, -1, 74, 1380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 75, -1, 75, 1500, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 76, -1, 76, 1620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 77, -1, 77, 9540, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 78, -1, 78, 720, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 79, -1, 79, 780, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 80, -1, 80, 9780, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 81, -1, 81, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 82, -1, 82, 1740, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 83, -1, 83, 1860, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 84, -1, 84, 1980, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 85, -1, 85, 840, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 86, -1, 86, 10620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 87, -1, 87, 2100, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 88, -1, 88, 10740, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 89, -1, 89, 900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 90, -1, 90, 2220, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_NOBREAK, utf8proc_sequences + 52, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 54, false, -1, -1, -1, 3600, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 0, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PI, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 57, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ET, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ET, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 60, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 62, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 64, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 67, false, 924, -1, 924, -1, -1, false, false, false, false, utf8proc_sequences + 67}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 69, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 72, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 28, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PF, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 74, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 78, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 82, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 86, false, -1, 224, -1, -1, -1, false, false, false, false, utf8proc_sequences + 89}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 91, false, -1, 225, -1, -1, -1, false, false, false, false, utf8proc_sequences + 94}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 96, false, -1, 226, -1, 10860, -1, false, false, false, false, utf8proc_sequences + 99}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 101, false, -1, 227, -1, -1, -1, false, false, false, false, utf8proc_sequences + 104}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 106, false, -1, 228, -1, 2400, -1, false, false, false, false, utf8proc_sequences + 109}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 111, false, -1, 229, -1, 3000, -1, false, false, false, false, utf8proc_sequences + 114}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 230, -1, 2640, -1, false, false, false, false, utf8proc_sequences + 116}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 118, false, -1, 231, -1, 8760, -1, false, false, false, false, utf8proc_sequences + 121}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 123, false, -1, 232, -1, -1, -1, false, false, false, false, utf8proc_sequences + 126}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 128, false, -1, 233, -1, -1, -1, false, false, false, false, utf8proc_sequences + 131}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 133, false, -1, 234, -1, 11220, -1, false, false, false, false, utf8proc_sequences + 136}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 138, false, -1, 235, -1, -1, -1, false, false, false, false, utf8proc_sequences + 141}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 143, false, -1, 236, -1, -1, -1, false, false, false, false, utf8proc_sequences + 146}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 148, false, -1, 237, -1, -1, -1, false, false, false, false, utf8proc_sequences + 151}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 153, false, -1, 238, -1, -1, -1, false, false, false, false, utf8proc_sequences + 156}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 158, false, -1, 239, -1, 9240, -1, false, false, false, false, utf8proc_sequences + 161}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 240, -1, -1, -1, false, false, false, false, utf8proc_sequences + 163}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 165, false, -1, 241, -1, -1, -1, false, false, false, false, utf8proc_sequences + 168}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 170, false, -1, 242, -1, -1, -1, false, false, false, false, utf8proc_sequences + 173}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 175, false, -1, 243, -1, -1, -1, false, false, false, false, utf8proc_sequences + 178}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 180, false, -1, 244, -1, 11460, -1, false, false, false, false, utf8proc_sequences + 183}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 185, false, -1, 245, -1, 3360, -1, false, false, false, false, utf8proc_sequences + 188}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 190, false, -1, 246, -1, 3240, -1, false, false, false, false, utf8proc_sequences + 193}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 248, -1, 3120, -1, false, false, false, false, utf8proc_sequences + 195}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 197, false, -1, 249, -1, -1, -1, false, false, false, false, utf8proc_sequences + 200}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 202, false, -1, 250, -1, -1, -1, false, false, false, false, utf8proc_sequences + 205}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 207, false, -1, 251, -1, -1, -1, false, false, false, false, utf8proc_sequences + 210}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 212, false, -1, 252, -1, 2280, -1, false, false, false, false, utf8proc_sequences + 215}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 217, false, -1, 253, -1, -1, -1, false, false, false, false, utf8proc_sequences + 220}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 254, -1, -1, -1, false, false, false, false, utf8proc_sequences + 222}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 224}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 227, false, 192, -1, 192, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 230, false, 193, -1, 193, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 233, false, 194, -1, 194, 10920, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 236, false, 195, -1, 195, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 239, false, 196, -1, 196, 2460, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 242, false, 197, -1, 197, 3060, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 198, -1, 198, 2700, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 245, false, 199, -1, 199, 8820, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 248, false, 200, -1, 200, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 251, false, 201, -1, 201, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 254, false, 202, -1, 202, 11280, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 257, false, 203, -1, 203, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 260, false, 204, -1, 204, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 263, false, 205, -1, 205, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 266, false, 206, -1, 206, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 269, false, 207, -1, 207, 9300, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 208, -1, 208, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 272, false, 209, -1, 209, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 275, false, 210, -1, 210, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 278, false, 211, -1, 211, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 281, false, 212, -1, 212, 11520, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 284, false, 213, -1, 213, 3420, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 287, false, 214, -1, 214, 3300, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 216, -1, 216, 3180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 290, false, 217, -1, 217, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 293, false, 218, -1, 218, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 296, false, 219, -1, 219, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 299, false, 220, -1, 220, 2340, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 302, false, 221, -1, 221, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 222, -1, 222, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 305, false, 376, -1, 376, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 308, false, -1, 257, -1, -1, -1, false, false, false, false, utf8proc_sequences + 311}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 313, false, 256, -1, 256, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 316, false, -1, 259, -1, 11100, -1, false, false, false, false, utf8proc_sequences + 319}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 321, false, 258, -1, 258, 11160, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 324, false, -1, 261, -1, -1, -1, false, false, false, false, utf8proc_sequences + 327}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 329, false, 260, -1, 260, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 332, false, -1, 263, -1, -1, -1, false, false, false, false, utf8proc_sequences + 335}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 337, false, 262, -1, 262, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 340, false, -1, 265, -1, -1, -1, false, false, false, false, utf8proc_sequences + 343}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 345, false, 264, -1, 264, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 348, false, -1, 267, -1, -1, -1, false, false, false, false, utf8proc_sequences + 351}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 353, false, 266, -1, 266, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 356, false, -1, 269, -1, -1, -1, false, false, false, false, utf8proc_sequences + 359}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 361, false, 268, -1, 268, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 364, false, -1, 271, -1, -1, -1, false, false, false, false, utf8proc_sequences + 367}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 369, false, 270, -1, 270, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 273, -1, -1, -1, false, false, false, false, utf8proc_sequences + 372}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 272, -1, 272, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 374, false, -1, 275, -1, 8880, -1, false, false, false, false, utf8proc_sequences + 377}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 379, false, 274, -1, 274, 8940, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 382, false, -1, 277, -1, -1, -1, false, false, false, false, utf8proc_sequences + 385}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 387, false, 276, -1, 276, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 390, false, -1, 279, -1, -1, -1, false, false, false, false, utf8proc_sequences + 393}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 395, false, 278, -1, 278, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 398, false, -1, 281, -1, -1, -1, false, false, false, false, utf8proc_sequences + 401}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 403, false, 280, -1, 280, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 406, false, -1, 283, -1, -1, -1, false, false, false, false, utf8proc_sequences + 409}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 411, false, 282, -1, 282, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 414, false, -1, 285, -1, -1, -1, false, false, false, false, utf8proc_sequences + 417}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 419, false, 284, -1, 284, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 422, false, -1, 287, -1, -1, -1, false, false, false, false, utf8proc_sequences + 425}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 427, false, 286, -1, 286, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 430, false, -1, 289, -1, -1, -1, false, false, false, false, utf8proc_sequences + 433}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 435, false, 288, -1, 288, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 438, false, -1, 291, -1, -1, -1, false, false, false, false, utf8proc_sequences + 441}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 443, false, 290, -1, 290, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 446, false, -1, 293, -1, -1, -1, false, false, false, false, utf8proc_sequences + 449}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 451, false, 292, -1, 292, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 295, -1, -1, -1, false, false, false, false, utf8proc_sequences + 454}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 294, -1, 294, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 456, false, -1, 297, -1, -1, -1, false, false, false, false, utf8proc_sequences + 459}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 461, false, 296, -1, 296, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 464, false, -1, 299, -1, -1, -1, false, false, false, false, utf8proc_sequences + 467}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 469, false, 298, -1, 298, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 472, false, -1, 301, -1, -1, -1, false, false, false, false, utf8proc_sequences + 475}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 477, false, 300, -1, 300, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 480, false, -1, 303, -1, -1, -1, false, false, false, false, utf8proc_sequences + 483}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 485, false, 302, -1, 302, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 488, false, -1, 105, -1, -1, -1, false, false, false, false, utf8proc_sequences + 491}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 73, -1, 73, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 494, false, -1, 307, -1, -1, -1, false, false, false, false, utf8proc_sequences + 497}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 499, false, 306, -1, 306, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 502, false, -1, 309, -1, -1, -1, false, false, false, false, utf8proc_sequences + 505}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 507, false, 308, -1, 308, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 510, false, -1, 311, -1, -1, -1, false, false, false, false, utf8proc_sequences + 513}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 515, false, 310, -1, 310, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 518, false, -1, 314, -1, -1, -1, false, false, false, false, utf8proc_sequences + 521}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 523, false, 313, -1, 313, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 526, false, -1, 316, -1, -1, -1, false, false, false, false, utf8proc_sequences + 529}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 531, false, 315, -1, 315, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 534, false, -1, 318, -1, -1, -1, false, false, false, false, utf8proc_sequences + 537}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 539, false, 317, -1, 317, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 542, false, -1, 320, -1, -1, -1, false, false, false, false, utf8proc_sequences + 545}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 547, false, 319, -1, 319, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 322, -1, -1, -1, false, false, false, false, utf8proc_sequences + 550}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 321, -1, 321, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 552, false, -1, 324, -1, -1, -1, false, false, false, false, utf8proc_sequences + 555}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 557, false, 323, -1, 323, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 560, false, -1, 326, -1, -1, -1, false, false, false, false, utf8proc_sequences + 563}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 565, false, 325, -1, 325, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 568, false, -1, 328, -1, -1, -1, false, false, false, false, utf8proc_sequences + 571}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 573, false, 327, -1, 327, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 576, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 576}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 331, -1, -1, -1, false, false, false, false, utf8proc_sequences + 579}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 330, -1, 330, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 581, false, -1, 333, -1, 9600, -1, false, false, false, false, utf8proc_sequences + 584}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 586, false, 332, -1, 332, 9660, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 589, false, -1, 335, -1, -1, -1, false, false, false, false, utf8proc_sequences + 592}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 594, false, 334, -1, 334, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 597, false, -1, 337, -1, -1, -1, false, false, false, false, utf8proc_sequences + 600}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 602, false, 336, -1, 336, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 339, -1, -1, -1, false, false, false, false, utf8proc_sequences + 605}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 338, -1, 338, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 607, false, -1, 341, -1, -1, -1, false, false, false, false, utf8proc_sequences + 610}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 612, false, 340, -1, 340, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 615, false, -1, 343, -1, -1, -1, false, false, false, false, utf8proc_sequences + 618}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 620, false, 342, -1, 342, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 623, false, -1, 345, -1, -1, -1, false, false, false, false, utf8proc_sequences + 626}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 628, false, 344, -1, 344, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 631, false, -1, 347, -1, 9960, -1, false, false, false, false, utf8proc_sequences + 634}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 636, false, 346, -1, 346, 10020, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 639, false, -1, 349, -1, -1, -1, false, false, false, false, utf8proc_sequences + 642}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 644, false, 348, -1, 348, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 647, false, -1, 351, -1, -1, -1, false, false, false, false, utf8proc_sequences + 650}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 652, false, 350, -1, 350, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 655, false, -1, 353, -1, 10080, -1, false, false, false, false, utf8proc_sequences + 658}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 660, false, 352, -1, 352, 10140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 663, false, -1, 355, -1, -1, -1, false, false, false, false, utf8proc_sequences + 666}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 668, false, 354, -1, 354, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 671, false, -1, 357, -1, -1, -1, false, false, false, false, utf8proc_sequences + 674}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 676, false, 356, -1, 356, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 359, -1, -1, -1, false, false, false, false, utf8proc_sequences + 679}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 358, -1, 358, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 681, false, -1, 361, -1, 10320, -1, false, false, false, false, utf8proc_sequences + 684}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 686, false, 360, -1, 360, 10380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 689, false, -1, 363, -1, 10440, -1, false, false, false, false, utf8proc_sequences + 692}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 694, false, 362, -1, 362, 10500, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 697, false, -1, 365, -1, -1, -1, false, false, false, false, utf8proc_sequences + 700}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 702, false, 364, -1, 364, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 705, false, -1, 367, -1, -1, -1, false, false, false, false, utf8proc_sequences + 708}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 710, false, 366, -1, 366, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 713, false, -1, 369, -1, -1, -1, false, false, false, false, utf8proc_sequences + 716}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 718, false, 368, -1, 368, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 721, false, -1, 371, -1, -1, -1, false, false, false, false, utf8proc_sequences + 724}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 726, false, 370, -1, 370, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 729, false, -1, 373, -1, -1, -1, false, false, false, false, utf8proc_sequences + 732}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 734, false, 372, -1, 372, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 737, false, -1, 375, -1, -1, -1, false, false, false, false, utf8proc_sequences + 740}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 742, false, 374, -1, 374, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 745, false, -1, 255, -1, -1, -1, false, false, false, false, utf8proc_sequences + 748}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 750, false, -1, 378, -1, -1, -1, false, false, false, false, utf8proc_sequences + 753}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 755, false, 377, -1, 377, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 758, false, -1, 380, -1, -1, -1, false, false, false, false, utf8proc_sequences + 761}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 763, false, 379, -1, 379, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 766, false, -1, 382, -1, -1, -1, false, false, false, false, utf8proc_sequences + 769}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 771, false, 381, -1, 381, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 36, false, 83, -1, 83, 10800, -1, false, false, false, false, utf8proc_sequences + 36}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 579, -1, 579, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 595, -1, -1, -1, false, false, false, false, utf8proc_sequences + 774}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 387, -1, -1, -1, false, false, false, false, utf8proc_sequences + 776}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 386, -1, 386, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 389, -1, -1, -1, false, false, false, false, utf8proc_sequences + 778}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 388, -1, 388, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 596, -1, -1, -1, false, false, false, false, utf8proc_sequences + 780}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 392, -1, -1, -1, false, false, false, false, utf8proc_sequences + 782}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 391, -1, 391, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 598, -1, -1, -1, false, false, false, false, utf8proc_sequences + 784}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 599, -1, -1, -1, false, false, false, false, utf8proc_sequences + 786}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 396, -1, -1, -1, false, false, false, false, utf8proc_sequences + 788}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 395, -1, 395, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 477, -1, -1, -1, false, false, false, false, utf8proc_sequences + 790}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 601, -1, -1, -1, false, false, false, false, utf8proc_sequences + 792}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 603, -1, -1, -1, false, false, false, false, utf8proc_sequences + 794}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 402, -1, -1, -1, false, false, false, false, utf8proc_sequences + 796}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 401, -1, 401, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 608, -1, -1, -1, false, false, false, false, utf8proc_sequences + 798}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 611, -1, -1, -1, false, false, false, false, utf8proc_sequences + 800}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 502, -1, 502, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 617, -1, -1, -1, false, false, false, false, utf8proc_sequences + 802}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 616, -1, -1, -1, false, false, false, false, utf8proc_sequences + 804}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 409, -1, -1, -1, false, false, false, false, utf8proc_sequences + 806}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 408, -1, 408, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 573, -1, 573, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 623, -1, -1, -1, false, false, false, false, utf8proc_sequences + 808}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 626, -1, -1, -1, false, false, false, false, utf8proc_sequences + 810}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 544, -1, 544, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 629, -1, -1, -1, false, false, false, false, utf8proc_sequences + 812}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 814, false, -1, 417, -1, 11700, -1, false, false, false, false, utf8proc_sequences + 817}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 819, false, 416, -1, 416, 11760, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 419, -1, -1, -1, false, false, false, false, utf8proc_sequences + 822}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 418, -1, 418, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 421, -1, -1, -1, false, false, false, false, utf8proc_sequences + 824}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 420, -1, 420, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 640, -1, -1, -1, false, false, false, false, utf8proc_sequences + 826}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 424, -1, -1, -1, false, false, false, false, utf8proc_sequences + 828}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 423, -1, 423, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 643, -1, -1, -1, false, false, false, false, utf8proc_sequences + 830}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 429, -1, -1, -1, false, false, false, false, utf8proc_sequences + 832}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 428, -1, 428, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 648, -1, -1, -1, false, false, false, false, utf8proc_sequences + 834}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 836, false, -1, 432, -1, 11820, -1, false, false, false, false, utf8proc_sequences + 839}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 841, false, 431, -1, 431, 11880, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 650, -1, -1, -1, false, false, false, false, utf8proc_sequences + 844}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 651, -1, -1, -1, false, false, false, false, utf8proc_sequences + 846}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 436, -1, -1, -1, false, false, false, false, utf8proc_sequences + 848}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 435, -1, 435, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 438, -1, -1, -1, false, false, false, false, utf8proc_sequences + 850}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 437, -1, 437, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 658, -1, 2880, -1, false, false, false, false, utf8proc_sequences + 852}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 441, -1, -1, -1, false, false, false, false, utf8proc_sequences + 854}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 440, -1, 440, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 445, -1, -1, -1, false, false, false, false, utf8proc_sequences + 856}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 444, -1, 444, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 503, -1, 503, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 858, false, -1, 454, 453, -1, -1, false, false, false, false, utf8proc_sequences + 861}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 863, false, 452, 454, 453, -1, -1, false, false, false, false, utf8proc_sequences + 861}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 866, false, 452, -1, 453, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 869, false, -1, 457, 456, -1, -1, false, false, false, false, utf8proc_sequences + 872}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 874, false, 455, 457, 456, -1, -1, false, false, false, false, utf8proc_sequences + 872}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 877, false, 455, -1, 456, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 880, false, -1, 460, 459, -1, -1, false, false, false, false, utf8proc_sequences + 883}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 885, false, 458, 460, 459, -1, -1, false, false, false, false, utf8proc_sequences + 883}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 888, false, 458, -1, 459, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 891, false, -1, 462, -1, -1, -1, false, false, false, false, utf8proc_sequences + 894}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 896, false, 461, -1, 461, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 899, false, -1, 464, -1, -1, -1, false, false, false, false, utf8proc_sequences + 902}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 904, false, 463, -1, 463, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 907, false, -1, 466, -1, -1, -1, false, false, false, false, utf8proc_sequences + 910}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 912, false, 465, -1, 465, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 915, false, -1, 468, -1, -1, -1, false, false, false, false, utf8proc_sequences + 918}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 920, false, 467, -1, 467, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 923, false, -1, 470, -1, -1, -1, false, false, false, false, utf8proc_sequences + 926}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 928, false, 469, -1, 469, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 931, false, -1, 472, -1, -1, -1, false, false, false, false, utf8proc_sequences + 934}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 936, false, 471, -1, 471, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 939, false, -1, 474, -1, -1, -1, false, false, false, false, utf8proc_sequences + 942}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 944, false, 473, -1, 473, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 947, false, -1, 476, -1, -1, -1, false, false, false, false, utf8proc_sequences + 950}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 952, false, 475, -1, 475, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 398, -1, 398, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 955, false, -1, 479, -1, -1, -1, false, false, false, false, utf8proc_sequences + 958}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 960, false, 478, -1, 478, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 963, false, -1, 481, -1, -1, -1, false, false, false, false, utf8proc_sequences + 966}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 968, false, 480, -1, 480, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 971, false, -1, 483, -1, -1, -1, false, false, false, false, utf8proc_sequences + 974}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 976, false, 482, -1, 482, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 485, -1, -1, -1, false, false, false, false, utf8proc_sequences + 979}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 484, -1, 484, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 981, false, -1, 487, -1, -1, -1, false, false, false, false, utf8proc_sequences + 984}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 986, false, 486, -1, 486, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 989, false, -1, 489, -1, -1, -1, false, false, false, false, utf8proc_sequences + 992}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 994, false, 488, -1, 488, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 997, false, -1, 491, -1, 2760, -1, false, false, false, false, utf8proc_sequences + 1000}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1002, false, 490, -1, 490, 2820, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1005, false, -1, 493, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1008}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1010, false, 492, -1, 492, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1013, false, -1, 495, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1016}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1018, false, 494, -1, 494, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1021, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1021}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1024, false, -1, 499, 498, -1, -1, false, false, false, false, utf8proc_sequences + 1027}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1029, false, 497, 499, 498, -1, -1, false, false, false, false, utf8proc_sequences + 1027}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1032, false, 497, -1, 498, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1035, false, -1, 501, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1038}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1040, false, 500, -1, 500, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 405, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1043}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 447, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1045}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1047, false, -1, 505, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1050}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1052, false, 504, -1, 504, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1055, false, -1, 507, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1058}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1060, false, 506, -1, 506, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1063, false, -1, 509, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1066}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1068, false, 508, -1, 508, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1071, false, -1, 511, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1074}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1076, false, 510, -1, 510, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1079, false, -1, 513, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1082}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1084, false, 512, -1, 512, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1087, false, -1, 515, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1090}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1092, false, 514, -1, 514, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1095, false, -1, 517, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1098}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1100, false, 516, -1, 516, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1103, false, -1, 519, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1106}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1108, false, 518, -1, 518, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1111, false, -1, 521, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1114}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1116, false, 520, -1, 520, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1119, false, -1, 523, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1122}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1124, false, 522, -1, 522, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1127, false, -1, 525, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1130}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1132, false, 524, -1, 524, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1135, false, -1, 527, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1138}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1140, false, 526, -1, 526, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1143, false, -1, 529, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1146}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1148, false, 528, -1, 528, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1151, false, -1, 531, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1154}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1156, false, 530, -1, 530, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1159, false, -1, 533, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1162}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1164, false, 532, -1, 532, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1167, false, -1, 535, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1170}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1172, false, 534, -1, 534, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1175, false, -1, 537, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1178}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1180, false, 536, -1, 536, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1183, false, -1, 539, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1186}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1188, false, 538, -1, 538, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 541, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1191}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 540, -1, 540, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1193, false, -1, 543, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1196}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1198, false, 542, -1, 542, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 414, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1201}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 547, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1203}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 546, -1, 546, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 549, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1205}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 548, -1, 548, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1207, false, -1, 551, -1, 2520, -1, false, false, false, false, utf8proc_sequences + 1210}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1212, false, 550, -1, 550, 2580, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1215, false, -1, 553, -1, 9000, -1, false, false, false, false, utf8proc_sequences + 1218}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1220, false, 552, -1, 552, 9060, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1223, false, -1, 555, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1226}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1228, false, 554, -1, 554, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1231, false, -1, 557, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1234}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1236, false, 556, -1, 556, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1239, false, -1, 559, -1, 3480, -1, false, false, false, false, utf8proc_sequences + 1242}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1244, false, 558, -1, 558, 3540, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1247, false, -1, 561, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1250}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1252, false, 560, -1, 560, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1255, false, -1, 563, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1258}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1260, false, 562, -1, 562, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11365, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1263}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 572, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1265}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 571, -1, 571, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 410, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1267}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11366, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1269}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 578, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1271}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 577, -1, 577, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 384, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1273}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 649, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1275}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 652, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1277}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 583, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1279}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 582, -1, 582, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 585, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1281}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 584, -1, 584, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 587, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1283}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 586, -1, 586, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 589, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1285}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 588, -1, 588, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 591, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1287}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 590, -1, 590, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 385, -1, 385, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 390, -1, 390, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 393, -1, 393, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 394, -1, 394, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 399, -1, 399, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 400, -1, 400, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 403, -1, 403, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 404, -1, 404, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 407, -1, 407, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 406, -1, 406, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11362, -1, 11362, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 412, -1, 412, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 413, -1, 413, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 415, -1, 415, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11364, -1, 11364, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 422, -1, 422, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 425, -1, 425, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 430, -1, 430, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 580, -1, 580, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 433, -1, 433, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 434, -1, 434, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 581, -1, 581, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 439, -1, 439, 2940, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 14, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1289, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 18, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 34, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1291, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1293, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1295, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 44, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 48, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1297, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1300, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1303, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1306, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1309, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1312, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 800, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 22, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 36, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 46, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1315, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 0, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 2, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 3, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 7, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 8, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 10, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 4, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 46, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 5, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 12, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 11, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 14, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 15, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 47, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 48, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 232, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 13, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 40, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 45, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 39, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 16, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 6, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 202, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 9, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 42, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 44, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 43, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 41, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 1, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 1, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 51, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 1317, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 1319, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 49, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 1321, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 1323, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 240, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, 921, -1, 921, -1, 50, false, false, false, true, utf8proc_sequences + 1326}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, true, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 233, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 234, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 1328, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1330, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1021, -1, 1021, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1022, -1, 1022, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1023, -1, 1023, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 1333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 1335, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1338, false, -1, 940, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1341}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 1343, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1345, false, -1, 941, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1348}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1350, false, -1, 942, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1353}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1355, false, -1, 943, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1358}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1360, false, -1, 972, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1363}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1365, false, -1, 973, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1368}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1370, false, -1, 974, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1373}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1375, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1378}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 945, -1, 3660, -1, false, false, false, false, utf8proc_sequences + 1382}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 946, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1384}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 947, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1386}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 948, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1388}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 949, -1, 3720, -1, false, false, false, false, utf8proc_sequences + 1390}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 950, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1392}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 951, -1, 3780, -1, false, false, false, false, utf8proc_sequences + 1394}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 952, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1396}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 953, -1, 3840, -1, false, false, false, false, utf8proc_sequences + 1326}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 954, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1398}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 955, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1400}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 956, -1, -1, -1, false, false, false, false, utf8proc_sequences + 67}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 957, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1402}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 958, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1404}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 959, -1, 3900, -1, false, false, false, false, utf8proc_sequences + 1406}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 960, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1408}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 961, -1, 16260, -1, false, false, false, false, utf8proc_sequences + 1410}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 963, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1412}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 964, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1414}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 965, -1, 3960, -1, false, false, false, false, utf8proc_sequences + 1416}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 966, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1418}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 967, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1420}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 968, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1422}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 969, -1, 4020, -1, false, false, false, false, utf8proc_sequences + 1424}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1426, false, -1, 970, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1429}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1431, false, -1, 971, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1434}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1436, false, 902, -1, 902, 15780, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1439, false, 904, -1, 904, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1442, false, 905, -1, 905, 15960, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1445, false, 906, -1, 906, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1448, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1451}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 913, -1, 913, 4140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 914, -1, 914, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 915, -1, 915, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 916, -1, 916, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 917, -1, 917, 4200, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 918, -1, 918, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 919, -1, 919, 4260, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 920, -1, 920, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 921, -1, 921, 4320, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 922, -1, 922, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 923, -1, 923, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 924, -1, 924, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 925, -1, 925, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 926, -1, 926, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 927, -1, 927, 4500, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 928, -1, 928, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 929, -1, 929, 16200, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 931, -1, 931, -1, -1, false, false, false, false, utf8proc_sequences + 1412}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 931, -1, 931, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 932, -1, 932, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 933, -1, 933, 4440, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 934, -1, 934, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 935, -1, 935, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 936, -1, 936, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 937, -1, 937, 4560, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1455, false, 938, -1, 938, 4080, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1458, false, 939, -1, 939, 4380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1461, false, 908, -1, 908, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1464, false, 910, -1, 910, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1467, false, 911, -1, 911, 16380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1384, false, 914, -1, 914, -1, -1, false, false, false, false, utf8proc_sequences + 1384}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1396, false, 920, -1, 920, -1, -1, false, false, false, false, utf8proc_sequences + 1396}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1470, false, -1, -1, -1, 4620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1472, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1475, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1418, false, 934, -1, 934, -1, -1, false, false, false, false, utf8proc_sequences + 1418}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1408, false, 928, -1, 928, -1, -1, false, false, false, false, utf8proc_sequences + 1408}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 985, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1478}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 984, -1, 984, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 987, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1480}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 986, -1, 986, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 989, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1482}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 988, -1, 988, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 991, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1484}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 990, -1, 990, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 993, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1486}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 992, -1, 992, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 995, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1488}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 994, -1, 994, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 997, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1490}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 996, -1, 996, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 999, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1492}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 998, -1, 998, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1001, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1494}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1000, -1, 1000, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1003, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1496}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1002, -1, 1002, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1005, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1498}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1004, -1, 1004, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1007, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1500}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1006, -1, 1006, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1398, false, 922, -1, 922, -1, -1, false, false, false, false, utf8proc_sequences + 1398}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1410, false, 929, -1, 929, -1, -1, false, false, false, false, utf8proc_sequences + 1410}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1502, false, 1017, -1, 1017, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1504, false, -1, 952, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1396}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1390, false, 917, -1, 917, -1, -1, false, false, false, false, utf8proc_sequences + 1390}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1016, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1506}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1015, -1, 1015, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 1508, false, -1, 1010, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1510}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1019, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1512}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1018, -1, 1018, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 891, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1514}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 892, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1516}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 893, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1518}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1520, false, -1, 1104, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1523}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1525, false, -1, 1105, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1528}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1106, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1530}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1532, false, -1, 1107, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1535}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1108, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1537}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1109, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1539}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1110, -1, 4800, -1, false, false, false, false, utf8proc_sequences + 1541}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1543, false, -1, 1111, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1546}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1112, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1548}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1113, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1550}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1114, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1552}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1115, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1554}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1556, false, -1, 1116, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1559}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1561, false, -1, 1117, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1564}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1566, false, -1, 1118, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1569}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1119, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1571}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1072, -1, 5640, -1, false, false, false, false, utf8proc_sequences + 1573}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1073, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1575}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1074, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1577}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1075, -1, 4740, -1, false, false, false, false, utf8proc_sequences + 1579}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1076, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1581}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1077, -1, 4680, -1, false, false, false, false, utf8proc_sequences + 1583}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1078, -1, 5520, -1, false, false, false, false, utf8proc_sequences + 1585}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1079, -1, 5880, -1, false, false, false, false, utf8proc_sequences + 1587}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1080, -1, 4920, -1, false, false, false, false, utf8proc_sequences + 1589}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1591, false, -1, 1081, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1594}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1082, -1, 4860, -1, false, false, false, false, utf8proc_sequences + 1596}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1083, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1598}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1084, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1600}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1085, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1602}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1086, -1, 6000, -1, false, false, false, false, utf8proc_sequences + 1604}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1087, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1606}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1088, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1608}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1089, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1610}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1090, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1612}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1091, -1, 4980, -1, false, false, false, false, utf8proc_sequences + 1614}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1092, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1616}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1093, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1618}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1094, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1620}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1095, -1, 6360, -1, false, false, false, false, utf8proc_sequences + 1622}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1096, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1624}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1097, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1626}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1098, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1628}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1099, -1, 6480, -1, false, false, false, false, utf8proc_sequences + 1630}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1100, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1632}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1101, -1, 6240, -1, false, false, false, false, utf8proc_sequences + 1634}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1102, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1636}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1103, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1638}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1040, -1, 1040, 5700, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1041, -1, 1041, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1042, -1, 1042, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1043, -1, 1043, 5160, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1044, -1, 1044, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1045, -1, 1045, 5100, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1046, -1, 1046, 5580, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1047, -1, 1047, 5940, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1048, -1, 1048, 5040, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1640, false, 1049, -1, 1049, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1050, -1, 1050, 5280, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1051, -1, 1051, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1052, -1, 1052, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1053, -1, 1053, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1054, -1, 1054, 6060, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1055, -1, 1055, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1056, -1, 1056, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1057, -1, 1057, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1058, -1, 1058, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1059, -1, 1059, 5340, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1060, -1, 1060, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1061, -1, 1061, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1062, -1, 1062, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1063, -1, 1063, 6420, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1064, -1, 1064, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1065, -1, 1065, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1066, -1, 1066, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1067, -1, 1067, 6540, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1068, -1, 1068, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1069, -1, 1069, 6300, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1070, -1, 1070, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1071, -1, 1071, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1643, false, 1024, -1, 1024, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1646, false, 1025, -1, 1025, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1026, -1, 1026, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1649, false, 1027, -1, 1027, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1028, -1, 1028, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1029, -1, 1029, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1030, -1, 1030, 5220, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1652, false, 1031, -1, 1031, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1032, -1, 1032, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1033, -1, 1033, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1034, -1, 1034, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1035, -1, 1035, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1655, false, 1036, -1, 1036, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1658, false, 1037, -1, 1037, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1661, false, 1038, -1, 1038, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1039, -1, 1039, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1121, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1664}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1120, -1, 1120, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1123, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1666}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1122, -1, 1122, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1125, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1668}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1124, -1, 1124, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1127, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1670}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1126, -1, 1126, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1129, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1672}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1128, -1, 1128, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1131, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1674}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1130, -1, 1130, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1133, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1676}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1132, -1, 1132, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1135, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1678}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1134, -1, 1134, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1137, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1680}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1136, -1, 1136, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1139, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1682}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1138, -1, 1138, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1141, -1, 5400, -1, false, false, false, false, utf8proc_sequences + 1684}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1140, -1, 1140, 5460, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1686, false, -1, 1143, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1689}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1691, false, 1142, -1, 1142, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1145, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1694}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1144, -1, 1144, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1147, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1696}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1146, -1, 1146, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1149, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1698}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1148, -1, 1148, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1151, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1700}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1150, -1, 1150, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1153, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1702}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1152, -1, 1152, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ME, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1163, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1704}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1162, -1, 1162, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1165, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1706}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1164, -1, 1164, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1167, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1708}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1166, -1, 1166, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1169, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1710}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1168, -1, 1168, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1171, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1712}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1170, -1, 1170, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1173, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1714}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1172, -1, 1172, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1175, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1716}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1174, -1, 1174, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1177, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1718}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1176, -1, 1176, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1179, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1720}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1178, -1, 1178, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1181, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1722}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1180, -1, 1180, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1183, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1724}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1182, -1, 1182, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1185, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1726}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1184, -1, 1184, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1187, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1728}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1186, -1, 1186, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1189, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1730}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1188, -1, 1188, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1191, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1732}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1190, -1, 1190, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1193, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1734}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1192, -1, 1192, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1195, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1736}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1194, -1, 1194, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1197, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1738}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1196, -1, 1196, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1199, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1740}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1198, -1, 1198, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1201, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1742}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1200, -1, 1200, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1203, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1744}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1202, -1, 1202, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1205, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1746}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1204, -1, 1204, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1207, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1748}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1206, -1, 1206, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1209, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1750}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1208, -1, 1208, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1211, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1752}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1210, -1, 1210, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1213, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1754}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1212, -1, 1212, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1215, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1756}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1214, -1, 1214, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1231, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1758}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1760, false, -1, 1218, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1763}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1765, false, 1217, -1, 1217, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1220, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1768}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1219, -1, 1219, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1222, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1770}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1221, -1, 1221, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1224, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1772}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1223, -1, 1223, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1226, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1774}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1225, -1, 1225, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1228, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1776}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1227, -1, 1227, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1230, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1778}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1229, -1, 1229, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1216, -1, 1216, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1780, false, -1, 1233, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1783}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1785, false, 1232, -1, 1232, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1788, false, -1, 1235, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1791}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1793, false, 1234, -1, 1234, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1237, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1796}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1236, -1, 1236, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1798, false, -1, 1239, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1801}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1803, false, 1238, -1, 1238, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1241, -1, 5760, -1, false, false, false, false, utf8proc_sequences + 1806}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1240, -1, 1240, 5820, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1808, false, -1, 1243, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1811}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1813, false, 1242, -1, 1242, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1816, false, -1, 1245, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1819}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1821, false, 1244, -1, 1244, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1824, false, -1, 1247, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1827}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1829, false, 1246, -1, 1246, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1249, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1832}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1248, -1, 1248, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1834, false, -1, 1251, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1837}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1839, false, 1250, -1, 1250, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1842, false, -1, 1253, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1845}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1847, false, 1252, -1, 1252, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1850, false, -1, 1255, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1853}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1855, false, 1254, -1, 1254, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1257, -1, 6120, -1, false, false, false, false, utf8proc_sequences + 1858}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1256, -1, 1256, 6180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1860, false, -1, 1259, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1863}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1865, false, 1258, -1, 1258, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1868, false, -1, 1261, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1871}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1873, false, 1260, -1, 1260, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1876, false, -1, 1263, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1879}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1881, false, 1262, -1, 1262, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1884, false, -1, 1265, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1887}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1889, false, 1264, -1, 1264, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1892, false, -1, 1267, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1895}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1897, false, 1266, -1, 1266, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1900, false, -1, 1269, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1903}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1905, false, 1268, -1, 1268, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1271, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1908}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1270, -1, 1270, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1910, false, -1, 1273, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1913}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1915, false, 1272, -1, 1272, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1275, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1918}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1274, -1, 1274, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1277, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1920}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1276, -1, 1276, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1279, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1922}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1278, -1, 1278, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1281, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1924}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1280, -1, 1280, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1283, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1926}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1282, -1, 1282, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1285, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1928}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1284, -1, 1284, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1287, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1930}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1286, -1, 1286, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1289, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1932}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1288, -1, 1288, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1291, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1934}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1290, -1, 1290, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1293, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1936}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1292, -1, 1292, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1295, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1938}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1294, -1, 1294, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1297, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1940}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1296, -1, 1296, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1299, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1942}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1298, -1, 1298, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1377, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1944}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1378, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1946}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1379, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1948}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1380, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1950}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1381, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1952}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1382, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1954}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1383, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1956}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1384, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1958}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1385, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1960}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1386, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1962}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1387, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1964}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1388, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1966}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1389, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1968}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1390, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1970}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1391, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1972}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1392, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1974}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1393, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1976}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1394, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1978}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1395, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1980}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1396, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1982}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1397, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1984}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1398, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1986}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1399, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1988}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1400, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1990}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1401, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1992}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1402, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1994}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1403, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1996}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1404, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1998}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1405, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2000}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1406, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2002}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1407, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2004}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1408, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2006}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1409, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2008}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1410, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2010}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1411, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2012}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1412, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2014}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1413, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2016}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 1414, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2018}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1329, -1, 1329, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1330, -1, 1330, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1331, -1, 1331, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1332, -1, 1332, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1333, -1, 1333, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1334, -1, 1334, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1335, -1, 1335, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1336, -1, 1336, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1337, -1, 1337, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1338, -1, 1338, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1339, -1, 1339, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1340, -1, 1340, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1341, -1, 1341, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1342, -1, 1342, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1343, -1, 1343, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1344, -1, 1344, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1345, -1, 1345, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1346, -1, 1346, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1347, -1, 1347, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1348, -1, 1348, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1349, -1, 1349, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1350, -1, 1350, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1351, -1, 1351, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1352, -1, 1352, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1353, -1, 1353, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1354, -1, 1354, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1355, -1, 1355, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1356, -1, 1356, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1357, -1, 1357, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1358, -1, 1358, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1359, -1, 1359, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1360, -1, 1360, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1361, -1, 1361, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1362, -1, 1362, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1363, -1, 1363, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1364, -1, 1364, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1365, -1, 1365, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 1366, -1, 1366, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2020, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2020}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 222, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 228, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 10, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 11, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 12, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 13, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 14, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 15, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 16, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 17, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 18, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 19, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 20, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 21, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 22, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_R, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 23, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 24, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 25, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2023, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2026, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2032, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2035, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, 6600, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, 6660, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, 6720, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 27, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 28, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 29, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 30, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 31, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 32, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 33, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 34, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 17, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 230, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 18, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 220, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 19, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_AN, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_AN, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 35, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2044, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2050, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, 6840, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2053, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, 6900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, utf8proc_sequences + 2056, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, 6780, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_AL, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 36, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_R, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_R, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 6960, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7020, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2062, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7080, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2065, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 20, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2068, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2071, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2074, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2077, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2080, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2083, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2086, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2089, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 7, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 21, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2092, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 22, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2098, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2101, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2104, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2107, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2110, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2113, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2116, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2119, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2122, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 24, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7200, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2128, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 23, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 25, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2134, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2137, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7260, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2140, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 27, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7320, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2146, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2149, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 26, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, 7440, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2152, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 84, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 91, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 28, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7500, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2155, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 31, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7560, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2161, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2164, false, -1, -1, -1, 7620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2167, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 29, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 30, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 32, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7680, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7740, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2170, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2173, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2176, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 33, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 9, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 34, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 35, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7800, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2179, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2182, false, -1, -1, -1, 7860, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2185, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2188, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 36, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2191, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 103, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 107, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2194, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 118, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2197, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2200, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, utf8proc_sequences + 2203, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2205, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2208, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2211, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2214, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2217, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2220, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 129, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 130, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2223, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 132, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2226, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2229, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2232, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2235, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2238, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2241, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2244, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2247, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2250, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2253, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2256, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, utf8proc_sequences + 2259, false, -1, -1, -1, -1, -1, true, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7920, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2262, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 37, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11520, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2265}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11521, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2267}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11522, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2269}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11523, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2271}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11524, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2273}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11525, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2275}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11526, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2277}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11527, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2279}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11528, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2281}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11529, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2283}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11530, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2285}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11531, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2287}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11532, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2289}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11533, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2291}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11534, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2293}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11535, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2295}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11536, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2297}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11537, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2299}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11538, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2301}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11539, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2303}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11540, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2305}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11541, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2307}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11542, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2309}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11543, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2311}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11544, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2313}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11545, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2315}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11546, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2317}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11547, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2319}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11548, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2321}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11549, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2323}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11550, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2325}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11551, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2327}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11552, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2329}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11553, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2331}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11554, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2333}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11555, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2335}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11556, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2337}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11557, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2339}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2341, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, true, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 7980, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2343, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8040, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2346, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8100, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2349, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8160, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2352, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8220, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2355, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8280, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2358, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 38, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, 8340, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2361, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, 8400, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2364, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8460, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 8520, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2367, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2370, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 0, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, 8580, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2373, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 9, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2376, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2378, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2380, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2382, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2384, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2388, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2390, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2392, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2394, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2396, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2398, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2400, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2402, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2404, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2406, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2408, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2410, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2412, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2414, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2416, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 0, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2418, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2420, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2422, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 8, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 792, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 794, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2424, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 12, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 20, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 24, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 579, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 28, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 780, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2426, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2428, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 30, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 38, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 40, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2430, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 808, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 42, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2432, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1384, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1388, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1418, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1420, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 16, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 34, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 40, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 42, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 1384, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 1386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 1410, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 1418, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 1420, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1602, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11363, -1, 11363, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2434, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2436, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 163, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 10, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2438, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2440, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2442, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 804, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 802, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2444, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2446, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2448, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2450, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2452, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2454, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2456, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2458, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 810, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2460, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2462, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 812, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2464, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2466, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 830, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2468, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1275, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 844, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2470, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 846, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1277, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 50, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2472, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 2474, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 852, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 1396, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2476, false, -1, 7681, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2479}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2481, false, 7680, -1, 7680, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2484, false, -1, 7683, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2487}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2489, false, 7682, -1, 7682, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2492, false, -1, 7685, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2495}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2497, false, 7684, -1, 7684, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2500, false, -1, 7687, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2503}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2505, false, 7686, -1, 7686, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2508, false, -1, 7689, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2511}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2513, false, 7688, -1, 7688, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2516, false, -1, 7691, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2519}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2521, false, 7690, -1, 7690, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2524, false, -1, 7693, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2527}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2529, false, 7692, -1, 7692, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2532, false, -1, 7695, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2535}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2537, false, 7694, -1, 7694, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2540, false, -1, 7697, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2543}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2545, false, 7696, -1, 7696, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2548, false, -1, 7699, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2551}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2553, false, 7698, -1, 7698, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2556, false, -1, 7701, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2559}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2561, false, 7700, -1, 7700, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2564, false, -1, 7703, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2567}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2569, false, 7702, -1, 7702, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2572, false, -1, 7705, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2575}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2577, false, 7704, -1, 7704, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2580, false, -1, 7707, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2583}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2585, false, 7706, -1, 7706, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2588, false, -1, 7709, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2591}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2593, false, 7708, -1, 7708, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2596, false, -1, 7711, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2599}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2601, false, 7710, -1, 7710, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2604, false, -1, 7713, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2607}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2609, false, 7712, -1, 7712, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2612, false, -1, 7715, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2615}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2617, false, 7714, -1, 7714, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2620, false, -1, 7717, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2623}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2625, false, 7716, -1, 7716, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2628, false, -1, 7719, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2631}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2633, false, 7718, -1, 7718, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2636, false, -1, 7721, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2639}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2641, false, 7720, -1, 7720, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2644, false, -1, 7723, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2647}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2649, false, 7722, -1, 7722, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2652, false, -1, 7725, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2655}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2657, false, 7724, -1, 7724, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2660, false, -1, 7727, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2663}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2665, false, 7726, -1, 7726, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2668, false, -1, 7729, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2671}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2673, false, 7728, -1, 7728, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2676, false, -1, 7731, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2679}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2681, false, 7730, -1, 7730, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2684, false, -1, 7733, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2687}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2689, false, 7732, -1, 7732, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2692, false, -1, 7735, -1, 9360, -1, false, false, false, false, utf8proc_sequences + 2695}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2697, false, 7734, -1, 7734, 9420, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2700, false, -1, 7737, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2703}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2705, false, 7736, -1, 7736, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2708, false, -1, 7739, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2711}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2713, false, 7738, -1, 7738, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2716, false, -1, 7741, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2719}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2721, false, 7740, -1, 7740, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2724, false, -1, 7743, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2727}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2729, false, 7742, -1, 7742, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2732, false, -1, 7745, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2735}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2737, false, 7744, -1, 7744, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2740, false, -1, 7747, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2743}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2745, false, 7746, -1, 7746, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2748, false, -1, 7749, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2751}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2753, false, 7748, -1, 7748, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2756, false, -1, 7751, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2759}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2761, false, 7750, -1, 7750, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2764, false, -1, 7753, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2767}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2769, false, 7752, -1, 7752, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2772, false, -1, 7755, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2775}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2777, false, 7754, -1, 7754, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2780, false, -1, 7757, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2783}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2785, false, 7756, -1, 7756, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2788, false, -1, 7759, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2791}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2793, false, 7758, -1, 7758, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2796, false, -1, 7761, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2799}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2801, false, 7760, -1, 7760, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2804, false, -1, 7763, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2807}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2809, false, 7762, -1, 7762, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2812, false, -1, 7765, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2815}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2817, false, 7764, -1, 7764, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2820, false, -1, 7767, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2823}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2825, false, 7766, -1, 7766, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2828, false, -1, 7769, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2831}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2833, false, 7768, -1, 7768, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2836, false, -1, 7771, -1, 9840, -1, false, false, false, false, utf8proc_sequences + 2839}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2841, false, 7770, -1, 7770, 9900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2844, false, -1, 7773, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2847}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2849, false, 7772, -1, 7772, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2852, false, -1, 7775, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2855}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2857, false, 7774, -1, 7774, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2860, false, -1, 7777, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2863}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2865, false, 7776, -1, 7776, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2868, false, -1, 7779, -1, 10200, -1, false, false, false, false, utf8proc_sequences + 2871}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2873, false, 7778, -1, 7778, 10260, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2876, false, -1, 7781, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2879}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2881, false, 7780, -1, 7780, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2884, false, -1, 7783, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2887}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2889, false, 7782, -1, 7782, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2892, false, -1, 7785, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2895}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2897, false, 7784, -1, 7784, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2900, false, -1, 7787, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2903}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2905, false, 7786, -1, 7786, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2908, false, -1, 7789, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2911}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2913, false, 7788, -1, 7788, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2916, false, -1, 7791, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2919}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2921, false, 7790, -1, 7790, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2924, false, -1, 7793, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2927}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2929, false, 7792, -1, 7792, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2932, false, -1, 7795, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2935}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2937, false, 7794, -1, 7794, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2940, false, -1, 7797, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2943}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2945, false, 7796, -1, 7796, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2948, false, -1, 7799, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2951}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2953, false, 7798, -1, 7798, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2956, false, -1, 7801, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2959}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2961, false, 7800, -1, 7800, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2964, false, -1, 7803, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2967}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2969, false, 7802, -1, 7802, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2972, false, -1, 7805, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2975}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2977, false, 7804, -1, 7804, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2980, false, -1, 7807, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2983}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2985, false, 7806, -1, 7806, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2988, false, -1, 7809, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2991}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2993, false, 7808, -1, 7808, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2996, false, -1, 7811, -1, -1, -1, false, false, false, false, utf8proc_sequences + 2999}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3001, false, 7810, -1, 7810, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3004, false, -1, 7813, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3007}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3009, false, 7812, -1, 7812, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3012, false, -1, 7815, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3015}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3017, false, 7814, -1, 7814, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3020, false, -1, 7817, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3023}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3025, false, 7816, -1, 7816, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3028, false, -1, 7819, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3031}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3033, false, 7818, -1, 7818, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3036, false, -1, 7821, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3039}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3041, false, 7820, -1, 7820, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3044, false, -1, 7823, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3047}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3049, false, 7822, -1, 7822, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3052, false, -1, 7825, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3055}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3057, false, 7824, -1, 7824, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3060, false, -1, 7827, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3063}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3065, false, 7826, -1, 7826, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3068, false, -1, 7829, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3071}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3073, false, 7828, -1, 7828, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3076, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3076}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3079, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3079}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3082, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3082}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3085, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3085}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 3088, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3088}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3091, false, 7776, -1, 7776, -1, -1, false, false, false, false, utf8proc_sequences + 2863}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3094, false, -1, 7841, -1, 10980, -1, false, false, false, false, utf8proc_sequences + 3097}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3099, false, 7840, -1, 7840, 11040, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3102, false, -1, 7843, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3105}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3107, false, 7842, -1, 7842, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3110, false, -1, 7845, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3113}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3115, false, 7844, -1, 7844, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3118, false, -1, 7847, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3121}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3123, false, 7846, -1, 7846, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3126, false, -1, 7849, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3129}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3131, false, 7848, -1, 7848, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3134, false, -1, 7851, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3137}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3139, false, 7850, -1, 7850, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3142, false, -1, 7853, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3145}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3147, false, 7852, -1, 7852, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3150, false, -1, 7855, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3153}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3155, false, 7854, -1, 7854, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3158, false, -1, 7857, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3161}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3163, false, 7856, -1, 7856, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3166, false, -1, 7859, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3169}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3171, false, 7858, -1, 7858, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3174, false, -1, 7861, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3177}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3179, false, 7860, -1, 7860, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3182, false, -1, 7863, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3185}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3187, false, 7862, -1, 7862, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3190, false, -1, 7865, -1, 11340, -1, false, false, false, false, utf8proc_sequences + 3193}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3195, false, 7864, -1, 7864, 11400, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3198, false, -1, 7867, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3201}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3203, false, 7866, -1, 7866, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3206, false, -1, 7869, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3209}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3211, false, 7868, -1, 7868, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3214, false, -1, 7871, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3217}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3219, false, 7870, -1, 7870, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3222, false, -1, 7873, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3225}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3227, false, 7872, -1, 7872, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3230, false, -1, 7875, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3233}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3235, false, 7874, -1, 7874, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3238, false, -1, 7877, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3241}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3243, false, 7876, -1, 7876, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3246, false, -1, 7879, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3249}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3251, false, 7878, -1, 7878, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3254, false, -1, 7881, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3257}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3259, false, 7880, -1, 7880, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3262, false, -1, 7883, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3265}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3267, false, 7882, -1, 7882, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3270, false, -1, 7885, -1, 11580, -1, false, false, false, false, utf8proc_sequences + 3273}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3275, false, 7884, -1, 7884, 11640, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3278, false, -1, 7887, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3281}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3283, false, 7886, -1, 7886, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3286, false, -1, 7889, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3289}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3291, false, 7888, -1, 7888, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3294, false, -1, 7891, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3297}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3299, false, 7890, -1, 7890, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3302, false, -1, 7893, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3305}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3307, false, 7892, -1, 7892, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3310, false, -1, 7895, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3313}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3315, false, 7894, -1, 7894, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3318, false, -1, 7897, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3321}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3323, false, 7896, -1, 7896, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3326, false, -1, 7899, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3329}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3331, false, 7898, -1, 7898, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3334, false, -1, 7901, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3337}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3339, false, 7900, -1, 7900, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3342, false, -1, 7903, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3345}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3347, false, 7902, -1, 7902, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3350, false, -1, 7905, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3353}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3355, false, 7904, -1, 7904, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3358, false, -1, 7907, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3361}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3363, false, 7906, -1, 7906, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3366, false, -1, 7909, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3369}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3371, false, 7908, -1, 7908, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3374, false, -1, 7911, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3377}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3379, false, 7910, -1, 7910, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3382, false, -1, 7913, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3385}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3387, false, 7912, -1, 7912, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3390, false, -1, 7915, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3393}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3395, false, 7914, -1, 7914, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3398, false, -1, 7917, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3401}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3403, false, 7916, -1, 7916, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3406, false, -1, 7919, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3409}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3411, false, 7918, -1, 7918, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3414, false, -1, 7921, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3417}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3419, false, 7920, -1, 7920, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3422, false, -1, 7923, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3425}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3427, false, 7922, -1, 7922, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3430, false, -1, 7925, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3433}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3435, false, 7924, -1, 7924, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3438, false, -1, 7927, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3441}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3443, false, 7926, -1, 7926, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3446, false, -1, 7929, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3449}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3451, false, 7928, -1, 7928, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3454, false, 7944, -1, 7944, 11940, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3457, false, 7945, -1, 7945, 12000, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3460, false, 7946, -1, 7946, 13560, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3463, false, 7947, -1, 7947, 13620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3466, false, 7948, -1, 7948, 13680, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3469, false, 7949, -1, 7949, 13740, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3472, false, 7950, -1, 7950, 13800, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3475, false, 7951, -1, 7951, 13860, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3478, false, -1, 7936, -1, 12060, -1, false, false, false, false, utf8proc_sequences + 3481}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3483, false, -1, 7937, -1, 12120, -1, false, false, false, false, utf8proc_sequences + 3486}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3488, false, -1, 7938, -1, 13920, -1, false, false, false, false, utf8proc_sequences + 3491}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3493, false, -1, 7939, -1, 13980, -1, false, false, false, false, utf8proc_sequences + 3496}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3498, false, -1, 7940, -1, 14040, -1, false, false, false, false, utf8proc_sequences + 3501}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3503, false, -1, 7941, -1, 14100, -1, false, false, false, false, utf8proc_sequences + 3506}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3508, false, -1, 7942, -1, 14160, -1, false, false, false, false, utf8proc_sequences + 3511}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3513, false, -1, 7943, -1, 14220, -1, false, false, false, false, utf8proc_sequences + 3516}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3518, false, 7960, -1, 7960, 12180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3521, false, 7961, -1, 7961, 12240, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3524, false, 7962, -1, 7962, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3527, false, 7963, -1, 7963, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3530, false, 7964, -1, 7964, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3533, false, 7965, -1, 7965, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3536, false, -1, 7952, -1, 12300, -1, false, false, false, false, utf8proc_sequences + 3539}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3541, false, -1, 7953, -1, 12360, -1, false, false, false, false, utf8proc_sequences + 3544}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3546, false, -1, 7954, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3549}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3551, false, -1, 7955, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3554}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3556, false, -1, 7956, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3559}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3561, false, -1, 7957, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3564}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3566, false, 7976, -1, 7976, 12420, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3569, false, 7977, -1, 7977, 12480, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3572, false, 7978, -1, 7978, 14280, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3575, false, 7979, -1, 7979, 14340, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3578, false, 7980, -1, 7980, 14400, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3581, false, 7981, -1, 7981, 14460, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3584, false, 7982, -1, 7982, 14520, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3587, false, 7983, -1, 7983, 14580, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3590, false, -1, 7968, -1, 12540, -1, false, false, false, false, utf8proc_sequences + 3593}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3595, false, -1, 7969, -1, 12600, -1, false, false, false, false, utf8proc_sequences + 3598}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3600, false, -1, 7970, -1, 14640, -1, false, false, false, false, utf8proc_sequences + 3603}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3605, false, -1, 7971, -1, 14700, -1, false, false, false, false, utf8proc_sequences + 3608}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3610, false, -1, 7972, -1, 14760, -1, false, false, false, false, utf8proc_sequences + 3613}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3615, false, -1, 7973, -1, 14820, -1, false, false, false, false, utf8proc_sequences + 3618}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3620, false, -1, 7974, -1, 14880, -1, false, false, false, false, utf8proc_sequences + 3623}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3625, false, -1, 7975, -1, 14940, -1, false, false, false, false, utf8proc_sequences + 3628}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3630, false, 7992, -1, 7992, 12660, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3633, false, 7993, -1, 7993, 12720, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3636, false, 7994, -1, 7994, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3639, false, 7995, -1, 7995, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3642, false, 7996, -1, 7996, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3645, false, 7997, -1, 7997, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3648, false, 7998, -1, 7998, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3651, false, 7999, -1, 7999, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3654, false, -1, 7984, -1, 12780, -1, false, false, false, false, utf8proc_sequences + 3657}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3659, false, -1, 7985, -1, 12840, -1, false, false, false, false, utf8proc_sequences + 3662}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3664, false, -1, 7986, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3667}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3669, false, -1, 7987, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3672}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3674, false, -1, 7988, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3677}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3679, false, -1, 7989, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3682}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3684, false, -1, 7990, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3687}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3689, false, -1, 7991, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3692}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3694, false, 8008, -1, 8008, 12900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3697, false, 8009, -1, 8009, 12960, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3700, false, 8010, -1, 8010, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3703, false, 8011, -1, 8011, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3706, false, 8012, -1, 8012, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3709, false, 8013, -1, 8013, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3712, false, -1, 8000, -1, 13020, -1, false, false, false, false, utf8proc_sequences + 3715}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3717, false, -1, 8001, -1, 13080, -1, false, false, false, false, utf8proc_sequences + 3720}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3722, false, -1, 8002, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3725}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3727, false, -1, 8003, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3730}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3732, false, -1, 8004, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3735}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3737, false, -1, 8005, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3740}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3742, false, -1, -1, -1, 13140, -1, false, false, false, false, utf8proc_sequences + 3742}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3745, false, 8025, -1, 8025, 13200, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3748, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3751}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3755, false, 8027, -1, 8027, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3758, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3761}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3765, false, 8029, -1, 8029, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3768, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3771}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3775, false, 8031, -1, 8031, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3778, false, -1, 8017, -1, 13260, -1, false, false, false, false, utf8proc_sequences + 3781}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3783, false, -1, 8019, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3786}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3788, false, -1, 8021, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3791}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3793, false, -1, 8023, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3796}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3798, false, 8040, -1, 8040, 13320, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3801, false, 8041, -1, 8041, 13380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3804, false, 8042, -1, 8042, 15000, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3807, false, 8043, -1, 8043, 15060, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3810, false, 8044, -1, 8044, 15120, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3813, false, 8045, -1, 8045, 15180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3816, false, 8046, -1, 8046, 15240, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3819, false, 8047, -1, 8047, 15300, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3822, false, -1, 8032, -1, 13440, -1, false, false, false, false, utf8proc_sequences + 3825}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3827, false, -1, 8033, -1, 13500, -1, false, false, false, false, utf8proc_sequences + 3830}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3832, false, -1, 8034, -1, 15360, -1, false, false, false, false, utf8proc_sequences + 3835}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3837, false, -1, 8035, -1, 15420, -1, false, false, false, false, utf8proc_sequences + 3840}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3842, false, -1, 8036, -1, 15480, -1, false, false, false, false, utf8proc_sequences + 3845}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3847, false, -1, 8037, -1, 15540, -1, false, false, false, false, utf8proc_sequences + 3850}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3852, false, -1, 8038, -1, 15600, -1, false, false, false, false, utf8proc_sequences + 3855}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3857, false, -1, 8039, -1, 15660, -1, false, false, false, false, utf8proc_sequences + 3860}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3862, false, 8122, -1, 8122, 15720, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1341, false, 8123, -1, 8123, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3865, false, 8136, -1, 8136, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1348, false, 8137, -1, 8137, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3868, false, 8138, -1, 8138, 15900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1353, false, 8139, -1, 8139, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3871, false, 8154, -1, 8154, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1358, false, 8155, -1, 8155, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3874, false, 8184, -1, 8184, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1363, false, 8185, -1, 8185, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3877, false, 8170, -1, 8170, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1368, false, 8171, -1, 8171, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3880, false, 8186, -1, 8186, 16320, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1373, false, 8187, -1, 8187, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3883, false, 8072, -1, 8072, -1, -1, false, false, false, false, utf8proc_sequences + 3886}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3889, false, 8073, -1, 8073, -1, -1, false, false, false, false, utf8proc_sequences + 3892}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3895, false, 8074, -1, 8074, -1, -1, false, false, false, false, utf8proc_sequences + 3898}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3901, false, 8075, -1, 8075, -1, -1, false, false, false, false, utf8proc_sequences + 3904}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3907, false, 8076, -1, 8076, -1, -1, false, false, false, false, utf8proc_sequences + 3910}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3913, false, 8077, -1, 8077, -1, -1, false, false, false, false, utf8proc_sequences + 3916}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3919, false, 8078, -1, 8078, -1, -1, false, false, false, false, utf8proc_sequences + 3922}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3925, false, 8079, -1, 8079, -1, -1, false, false, false, false, utf8proc_sequences + 3928}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3931, false, -1, 8064, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3934}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3936, false, -1, 8065, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3939}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3941, false, -1, 8066, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3944}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3946, false, -1, 8067, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3949}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3951, false, -1, 8068, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3954}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3956, false, -1, 8069, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3959}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3961, false, -1, 8070, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3964}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3966, false, -1, 8071, -1, -1, -1, false, false, false, false, utf8proc_sequences + 3969}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3971, false, 8088, -1, 8088, -1, -1, false, false, false, false, utf8proc_sequences + 3974}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3977, false, 8089, -1, 8089, -1, -1, false, false, false, false, utf8proc_sequences + 3980}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3983, false, 8090, -1, 8090, -1, -1, false, false, false, false, utf8proc_sequences + 3986}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3989, false, 8091, -1, 8091, -1, -1, false, false, false, false, utf8proc_sequences + 3992}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 3995, false, 8092, -1, 8092, -1, -1, false, false, false, false, utf8proc_sequences + 3998}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4001, false, 8093, -1, 8093, -1, -1, false, false, false, false, utf8proc_sequences + 4004}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4007, false, 8094, -1, 8094, -1, -1, false, false, false, false, utf8proc_sequences + 4010}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4013, false, 8095, -1, 8095, -1, -1, false, false, false, false, utf8proc_sequences + 4016}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4019, false, -1, 8080, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4022}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4024, false, -1, 8081, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4027}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4029, false, -1, 8082, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4032}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4034, false, -1, 8083, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4037}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4039, false, -1, 8084, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4042}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4044, false, -1, 8085, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4047}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4049, false, -1, 8086, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4052}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4054, false, -1, 8087, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4057}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4059, false, 8104, -1, 8104, -1, -1, false, false, false, false, utf8proc_sequences + 4062}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4065, false, 8105, -1, 8105, -1, -1, false, false, false, false, utf8proc_sequences + 4068}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4071, false, 8106, -1, 8106, -1, -1, false, false, false, false, utf8proc_sequences + 4074}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4077, false, 8107, -1, 8107, -1, -1, false, false, false, false, utf8proc_sequences + 4080}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4083, false, 8108, -1, 8108, -1, -1, false, false, false, false, utf8proc_sequences + 4086}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4089, false, 8109, -1, 8109, -1, -1, false, false, false, false, utf8proc_sequences + 4092}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4095, false, 8110, -1, 8110, -1, -1, false, false, false, false, utf8proc_sequences + 4098}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4101, false, 8111, -1, 8111, -1, -1, false, false, false, false, utf8proc_sequences + 4104}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4107, false, -1, 8096, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4110}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4112, false, -1, 8097, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4115}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4117, false, -1, 8098, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4120}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4122, false, -1, 8099, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4125}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4127, false, -1, 8100, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4130}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4132, false, -1, 8101, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4135}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4137, false, -1, 8102, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4140}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4142, false, -1, 8103, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4145}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4147, false, 8120, -1, 8120, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4150, false, 8121, -1, 8121, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4153, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4156}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4159, false, 8124, -1, 8124, -1, -1, false, false, false, false, utf8proc_sequences + 4162}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4165, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4168}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4171, false, -1, -1, -1, 15840, -1, false, false, false, false, utf8proc_sequences + 4171}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4174, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4177}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4181, false, -1, 8112, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4184}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4186, false, -1, 8113, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4189}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4191, false, -1, 8048, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4194}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4196, false, -1, 8049, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4198}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4200, false, -1, 8115, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4203}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4205, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 1326, false, 921, -1, 921, -1, -1, false, false, false, false, utf8proc_sequences + 1326}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4205, false, -1, -1, -1, 16080, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4208, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4211, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4214, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4217}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4220, false, 8140, -1, 8140, -1, -1, false, false, false, false, utf8proc_sequences + 4223}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4226, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4229}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4232, false, -1, -1, -1, 16020, -1, false, false, false, false, utf8proc_sequences + 4232}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4235, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4238}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4242, false, -1, 8050, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4245}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4247, false, -1, 8051, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4249}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4251, false, -1, 8052, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4254}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4256, false, -1, 8053, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4258}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4260, false, -1, 8131, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4263}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4265, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4268, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4271, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4274, false, 8152, -1, 8152, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4277, false, 8153, -1, 8153, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4280, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4283}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4287, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1378}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4289, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4289}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4292, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4295}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4299, false, -1, 8144, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4302}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4304, false, -1, 8145, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4307}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4309, false, -1, 8054, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4312}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4314, false, -1, 8055, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4316}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4318, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4321, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4324, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4327, false, 8168, -1, 8168, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4330, false, 8169, -1, 8169, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4333, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4336}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4340, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1451}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4342, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4342}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4345, false, 8172, -1, 8172, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4348, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4348}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4351, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4354}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4358, false, -1, 8160, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4361}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4363, false, -1, 8161, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4366}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4368, false, -1, 8058, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4371}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4373, false, -1, 8059, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4375}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4377, false, -1, 8165, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4380}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4382, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4385, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4387, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4389, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4392}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4395, false, 8188, -1, 8188, -1, -1, false, false, false, false, utf8proc_sequences + 4398}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4401, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4404}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4407, false, -1, -1, -1, 16440, -1, false, false, false, false, utf8proc_sequences + 4407}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4410, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4413}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4417, false, -1, 8056, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4420}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4422, false, -1, 8057, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4424}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4426, false, -1, 8060, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4429}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4431, false, -1, 8061, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4433}, + {UTF8PROC_CATEGORY_LT, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4435, false, -1, 8179, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4438}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4440, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4442, false, -1, -1, -1, 16140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, utf8proc_sequences + 4445, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, 0, utf8proc_sequences + 4447, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 52, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_NOBREAK, utf8proc_sequences + 52, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_BN, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, true, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_R, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NOBREAK, utf8proc_sequences + 4449, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4451, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4454, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4456, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4459, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZL, 0, UTF8PROC_BIDI_CLASS_WS, 0, NULL, false, -1, -1, -1, -1, -1, false, false, true, false, NULL}, + {UTF8PROC_CATEGORY_ZP, 0, UTF8PROC_BIDI_CLASS_B, 0, NULL, false, -1, -1, -1, -1, -1, false, false, true, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRE, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLE, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_PDF, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_LRO, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_RLO, 0, NULL, false, -1, -1, -1, -1, -1, false, true, true, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4463, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4466, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4470, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4473, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4477, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4480, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_CS, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4483, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4486, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4489, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4492, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 16, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4501, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4509, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4513, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4515, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4517, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4519, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 26, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 72, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 60, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 62, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4501, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4509, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4513, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4515, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4517, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 4519, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 0, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 8, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 28, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 46, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUB, utf8proc_sequences + 792, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4521, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4524, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4528, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4534, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4537, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4541, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4545, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4547, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 12, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2390, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 14, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 454, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2392, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2398, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 22, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2402, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4550, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2408, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4553, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2410, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4555, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4558, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 4562, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4565, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4567, false, -1, 969, -1, -1, -1, false, false, false, false, utf8proc_sequences + 1424}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 2396, false, -1, 107, -1, -1, -1, false, false, false, false, utf8proc_sequences + 20}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 4569, false, -1, 229, -1, -1, -1, false, false, false, false, utf8proc_sequences + 114}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2380, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2384, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4571, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 8526, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4573}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2400, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 28, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4575, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4577, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4579, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4581, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 16, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4583, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1408, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4587, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4589, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4591, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2382, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 6, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 18, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 8498, -1, 8498, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4593, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4597, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4601, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4605, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4609, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4613, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4617, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4621, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4625, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4629, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4633, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4637, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_FRACTION, utf8proc_sequences + 4641, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2392, false, -1, 8560, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4644}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4646, false, -1, 8561, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4649}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4651, false, -1, 8562, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4655}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4657, false, -1, 8563, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4660}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4662, false, -1, 8564, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4664}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4666, false, -1, 8565, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4669}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4671, false, -1, 8566, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4675}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4677, false, -1, 8567, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4682}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4684, false, -1, 8568, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4687}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4689, false, -1, 8569, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4691}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4693, false, -1, 8570, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4696}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4698, false, -1, 8571, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4702}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2398, false, -1, 8572, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4704}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4532, false, -1, 8573, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4706}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2382, false, -1, 8574, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4708}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 2400, false, -1, 8575, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4710}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 16, false, 8544, -1, 8544, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4712, false, 8545, -1, 8545, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4715, false, 8546, -1, 8546, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4719, false, 8547, -1, 8547, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 42, false, 8548, -1, 8548, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4722, false, 8549, -1, 8549, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4725, false, 8550, -1, 8550, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4729, false, 8551, -1, 8551, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4734, false, 8552, -1, 8552, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 46, false, 8553, -1, 8553, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4737, false, 8554, -1, 8554, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4740, false, 8555, -1, 8555, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 22, false, 8556, -1, 8556, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4, false, 8557, -1, 8557, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6, false, 8558, -1, 8558, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 24, false, 8559, -1, 8559, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 8580, -1, -1, -1, false, false, false, false, utf8proc_sequences + 4744}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 8579, -1, 8579, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 16500, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 16560, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 16620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4746, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4749, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4752, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4755, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4758, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4761, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 16680, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 16800, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 16740, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 16860, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4764, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 16920, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4767, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 16980, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4770, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 17040, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4773, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 17100, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4776, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4779, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4782, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4786, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4789, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17160, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4793, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17220, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4796, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17280, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4799, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17340, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4802, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 17520, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4805, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 17460, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4808, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17700, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17760, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4811, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4814, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4817, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4820, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4823, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17820, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17880, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4826, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4829, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 17940, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18000, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4832, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4835, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18060, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18120, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18660, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18720, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4838, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4841, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18240, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4844, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4847, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18300, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18360, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4850, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4853, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18780, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18840, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18420, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18480, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18540, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18600, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4856, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4859, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4862, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4865, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 18960, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 19020, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, true, -1, -1, -1, 19080, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4868, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4871, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4874, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4877, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4880, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4883, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4886, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4889, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4892, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 4894, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 72, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 60, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 62, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4501, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4509, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4896, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4899, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4905, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4911, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4917, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4923, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4929, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4933, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4937, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4941, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4945, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4949, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4953, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4957, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4961, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4970, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4975, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4985, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4990, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 4995, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5000, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5005, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5010, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5015, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5020, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5023, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5026, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5032, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5035, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5044, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5051, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5055, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5063, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5067, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5071, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5075, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5079, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5083, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5099, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5107, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5111, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5123, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5127, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5135, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5139, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5147, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5151, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5155, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5159, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5163, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5167, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5171, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5175, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5179, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5183, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5187, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5191, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2376, false, -1, 9424, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5195}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2380, false, -1, 9425, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5197}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4532, false, -1, 9426, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5199}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2382, false, -1, 9427, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5201}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2384, false, -1, 9428, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5203}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4571, false, -1, 9429, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5205}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2388, false, -1, 9430, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5207}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2390, false, -1, 9431, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5209}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2392, false, -1, 9432, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5211}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2394, false, -1, 9433, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5213}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2396, false, -1, 9434, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5215}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2398, false, -1, 9435, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5217}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2400, false, -1, 9436, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5219}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2402, false, -1, 9437, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5221}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2404, false, -1, 9438, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5223}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2408, false, -1, 9439, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5225}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4553, false, -1, 9440, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5227}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2410, false, -1, 9441, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5229}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5231, false, -1, 9442, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5233}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2412, false, -1, 9443, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5235}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2414, false, -1, 9444, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5237}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4662, false, -1, 9445, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5239}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2416, false, -1, 9446, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5241}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4689, false, -1, 9447, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5243}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5245, false, -1, 9448, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5247}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4565, false, -1, 9449, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5249}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 0, false, 9398, -1, 9398, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 2, false, 9399, -1, 9399, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4, false, 9400, -1, 9400, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6, false, 9401, -1, 9401, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 8, false, 9402, -1, 9402, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 10, false, 9403, -1, 9403, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 12, false, 9404, -1, 9404, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 14, false, 9405, -1, 9405, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 16, false, 9406, -1, 9406, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 18, false, 9407, -1, 9407, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 20, false, 9408, -1, 9408, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 22, false, 9409, -1, 9409, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 24, false, 9410, -1, 9410, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 26, false, 9411, -1, 9411, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 28, false, 9412, -1, 9412, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 30, false, 9413, -1, 9413, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 32, false, 9414, -1, 9414, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 34, false, 9415, -1, 9415, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 36, false, 9416, -1, 9416, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 38, false, 9417, -1, 9417, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 40, false, 9418, -1, 9418, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 42, false, 9419, -1, 9419, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 44, false, 9420, -1, 9420, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 46, false, 9421, -1, 9421, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 48, false, 9422, -1, 9422, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 50, false, 9423, -1, 9423, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 4497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5251, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5256, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5260, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5263, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, utf8proc_sequences + 5267, true, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, 19140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11312, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5270}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11313, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5272}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11314, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5274}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11315, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5276}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11316, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5278}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11317, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5280}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11318, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5282}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11319, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5284}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11320, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5286}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11321, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5288}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11322, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5290}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11323, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5292}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11324, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5294}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11325, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5296}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11326, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5298}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11327, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5300}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11328, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5302}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11329, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5304}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11330, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5306}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11331, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5308}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11332, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5310}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11333, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5312}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11334, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5314}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11335, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5316}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11336, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5318}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11337, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5320}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11338, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5322}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11339, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5324}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11340, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5326}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11341, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5328}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11342, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5330}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11343, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5332}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11344, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5334}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11345, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5336}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11346, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5338}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11347, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5340}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11348, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5342}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11349, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5344}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11350, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5346}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11351, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5348}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11352, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5350}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11353, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5352}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11354, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5354}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11355, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5356}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11356, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5358}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11357, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5360}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11358, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5362}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11264, -1, 11264, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11265, -1, 11265, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11266, -1, 11266, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11267, -1, 11267, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11268, -1, 11268, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11269, -1, 11269, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11270, -1, 11270, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11271, -1, 11271, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11272, -1, 11272, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11273, -1, 11273, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11274, -1, 11274, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11275, -1, 11275, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11276, -1, 11276, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11277, -1, 11277, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11278, -1, 11278, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11279, -1, 11279, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11280, -1, 11280, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11281, -1, 11281, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11282, -1, 11282, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11283, -1, 11283, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11284, -1, 11284, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11285, -1, 11285, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11286, -1, 11286, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11287, -1, 11287, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11288, -1, 11288, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11289, -1, 11289, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11290, -1, 11290, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11291, -1, 11291, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11292, -1, 11292, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11293, -1, 11293, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11294, -1, 11294, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11295, -1, 11295, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11296, -1, 11296, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11297, -1, 11297, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11298, -1, 11298, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11299, -1, 11299, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11300, -1, 11300, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11301, -1, 11301, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11302, -1, 11302, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11303, -1, 11303, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11304, -1, 11304, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11305, -1, 11305, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11306, -1, 11306, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11307, -1, 11307, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11308, -1, 11308, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11309, -1, 11309, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11310, -1, 11310, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11361, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5364}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11360, -1, 11360, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 619, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5366}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 7549, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5368}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 637, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5370}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 570, -1, 570, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 574, -1, 574, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11368, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5372}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11367, -1, 11367, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11370, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5374}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11369, -1, 11369, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11372, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5376}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11371, -1, 11371, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11382, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5378}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11381, -1, 11381, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11393, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5380}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11392, -1, 11392, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11395, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5382}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11394, -1, 11394, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11397, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5384}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11396, -1, 11396, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11399, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5386}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11398, -1, 11398, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11401, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5388}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11400, -1, 11400, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11403, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5390}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11402, -1, 11402, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11405, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5392}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11404, -1, 11404, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11407, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5394}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11406, -1, 11406, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11409, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5396}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11408, -1, 11408, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11411, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5398}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11410, -1, 11410, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11413, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5400}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11412, -1, 11412, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11415, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5402}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11414, -1, 11414, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11417, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5404}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11416, -1, 11416, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11419, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5406}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11418, -1, 11418, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11421, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5408}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11420, -1, 11420, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11423, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5410}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11422, -1, 11422, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11425, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5412}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11424, -1, 11424, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11427, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5414}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11426, -1, 11426, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11429, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5416}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11428, -1, 11428, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11431, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5418}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11430, -1, 11430, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11433, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5420}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11432, -1, 11432, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11435, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5422}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11434, -1, 11434, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11437, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5424}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11436, -1, 11436, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11439, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5426}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11438, -1, 11438, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11441, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5428}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11440, -1, 11440, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11443, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5430}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11442, -1, 11442, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11445, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5432}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11444, -1, 11444, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11447, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5434}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11446, -1, 11446, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11449, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5436}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11448, -1, 11448, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11451, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5438}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11450, -1, 11450, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11453, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5440}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11452, -1, 11452, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11455, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5442}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11454, -1, 11454, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11457, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5444}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11456, -1, 11456, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11459, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5446}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11458, -1, 11458, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11461, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5448}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11460, -1, 11460, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11463, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5450}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11462, -1, 11462, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11465, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5452}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11464, -1, 11464, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11467, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5454}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11466, -1, 11466, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11469, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5456}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11468, -1, 11468, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11471, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5458}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11470, -1, 11470, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11473, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5460}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11472, -1, 11472, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11475, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5462}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11474, -1, 11474, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11477, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5464}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11476, -1, 11476, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11479, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5466}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11478, -1, 11478, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11481, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5468}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11480, -1, 11480, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11483, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5470}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11482, -1, 11482, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11485, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5472}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11484, -1, 11484, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11487, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5474}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11486, -1, 11486, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11489, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5476}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11488, -1, 11488, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 11491, -1, -1, -1, false, false, false, false, utf8proc_sequences + 5478}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 11490, -1, 11490, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4256, -1, 4256, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4257, -1, 4257, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4258, -1, 4258, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4259, -1, 4259, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4260, -1, 4260, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4261, -1, 4261, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4262, -1, 4262, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4263, -1, 4263, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4264, -1, 4264, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4265, -1, 4265, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4266, -1, 4266, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4267, -1, 4267, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4268, -1, 4268, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4269, -1, 4269, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4270, -1, 4270, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4271, -1, 4271, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4272, -1, 4272, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4273, -1, 4273, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4274, -1, 4274, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4275, -1, 4275, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4276, -1, 4276, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4277, -1, 4277, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4278, -1, 4278, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4279, -1, 4279, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4280, -1, 4280, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4281, -1, 4281, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4282, -1, 4282, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4283, -1, 4283, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4284, -1, 4284, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4285, -1, 4285, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4286, -1, 4286, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4287, -1, 4287, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4288, -1, 4288, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4289, -1, 4289, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4290, -1, 4290, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4291, -1, 4291, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4292, -1, 4292, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 4293, -1, 4293, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 5480, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5484, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5486, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5488, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5490, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5492, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5494, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5496, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5498, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5500, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5502, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5504, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5506, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5508, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5510, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5512, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5514, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5516, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5518, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5520, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5522, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5524, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5526, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5528, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5530, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5534, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5536, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5538, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5540, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5542, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5544, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5546, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5548, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5550, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5552, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5554, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5556, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5558, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5560, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5562, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5564, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5566, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5568, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5570, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5572, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5574, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5576, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5578, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5580, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5582, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5584, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5586, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5588, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5590, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5592, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5594, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5596, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5598, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5600, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5602, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5604, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5606, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5608, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5610, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5612, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5614, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5616, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5618, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5620, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5622, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5624, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5626, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5628, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5630, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5632, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5634, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5636, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5638, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5640, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5642, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5644, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5646, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5648, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5650, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5652, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5654, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5656, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5658, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5660, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5662, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5664, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5666, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5668, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5670, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5672, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5674, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5676, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5678, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5680, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5682, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5684, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5686, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5688, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5690, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5692, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5694, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5696, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5698, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5700, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5702, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5704, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5706, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5708, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5710, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5712, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5714, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5716, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5718, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5720, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5722, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5724, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5726, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5728, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5730, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5732, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5734, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5736, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5738, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5740, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5742, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5744, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5746, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5748, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5750, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5752, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5754, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5756, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5758, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5760, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5762, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5764, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5766, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5768, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5770, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5772, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5774, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5776, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5778, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5780, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5782, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5784, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5786, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5788, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5790, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5792, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5794, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5796, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5798, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5800, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5802, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5804, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5806, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5808, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5810, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5812, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5814, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5816, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5818, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5820, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5822, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5824, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5826, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5828, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5830, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5832, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5834, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5836, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5838, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5840, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5842, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5844, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5846, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5848, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5850, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5852, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5854, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5856, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5858, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5860, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5862, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5864, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5866, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5868, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5870, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5872, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5874, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5876, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5878, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5880, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5882, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5884, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5886, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5888, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5890, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5892, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5894, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5896, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5898, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5900, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5904, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5906, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ZS, 0, UTF8PROC_BIDI_CLASS_WS, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 52, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 218, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 224, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5916, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5918, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20400, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19200, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19260, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5923, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19320, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19380, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5929, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19440, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5932, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19500, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5935, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19560, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5938, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19620, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5941, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19680, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5944, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19740, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5947, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19800, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5950, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19860, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5953, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19920, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5956, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 19980, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5959, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20040, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5962, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20100, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5968, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20160, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5971, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5974, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20220, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5977, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20280, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5983, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5986, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20340, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5989, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5992, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5995, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 8, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 52, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MN, 8, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, 53, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 5998, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6001, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20460, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6004, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 6007, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21720, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20520, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6010, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20580, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6013, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20640, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6016, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20700, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6019, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20760, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6022, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20820, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6025, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20880, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6028, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 20940, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6031, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21000, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6034, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21060, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6037, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21120, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6040, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21180, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6043, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21240, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6046, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21300, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6049, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21360, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6052, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21420, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6055, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6058, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21480, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6061, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6064, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21540, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6067, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6070, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21600, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6073, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6076, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21660, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6079, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6082, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21780, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21840, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21900, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 21960, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6085, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6088, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6094, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6097, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 22020, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6100, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 6103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6106, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6108, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6110, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6112, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6114, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6116, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6118, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6120, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6122, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6124, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6126, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6128, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6130, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6132, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6134, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6136, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6138, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6140, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6142, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6144, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6146, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6148, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6150, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6152, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6154, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6156, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6160, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6162, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6164, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6166, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6168, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6170, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6172, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6174, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6176, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6178, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6180, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6182, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6184, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6186, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6188, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6190, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6192, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6194, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6196, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6198, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6200, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6202, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6204, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6206, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6208, false, -1, -1, -1, -1, -1, false, true, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6210, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6212, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6214, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6216, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6218, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6220, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6222, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6224, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6226, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6228, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6230, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6232, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6234, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6236, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6238, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6240, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6242, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6244, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6246, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6248, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6250, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6252, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6254, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6256, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6258, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6260, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6262, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6264, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6266, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6268, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6270, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6272, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6274, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6276, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6278, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6280, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6282, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6284, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6286, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6288, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6290, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6292, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 5486, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 5498, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6294, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6296, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6298, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6300, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6302, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6304, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 5494, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6306, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6308, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6310, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 6312, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SUPER, utf8proc_sequences + 5502, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6314, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6318, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6322, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6326, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6330, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6334, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6338, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6342, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6346, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6350, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6354, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6358, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6362, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6366, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6370, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6375, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6380, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6385, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6390, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6395, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6400, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6405, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6410, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6415, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6420, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6425, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6430, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6435, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6440, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6445, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6453, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6460, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6464, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6468, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6472, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6476, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6480, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6484, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6488, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6492, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6496, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6500, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6504, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6508, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6512, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6516, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6520, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6524, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6528, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6536, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6540, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6544, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6548, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6552, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6556, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6560, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6564, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6568, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6572, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6576, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6580, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6584, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6588, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6592, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6596, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6600, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6604, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6608, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6611, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6614, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6617, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6620, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6623, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6626, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6629, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6632, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6635, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6638, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6641, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6644, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6647, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6650, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6106, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6112, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6118, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6122, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6138, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6140, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6146, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6150, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6152, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6156, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6160, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6162, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6164, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6653, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6656, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6659, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6662, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6665, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6668, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6671, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6674, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6677, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6680, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6683, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6686, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6689, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6692, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6695, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6701, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6706, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5486, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5498, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6294, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6296, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6709, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6711, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6713, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5508, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6715, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5632, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5656, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5654, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5634, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5818, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5548, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5628, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6717, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6719, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6721, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6723, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6725, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6727, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6729, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6731, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6733, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6735, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 5560, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6737, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6739, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6741, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6743, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6745, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6747, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6749, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6751, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6298, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6300, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6302, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6753, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6755, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6757, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6759, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6761, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6763, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6765, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6767, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6769, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6771, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6773, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6776, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6779, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6782, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6785, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6788, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6791, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6794, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6797, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6800, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6803, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6806, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6809, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6812, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6815, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6818, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6821, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6824, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6827, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6830, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6833, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6836, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6839, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6842, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6845, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6849, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 6853, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6857, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6860, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6864, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6867, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6871, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6873, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6875, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6877, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6879, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6881, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6883, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6885, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6887, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6889, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6891, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6893, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6895, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6897, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6899, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6901, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6903, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6905, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6907, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6909, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6911, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6913, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6915, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6917, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6919, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6921, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6923, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6925, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6927, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6929, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6931, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6933, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6935, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6937, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6939, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6941, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6943, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6945, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6947, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6949, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6951, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6953, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6955, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6957, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6959, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6961, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_CIRCLE, utf8proc_sequences + 6963, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6970, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6975, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6984, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6989, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6993, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 6997, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7003, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7008, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7012, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7016, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7020, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7025, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7030, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7034, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7045, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7050, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7055, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7058, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7064, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7071, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7077, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7081, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7093, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7098, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7102, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7106, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7110, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7121, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7126, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7130, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7134, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7138, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7141, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7144, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7147, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7150, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7154, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7164, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7168, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7173, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7179, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7183, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7186, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7189, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7195, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7200, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7206, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7210, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7216, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7219, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7223, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7227, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7231, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7235, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7244, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7248, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7251, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7255, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7259, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7263, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7268, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7272, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7276, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7280, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7286, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7291, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7294, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7300, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7303, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7308, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7313, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7317, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7321, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7325, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7330, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7337, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7342, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7345, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7351, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7355, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7358, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7361, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7364, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7367, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7370, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7373, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7376, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7379, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7382, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7385, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7389, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7393, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7397, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7401, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7405, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7409, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7413, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7417, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7421, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7425, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7429, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7433, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7437, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7441, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7445, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7449, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7452, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7455, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7459, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7462, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7465, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7468, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7472, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7476, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7479, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7485, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7488, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7491, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7496, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7502, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7508, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7514, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7517, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7520, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7524, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7529, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7535, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7538, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7541, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7544, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7547, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7550, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7554, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7558, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7562, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7566, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7569, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7572, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7575, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7578, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7581, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7584, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7587, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7590, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7593, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7596, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7600, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7604, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7607, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7611, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7615, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7619, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7622, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7626, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7630, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7635, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7638, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7642, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7646, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7650, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7654, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7660, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7667, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7670, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7673, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7676, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7679, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7682, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7685, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7688, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7691, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7694, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7697, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7700, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7703, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7706, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7709, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7712, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7715, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7718, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7721, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7726, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7729, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7732, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7735, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7740, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7744, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7747, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7750, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7753, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7756, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7759, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7762, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7765, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7768, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7771, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7774, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7778, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7781, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7784, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7788, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7792, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7795, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7800, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7804, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7807, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7810, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7813, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7816, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7820, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7824, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7827, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7830, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7833, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7836, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7839, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7842, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7845, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7848, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7851, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7855, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7859, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7863, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7867, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7871, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7875, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7879, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7883, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7887, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7891, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7895, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7899, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7903, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7907, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7911, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7915, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7919, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7923, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7927, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7931, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 7935, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SQUARE, utf8proc_sequences + 7939, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_CS, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, true, false, false, NULL}, + {UTF8PROC_CATEGORY_CO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7943, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7945, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5802, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7947, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7949, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7951, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7953, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7955, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5818, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7957, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7959, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7961, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7963, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7967, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7969, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7971, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7973, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7975, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7977, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7979, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7981, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7983, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7985, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7987, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7989, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7991, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7993, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7995, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7997, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 7999, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8001, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8003, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8005, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8007, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8009, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8011, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8013, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8015, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8017, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8019, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8021, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8023, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8025, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8027, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8031, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8033, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8035, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8037, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5734, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8039, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8043, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8045, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8049, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8051, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8053, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8055, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8057, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5880, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8061, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8063, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8065, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8067, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8069, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8071, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8073, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8075, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8077, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8079, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8081, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8083, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8085, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8089, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8093, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8097, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8099, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8105, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8107, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8109, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8111, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8117, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8121, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8123, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8127, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8129, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8133, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8135, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8139, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8141, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8145, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8147, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8149, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8151, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8153, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5806, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8155, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8157, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8159, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8161, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8163, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8165, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8167, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8169, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8171, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8173, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8175, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8177, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8179, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8181, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8183, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5560, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8185, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8187, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8189, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8191, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8193, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8195, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8197, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8199, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5522, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8201, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8203, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8205, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8207, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8209, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8211, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8213, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8215, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8217, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8219, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8221, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8223, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8225, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8227, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8229, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8231, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8233, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8235, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8237, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8241, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8243, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8245, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8247, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8249, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8251, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8253, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8255, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8257, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8259, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8261, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8263, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8265, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8267, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8269, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8271, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8273, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8275, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8277, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8279, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8281, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8283, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8285, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8287, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8289, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8291, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8293, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8295, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8297, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8299, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8301, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8303, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8305, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8307, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8309, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8311, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8313, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8315, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8317, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8319, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8321, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8323, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8325, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8327, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8329, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8331, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6711, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8335, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8337, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8339, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8341, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8343, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8345, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8347, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8349, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8351, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8353, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8355, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8357, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8359, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8361, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8363, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8365, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8367, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8369, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8371, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8373, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8375, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5816, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8377, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8379, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8381, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8383, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8385, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8387, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8389, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8391, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8393, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8395, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8397, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8399, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8401, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5718, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8403, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8405, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8407, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8409, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8411, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8413, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8415, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8417, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8419, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8421, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8423, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8425, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8427, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8429, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8431, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8433, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5772, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8435, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5778, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8437, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8439, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8441, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8443, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8445, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8447, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8449, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8451, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8453, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8455, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8457, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8459, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8461, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8463, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5732, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8465, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8467, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8469, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8471, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8473, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8475, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8477, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8479, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8481, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8483, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8485, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8487, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8489, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8491, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8493, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8495, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8501, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5574, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8509, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8513, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8515, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8517, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8519, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8521, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8523, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8525, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8527, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8529, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8531, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8533, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6721, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8535, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8537, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8539, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8541, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 6729, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8543, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8545, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8547, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8549, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8551, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8553, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8555, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8557, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8559, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8561, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8563, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8565, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8567, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8569, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8571, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8573, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8575, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8577, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8579, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8581, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8583, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8585, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8587, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8589, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8591, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8593, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8595, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8597, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8599, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8601, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8603, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8605, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8607, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8609, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8611, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8613, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8615, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8617, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8619, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8621, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8623, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8625, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8627, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8629, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8631, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8633, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8635, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8637, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8639, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8641, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8643, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8645, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8647, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5640, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8649, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8651, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8653, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8655, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8657, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8659, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8661, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8663, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8665, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8667, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8669, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8671, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8673, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8675, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8677, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8679, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8681, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8683, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8685, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8687, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8689, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8691, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8693, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8695, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8697, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8699, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8701, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8703, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8705, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8707, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8709, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8711, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8713, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8715, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8717, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8719, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8721, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8723, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8725, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8727, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8729, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8731, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8733, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8735, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8737, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8739, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8741, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 8743, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8745, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8745}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8748, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8748}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8751, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8751}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8754, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8754}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8758, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8758}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8762, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8765}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8765, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8765}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8768, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8768}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8771, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8771}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8774, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8774}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8777, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8777}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8780, false, -1, -1, -1, -1, -1, false, false, false, false, utf8proc_sequences + 8780}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8783, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MN, 26, UTF8PROC_BIDI_CLASS_NSM, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8786, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8789, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4575, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4581, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8791, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8793, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8795, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8797, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8799, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 8801, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8803, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8806, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8809, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8812, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8815, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8818, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8821, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8824, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8827, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8830, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8833, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8836, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8839, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8842, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8845, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8848, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8851, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8854, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8857, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8860, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8863, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8866, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8869, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8872, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8875, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8878, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8881, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8884, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8887, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8890, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8893, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, 0, utf8proc_sequences + 8896, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_R, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 8899, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8904, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8904, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8904, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8904, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8906, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8906, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8906, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8906, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8916, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8916, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8916, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8916, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8918, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8918, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8918, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8918, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8922, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8922, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8922, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8922, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8924, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8924, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8924, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8924, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8928, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8928, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8930, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8930, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8932, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8932, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8934, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8934, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8936, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8936, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8938, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8938, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8940, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8940, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8940, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8940, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8942, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8942, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8942, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8942, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8944, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8944, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8944, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8944, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8946, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8946, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8946, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8946, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8948, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8948, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8950, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8950, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8950, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8950, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8952, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8952, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8954, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8954, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8954, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8954, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8956, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8956, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8956, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8956, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8958, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8958, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8960, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8960, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8962, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8962, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8962, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8962, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8964, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8964, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8966, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8966, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8968, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8968, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8970, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8972, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8972, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8974, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8974, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8976, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8976, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8978, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8978, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8978, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8978, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 8980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 8980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8982, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8982, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8985, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8985, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8988, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8988, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8991, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8991, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8994, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8994, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8997, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8997, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9000, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9000, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9000, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9003, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9003, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9003, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9006, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9006, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9006, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9006, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9008, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9011, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9014, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9017, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9020, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9023, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9026, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9032, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9035, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9044, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9050, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9053, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9056, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9062, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9065, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9068, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9071, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9074, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9077, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9080, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9083, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9086, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9089, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9092, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9098, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9104, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9107, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9110, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9116, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9122, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9128, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9134, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9140, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9146, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9149, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9152, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9155, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9161, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9164, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9167, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9170, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9173, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9176, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9179, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9182, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9185, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9188, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9191, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9194, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9197, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9200, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9203, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9206, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9209, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9212, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9215, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9218, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9221, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9224, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9227, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9230, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9233, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9236, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9242, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9245, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9248, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9251, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9254, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9257, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9260, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9263, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9266, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9269, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9272, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9275, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9278, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9281, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9284, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9287, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9291, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9295, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9299, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9303, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9307, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9311, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9314, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9014, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9317, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9017, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9320, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9323, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9326, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9032, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9035, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9329, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9332, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9335, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9050, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9053, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9338, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9341, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9344, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9062, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9065, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9152, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9155, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9164, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9167, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9170, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9182, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9185, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9188, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9191, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9203, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9206, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9209, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9347, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9221, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9350, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9353, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9356, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9242, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9245, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9284, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9359, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9362, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9269, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9365, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9272, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9275, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9008, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9011, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9368, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9014, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9371, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9020, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9023, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9026, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9374, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9044, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9377, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9068, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9071, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9074, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9077, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9080, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9086, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9089, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9092, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9098, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9380, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9104, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9107, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9110, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9116, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9128, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9134, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9140, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9146, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9149, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9161, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9173, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9176, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9179, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9182, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9185, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9194, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9197, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9200, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9203, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9383, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9212, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9215, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9218, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9221, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9230, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9233, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9236, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9248, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9251, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9389, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9260, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9263, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9266, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9269, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9392, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9014, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9371, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9374, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9377, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9395, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9098, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9398, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9401, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9404, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9182, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9185, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9203, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9269, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9392, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9407, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9411, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9415, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9419, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9422, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9425, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9428, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9431, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9434, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9437, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9440, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9443, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9446, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9449, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9452, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9455, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9458, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9461, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9464, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9467, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9470, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9473, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9476, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9479, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9485, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9401, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9488, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9491, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9494, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9419, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9422, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9425, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9428, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9431, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9434, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9437, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9440, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9443, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9446, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9449, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9452, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9455, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9458, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9461, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9464, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9467, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9470, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9473, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9476, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9479, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9485, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9401, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9488, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9491, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9494, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9479, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9485, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9401, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9398, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9404, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9122, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9089, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9092, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9479, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9485, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9122, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 9125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9500, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9500, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9515, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9519, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9523, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9527, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9531, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9531, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9535, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9539, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9543, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9547, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9551, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9555, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9555, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9559, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9563, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9563, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9567, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9567, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9571, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9575, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9575, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9579, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9583, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9583, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9587, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9587, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9591, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9595, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9595, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9599, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9599, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9603, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9607, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9611, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9615, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9615, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9619, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9623, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9627, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9631, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9635, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9635, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9639, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9643, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9647, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9651, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9655, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9659, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9659, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9663, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9663, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9667, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9667, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9671, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9675, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9679, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9683, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9687, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9691, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9695, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9699, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9703, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9707, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9711, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9715, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9719, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9719, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9723, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9727, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9731, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9735, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9735, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9739, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9743, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9747, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9751, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9755, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9759, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9763, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9767, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9771, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9775, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9779, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9783, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9787, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9791, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9795, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9799, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9803, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9807, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9811, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9815, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9819, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9823, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9639, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9647, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9827, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9831, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9835, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9839, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9843, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9847, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9843, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9835, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9851, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9855, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9859, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9863, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9867, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9847, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9611, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 9571, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9871, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 9875, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9879, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9883, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9887, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9892, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9897, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9907, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9917, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9922, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9945, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 9954, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9959, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9961, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9963, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 1333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9967, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9969, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9971, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9973, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9975, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9977, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9979, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9981, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9983, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 4517, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 4519, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9985, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9987, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9989, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9991, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9993, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9995, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9997, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 9999, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 4892, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 4894, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 10001, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 10003, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 10005, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 10007, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 10009, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_VERTICAL, utf8proc_sequences + 10011, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 10013, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_COMPAT, utf8proc_sequences + 9983, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9959, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9961, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 4454, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 1333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9969, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9967, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9979, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 4517, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 4519, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9985, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9987, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9989, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 9991, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10015, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10017, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10019, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 4511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10021, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10023, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10025, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 4515, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10027, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10031, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_SMALL, utf8proc_sequences + 10033, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10035, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10041, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10044, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10047, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10050, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10053, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10056, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10059, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10062, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10065, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10068, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10071, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10074, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10077, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10079, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10079, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10081, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10081, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10083, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10083, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10085, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10085, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10087, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10089, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10089, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10091, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10093, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10093, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10095, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10097, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10097, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10097, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10097, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10099, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10099, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10099, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10099, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10101, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10103, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10105, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10105, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10107, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10107, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10109, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10109, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10111, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10111, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10113, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10115, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10117, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10117, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10117, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10117, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10119, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10121, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10121, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10121, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10121, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10123, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10123, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10123, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10123, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10125, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10127, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10127, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10127, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10127, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10129, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10129, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10129, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10129, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10131, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10133, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10133, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10133, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10133, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10135, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10135, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10135, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10135, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10137, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10139, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10139, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10139, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10139, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10141, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10141, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10141, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10141, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10143, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 8980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 8980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10145, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10145, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_INITIAL, utf8proc_sequences + 10145, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_MEDIAL, utf8proc_sequences + 10145, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10147, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10147, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10150, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10150, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10153, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10153, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_ISOLATED, utf8proc_sequences + 10156, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_AL, UTF8PROC_DECOMP_TYPE_FINAL, utf8proc_sequences + 10156, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9967, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10159, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10015, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10029, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10031, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10017, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10161, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4517, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4519, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10019, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4511, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9959, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PD, 0, UTF8PROC_BIDI_CLASS_ES, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10021, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4454, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10163, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 72, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 60, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 62, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4501, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4509, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_CS, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9965, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 1333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10023, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4515, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10025, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9969, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10033, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2376, false, -1, 65345, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10165}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2380, false, -1, 65346, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10167}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4532, false, -1, 65347, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10169}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2382, false, -1, 65348, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10171}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2384, false, -1, 65349, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10173}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4571, false, -1, 65350, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10175}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2388, false, -1, 65351, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10177}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2390, false, -1, 65352, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10179}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2392, false, -1, 65353, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10181}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2394, false, -1, 65354, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10183}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2396, false, -1, 65355, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10185}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2398, false, -1, 65356, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10187}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2400, false, -1, 65357, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10189}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2402, false, -1, 65358, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10191}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2404, false, -1, 65359, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10193}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2408, false, -1, 65360, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10195}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4553, false, -1, 65361, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10197}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2410, false, -1, 65362, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10199}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 5231, false, -1, 65363, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10201}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2412, false, -1, 65364, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10203}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2414, false, -1, 65365, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10205}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4662, false, -1, 65366, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10207}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2416, false, -1, 65367, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10209}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4689, false, -1, 65368, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10211}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 5245, false, -1, 65369, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10213}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4565, false, -1, 65370, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10215}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10009, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10027, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10011, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10217, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PC, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9983, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4387, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 0, false, 65313, -1, 65313, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 2, false, 65314, -1, 65314, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 4, false, 65315, -1, 65315, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 6, false, 65316, -1, 65316, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 8, false, 65317, -1, 65317, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10, false, 65318, -1, 65318, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 12, false, 65319, -1, 65319, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 14, false, 65320, -1, 65320, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 16, false, 65321, -1, 65321, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 18, false, 65322, -1, 65322, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 20, false, 65323, -1, 65323, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 22, false, 65324, -1, 65324, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 24, false, 65325, -1, 65325, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 26, false, 65326, -1, 65326, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 28, false, 65327, -1, 65327, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 30, false, 65328, -1, 65328, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 32, false, 65329, -1, 65329, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 34, false, 65330, -1, 65330, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 36, false, 65331, -1, 65331, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 38, false, 65332, -1, 65332, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 40, false, 65333, -1, 65333, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 42, false, 65334, -1, 65334, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 44, false, 65335, -1, 65335, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 46, false, 65336, -1, 65336, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 48, false, 65337, -1, 65337, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 50, false, 65338, -1, 65338, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9985, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10219, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 9987, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10221, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10223, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10225, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 9963, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10001, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10003, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 9961, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10227, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6963, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10229, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10231, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10233, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10235, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10237, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10239, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10241, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10243, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10245, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10247, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6871, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6873, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6875, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6877, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6879, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6881, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6883, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6885, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6887, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6889, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6891, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6893, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6895, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6897, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6899, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6901, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6903, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6905, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6907, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6909, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6911, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6913, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6915, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6917, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6919, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6921, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6923, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6925, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6927, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6929, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6931, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6933, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6935, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6937, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6939, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6941, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6943, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6945, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6947, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6949, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6951, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6953, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6955, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 6957, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10249, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10251, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10253, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10255, false, -1, -1, -1, -1, -1, false, true, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10257, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10259, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10261, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10263, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10265, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10267, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10269, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10271, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10273, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10275, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10277, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10279, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10281, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10283, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10285, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10287, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10289, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10291, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10293, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10295, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10297, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10299, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10301, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10303, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10305, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10307, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10309, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10311, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10313, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10315, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10317, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10319, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10321, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10323, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10325, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10327, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10329, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10331, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10333, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10335, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10337, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10339, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10341, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10343, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10345, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10347, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10349, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10351, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10353, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10355, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10357, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10359, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10361, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10363, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SK, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10365, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10367, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10369, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SC, 0, UTF8PROC_BIDI_CLASS_ET, UTF8PROC_DECOMP_TYPE_WIDE, utf8proc_sequences + 10371, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10373, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10375, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10377, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10379, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10381, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10383, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_ON, UTF8PROC_DECOMP_TYPE_NARROW, utf8proc_sequences + 10385, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_CF, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, true, false, NULL}, + {UTF8PROC_CATEGORY_NL, 0, UTF8PROC_BIDI_CLASS_ON, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66600, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10387}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66601, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10389}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66602, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10391}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66603, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10393}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66604, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10395}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66605, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10397}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66606, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10399}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66607, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10401}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66608, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10403}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66609, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10405}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66610, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10407}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66611, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10409}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66612, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10411}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66613, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10413}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66614, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10415}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66615, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10417}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66616, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10419}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66617, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10421}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66618, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10423}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66619, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10425}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66620, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10427}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66621, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10429}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66622, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10431}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66623, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10433}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66624, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10435}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66625, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10437}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66626, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10439}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66627, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10441}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66628, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10443}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66629, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10445}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66630, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10447}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66631, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10449}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66632, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10451}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66633, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10453}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66634, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10455}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66635, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10457}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66636, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10459}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66637, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10461}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66638, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10463}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, 66639, -1, -1, -1, false, false, false, false, utf8proc_sequences + 10465}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66560, -1, 66560, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66561, -1, 66561, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66562, -1, 66562, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66563, -1, 66563, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66564, -1, 66564, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66565, -1, 66565, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66566, -1, 66566, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66567, -1, 66567, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66568, -1, 66568, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66569, -1, 66569, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66570, -1, 66570, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66571, -1, 66571, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66572, -1, 66572, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66573, -1, 66573, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66574, -1, 66574, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66575, -1, 66575, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66576, -1, 66576, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66577, -1, 66577, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66578, -1, 66578, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66579, -1, 66579, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66580, -1, 66580, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66581, -1, 66581, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66582, -1, 66582, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66583, -1, 66583, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66584, -1, 66584, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66585, -1, 66585, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66586, -1, 66586, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66587, -1, 66587, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66588, -1, 66588, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66589, -1, 66589, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66590, -1, 66590, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66591, -1, 66591, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66592, -1, 66592, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66593, -1, 66593, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66594, -1, 66594, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66595, -1, 66595, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66596, -1, 66596, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66597, -1, 66597, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66598, -1, 66598, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, 66599, -1, 66599, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_NO, 0, UTF8PROC_BIDI_CLASS_R, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 22080, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 22140, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10467, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10470, false, -1, -1, -1, 22200, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10473, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10476, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10479, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10482, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10485, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 54, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 226, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 55, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 56, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 57, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 58, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_MC, 216, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, -1, 59, false, false, false, true, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 22260, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, NULL, false, -1, -1, -1, 22320, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10488, false, -1, -1, -1, 22380, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10491, false, -1, -1, -1, 22440, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10494, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10497, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10500, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10503, false, -1, -1, -1, -1, -1, true, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2376, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2388, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2394, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2396, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2404, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 5231, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2412, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2414, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4662, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2416, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4689, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 5245, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 0, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 2, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 20, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 24, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 26, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 30, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 32, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 34, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 36, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 38, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 40, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 42, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 44, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 46, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 48, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 50, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10506, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10508, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10510, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10512, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10514, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10516, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10518, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10520, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1504, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10522, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10524, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10526, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10528, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10530, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10532, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10534, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10536, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10538, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1508, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10540, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1470, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10542, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10544, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10546, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4567, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10548, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1382, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1384, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1388, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1390, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1392, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1394, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1396, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1326, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1398, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1400, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 67, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1402, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1404, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1406, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1410, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1502, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1412, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1414, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1416, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1418, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1420, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1422, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1424, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_SM, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10550, true, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10552, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10554, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10556, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10558, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10560, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10562, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 10564, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 1482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4497, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 72, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 60, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 62, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4499, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4501, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4503, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4505, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4507, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_ND, 0, UTF8PROC_BIDI_CLASS_EN, UTF8PROC_DECOMP_TYPE_FONT, utf8proc_sequences + 4509, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10566, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10568, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10570, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10572, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10574, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10576, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10578, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10580, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10582, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10584, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10586, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10588, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10590, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10592, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10594, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10596, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10598, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10600, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10602, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10604, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10606, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10608, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10610, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10612, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10614, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5518, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10616, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10618, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10620, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10622, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10624, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10626, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10628, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10630, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10632, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10634, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10636, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10638, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10640, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10642, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10644, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10646, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10648, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10650, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10652, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10654, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10656, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10658, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10660, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10662, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10664, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10666, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10668, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10670, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10672, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10674, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10676, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10678, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10680, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10682, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10684, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10686, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10688, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10690, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10692, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10694, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10696, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10698, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10700, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10702, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10704, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10706, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10708, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10710, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10712, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10714, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10716, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10718, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10720, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10722, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10724, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10726, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10728, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10730, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10732, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10734, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10736, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10738, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10740, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10742, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10744, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10746, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10748, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10750, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10752, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10754, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10756, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10758, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10760, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5570, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10762, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10764, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10766, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10768, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10770, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10772, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10774, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10776, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10778, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10780, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10782, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10784, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10786, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10788, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10790, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10792, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10794, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10796, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10798, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10800, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10802, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10804, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10806, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10808, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5594, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10810, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10812, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10814, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10816, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10818, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10820, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10822, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10824, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10826, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10828, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10830, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10832, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10834, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10836, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10838, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10840, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10842, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10844, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10846, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10848, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10850, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10852, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10854, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10856, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10858, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10860, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10862, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10864, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10866, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10868, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10870, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10872, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10874, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10876, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10878, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10880, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10882, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10884, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10886, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10888, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10890, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10892, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10894, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10896, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10898, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10900, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10904, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10906, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10908, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10910, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10912, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10914, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10916, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10918, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10920, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10922, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10924, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10926, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10928, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10930, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10932, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10934, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10936, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10938, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10940, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10942, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10944, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10946, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10948, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10950, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10952, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10954, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10956, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10958, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10960, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10962, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10964, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10966, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10968, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10970, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10972, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10974, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10976, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10978, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10980, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10982, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10984, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10986, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10988, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10990, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10992, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10994, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10996, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 10998, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11000, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11002, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11004, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11006, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11008, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11010, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11012, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11014, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11016, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11018, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11020, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11022, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11024, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11026, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11028, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11030, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11032, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11034, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11036, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11038, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11040, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11042, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11044, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11046, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11048, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11050, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11052, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11054, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11056, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11058, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11060, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11062, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11064, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11066, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11068, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11070, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11072, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11074, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11076, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11078, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11080, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11082, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11084, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11086, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11088, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11090, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11092, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11094, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11096, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11098, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11100, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11102, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11104, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11106, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11108, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11110, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11112, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11114, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11116, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11118, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11120, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11122, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11124, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11126, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11128, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11130, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11132, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11134, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11136, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11138, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11140, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11142, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11144, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11146, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11148, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11150, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11152, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11154, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11156, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11158, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11160, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11162, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11164, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11166, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11168, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11170, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11172, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11174, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11176, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11178, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11180, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11182, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11184, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11186, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11188, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11190, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11192, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11194, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11196, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11198, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11200, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11202, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11204, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11206, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11208, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11210, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11212, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11214, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11216, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11218, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11220, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11222, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11224, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11226, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11228, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11230, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11232, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11234, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11236, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11238, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11240, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11242, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11244, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11246, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11248, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11250, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11252, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11254, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11256, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11258, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11260, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11262, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11264, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11266, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11268, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11270, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11272, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11274, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11276, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11278, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11280, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11282, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11284, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11286, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11288, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11290, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11292, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11294, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11296, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11298, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11300, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11302, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11304, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11306, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11308, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11310, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11312, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11314, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11316, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11318, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11320, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11322, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11324, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11326, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11328, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11330, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11332, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11334, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11336, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11338, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11340, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11342, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11344, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5774, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11346, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11348, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11350, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11352, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11354, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11356, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11358, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11360, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11362, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11364, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11366, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5788, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11368, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11370, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11372, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11374, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11376, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11378, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11380, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11382, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11384, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11386, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11388, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11390, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11392, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11394, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11396, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11398, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11400, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11402, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11404, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11406, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11408, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11410, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11412, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11414, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11416, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11418, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11420, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11422, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11424, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11426, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11428, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11430, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11432, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11434, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11436, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11438, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11440, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11442, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11444, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11446, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11448, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11450, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11452, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11454, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11456, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11458, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11460, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11462, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11464, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11466, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11468, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11470, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11472, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11474, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11476, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11478, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11480, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11482, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11484, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11486, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11488, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11490, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5884, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11492, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5892, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11494, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11496, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11498, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11500, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 5902, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, + {UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, utf8proc_sequences + 11502, false, -1, -1, -1, -1, -1, false, false, false, false, NULL}, +}; + +const int32_t utf8proc_combinations[] = { + 192, 193, 194, 195, 196, 197, -1, + 256, 258, 260, 550, 461, -1, -1, 512, + 514, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7680, 7840, -1, -1, -1, -1, -1, 7842, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 262, 264, + -1, -1, -1, 199, -1, -1, -1, 266, + 268, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 200, 201, 202, 7868, 203, -1, 552, + 274, 276, 280, 278, 282, -1, -1, 516, + 518, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7864, -1, 7704, 7706, -1, -1, 7866, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 204, 205, 206, + 296, 207, -1, -1, 298, 300, 302, 304, + 463, -1, -1, 520, 522, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7882, -1, -1, + 7724, -1, -1, 7880, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 504, 323, -1, 209, -1, -1, 325, + -1, -1, -1, 7748, 327, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7750, 7752, 7754, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 210, 211, 212, + 213, 214, -1, -1, 332, 334, 490, 558, + 465, 336, 416, 524, 526, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7884, -1, -1, + -1, -1, -1, 7886, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 217, 218, 219, 360, 220, 366, -1, + 362, 364, 370, -1, 467, 368, 431, 532, + 534, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7908, -1, 7798, 7796, -1, 7794, 7910, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7922, 221, 374, + 7928, 376, -1, -1, 562, -1, -1, 7822, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7924, -1, -1, + -1, -1, -1, 7926, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 224, 225, 226, 227, 228, 229, -1, + 257, 259, 261, 551, 462, -1, -1, 513, + 515, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7681, 7841, -1, -1, -1, -1, -1, 7843, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 263, 265, + -1, -1, -1, 231, -1, -1, -1, 267, + 269, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 232, 233, 234, 7869, 235, -1, 553, + 275, 277, 281, 279, 283, -1, -1, 517, + 519, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7865, -1, 7705, 7707, -1, -1, 7867, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 236, 237, 238, + 297, 239, -1, -1, 299, 301, 303, -1, + 464, -1, -1, 521, 523, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7883, -1, -1, + 7725, -1, -1, 7881, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 505, 324, -1, 241, -1, -1, 326, + -1, -1, -1, 7749, 328, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7751, 7753, 7755, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 242, 243, 244, + 245, 246, -1, -1, 333, 335, 491, 559, + 466, 337, 417, 525, 527, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7885, -1, -1, + -1, -1, -1, 7887, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 249, 250, 251, 361, 252, 367, -1, + 363, 365, 371, -1, 468, 369, 432, 533, + 535, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7909, -1, 7799, 7797, -1, 7795, 7911, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7923, 253, 375, + 7929, 255, 7833, -1, 563, -1, -1, 7823, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7925, -1, -1, + -1, -1, -1, 7927, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7696, + -1, -1, -1, 7690, 270, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7692, 7694, 7698, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7697, -1, -1, -1, 7691, + 271, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7693, 7695, 7699, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 500, 284, -1, -1, -1, 290, + 7712, 286, -1, 288, 486, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 501, 285, + -1, -1, -1, 291, 7713, 287, -1, 289, + 487, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 292, -1, 7718, -1, 7720, + -1, -1, -1, 7714, 542, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7716, -1, -1, -1, 7722, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 293, + -1, 7719, -1, 7721, -1, -1, -1, 7715, + 543, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7717, 7830, -1, + -1, 7723, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 308, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 309, + -1, -1, -1, -1, -1, -1, -1, -1, + 496, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7728, -1, -1, -1, -1, 310, + -1, -1, -1, -1, 488, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7730, 7732, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7729, -1, + -1, -1, -1, 311, -1, -1, -1, -1, + 489, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7731, 7733, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 313, -1, -1, -1, -1, 315, + -1, -1, -1, -1, 317, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7734, 7738, 7740, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 314, -1, + -1, -1, -1, 316, -1, -1, -1, -1, + 318, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7735, 7739, 7741, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 340, -1, -1, -1, -1, 342, + -1, -1, -1, 7768, 344, -1, -1, 528, + 530, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7770, 7774, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 341, -1, + -1, -1, -1, 343, -1, -1, -1, 7769, + 345, -1, -1, 529, 531, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7771, 7775, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 346, 348, -1, -1, -1, 350, + -1, -1, -1, 7776, 352, -1, -1, -1, + -1, 536, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7778, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 347, 349, + -1, -1, -1, 351, -1, -1, -1, 7777, + 353, -1, -1, -1, -1, 537, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7779, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 354, + -1, -1, -1, 7786, 356, -1, -1, -1, + -1, 538, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7788, 7790, 7792, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7831, -1, 355, -1, -1, -1, 7787, + 357, -1, -1, -1, -1, 539, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7789, 7791, 7793, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7808, 7810, 372, -1, 7812, -1, -1, + -1, -1, -1, 7814, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7816, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7809, 7811, 373, + -1, 7813, 7832, -1, -1, -1, -1, 7815, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7817, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 377, 7824, -1, -1, -1, -1, + -1, -1, -1, 379, 381, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7826, 7828, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 378, 7825, + -1, -1, -1, -1, -1, -1, -1, 380, + 382, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7827, 7829, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 475, 471, -1, -1, -1, -1, -1, + 469, -1, -1, -1, 473, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 476, 472, -1, + -1, -1, -1, -1, 470, -1, -1, -1, + 474, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 478, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 479, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 480, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 481, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 508, -1, -1, -1, -1, -1, + 482, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 509, -1, + -1, -1, -1, -1, 483, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 492, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 493, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 494, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 495, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 506, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 507, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 510, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 511, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 554, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 555, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7756, -1, -1, 7758, -1, -1, + 556, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7757, -1, + -1, 7759, -1, -1, 557, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 560, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 561, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8173, 901, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8129, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8122, 902, -1, + -1, -1, -1, -1, 8121, 8120, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7944, 7945, -1, 8124, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8136, 904, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7960, 7961, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8138, 905, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7976, 7977, -1, 8140, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8154, 906, -1, -1, 938, -1, -1, + 8153, 8152, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7992, 7993, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8184, 908, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8008, 8009, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8170, 910, -1, -1, 939, -1, -1, + 8169, 8168, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8025, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8186, 911, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8040, 8041, -1, 8188, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8146, 912, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8151, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8048, 940, -1, + -1, -1, -1, -1, 8113, 8112, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7936, 7937, 8118, 8115, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8050, 941, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7952, 7953, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8052, 942, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7968, 7969, 8134, 8131, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8054, 943, -1, -1, 970, -1, -1, + 8145, 8144, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7984, 7985, 8150, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8162, 944, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8167, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8058, 973, -1, -1, 971, -1, -1, + 8161, 8160, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8016, 8017, 8166, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8056, 972, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8000, 8001, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8060, 974, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8032, 8033, 8182, 8179, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 979, -1, + -1, 980, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1024, -1, -1, -1, 1025, -1, -1, + -1, 1238, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1027, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1031, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 1036, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1037, -1, -1, -1, 1252, -1, -1, + 1250, 1049, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1264, -1, -1, 1262, 1038, -1, -1, + -1, 1266, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1117, -1, -1, -1, 1253, -1, -1, + 1251, 1081, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1104, -1, -1, + -1, 1105, -1, -1, -1, 1239, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1107, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1111, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1116, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1265, -1, -1, 1263, 1118, -1, -1, + -1, 1267, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1142, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1143, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1244, -1, -1, + -1, 1217, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1245, -1, -1, -1, 1218, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1234, -1, -1, + -1, 1232, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1235, -1, -1, -1, 1233, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1242, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1243, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1246, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1247, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1254, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1255, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1258, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1259, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1260, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1261, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1268, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1269, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 1272, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 1273, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 1570, 1571, 1573, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1572, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1574, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1728, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 1730, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 1747, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 2345, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 2353, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 2356, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 2507, 2508, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 2888, 2891, 2892, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 2964, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3020, 3018, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 3019, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3144, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3264, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 3271, 3272, + 3274, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 3275, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 3402, 3404, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 3403, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 3546, 3548, 3550, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 3549, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 4134, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6918, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 6920, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6922, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 6924, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6926, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 6930, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6971, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 6973, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6976, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 6977, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 6979, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7682, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7684, 7686, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7683, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7685, 7687, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7688, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7689, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7700, 7702, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7701, 7703, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7708, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7709, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7710, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7711, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7726, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7727, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7736, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7737, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7742, -1, -1, -1, -1, -1, + -1, -1, -1, 7744, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7746, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7743, -1, + -1, -1, -1, -1, -1, -1, -1, 7745, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7747, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7760, 7762, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7761, 7763, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7764, -1, -1, -1, -1, -1, + -1, -1, -1, 7766, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7765, -1, + -1, -1, -1, -1, -1, -1, -1, 7767, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7772, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7773, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7780, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7781, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7782, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7783, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7784, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7785, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7800, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7801, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7802, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7803, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 7804, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7806, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 7805, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7807, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7820, -1, -1, + -1, -1, -1, 7818, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7821, -1, -1, -1, -1, -1, 7819, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7835, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7846, 7844, -1, + 7850, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7848, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7847, 7845, -1, 7851, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7849, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7852, + -1, -1, -1, -1, -1, 7862, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7853, -1, -1, -1, -1, + -1, 7863, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7856, 7854, -1, + 7860, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7858, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7857, 7855, -1, 7861, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7859, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7872, 7870, -1, + 7876, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7874, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7873, 7871, -1, 7877, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7875, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7878, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7879, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7890, 7888, -1, + 7894, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7892, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7891, 7889, -1, 7895, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7893, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 7896, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 7897, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7900, 7898, -1, + 7904, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7906, -1, -1, + -1, -1, -1, 7902, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7901, 7899, -1, 7905, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7907, -1, -1, -1, -1, -1, 7903, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7914, 7912, -1, + 7918, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7920, -1, -1, + -1, -1, -1, 7916, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7915, 7913, -1, 7919, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7921, -1, -1, -1, -1, -1, 7917, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7938, 7940, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7942, 8064, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7939, 7941, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7943, 8065, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7946, 7948, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7950, 8072, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7947, 7949, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7951, 8073, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7954, 7956, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7955, 7957, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7962, 7964, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7963, 7965, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7970, 7972, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7974, 8080, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7971, 7973, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7975, 8081, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7978, 7980, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7982, 8088, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7979, 7981, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7983, 8089, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7986, 7988, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7990, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7987, 7989, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7991, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 7994, 7996, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 7998, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 7995, 7997, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 7999, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8002, 8004, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8003, 8005, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8010, 8012, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8011, 8013, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8018, 8020, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8022, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8019, 8021, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8023, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8027, 8029, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8031, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8034, 8036, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8038, 8096, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8035, 8037, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8039, 8097, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8042, 8044, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8046, 8104, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8043, 8045, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8047, 8105, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8066, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8067, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8068, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8069, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8070, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8071, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8074, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8075, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8076, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8077, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8078, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8079, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8082, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8083, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8084, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8085, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8086, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8087, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8090, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8091, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8092, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8093, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8094, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8095, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8098, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8099, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8100, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8101, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8102, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8103, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8106, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8107, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8108, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8109, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8110, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8111, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8114, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8116, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8119, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8130, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8132, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8135, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 8141, 8142, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 8143, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8157, 8158, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, 8159, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8164, 8165, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 8172, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8178, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 8180, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 8183, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8602, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8603, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8622, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8653, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8654, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8655, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8708, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8713, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8716, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8740, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8742, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8769, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8772, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8775, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8777, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8800, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8802, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8813, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8814, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8815, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8816, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8817, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8820, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8821, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8824, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8825, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8832, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8833, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8836, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8837, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8840, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8841, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8876, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8877, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8878, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8879, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8928, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8929, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8930, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8931, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8938, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8939, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 8940, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 8941, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 10972, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12364, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12366, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12368, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12370, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12372, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12374, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12376, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12378, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12380, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12382, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12384, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12386, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12389, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12391, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12393, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12400, 12401, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12403, 12404, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12406, 12407, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12409, 12410, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12412, 12413, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12436, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12446, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12460, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12462, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12464, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12466, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12468, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12470, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12472, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12474, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12476, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12478, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12480, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12482, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12485, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12487, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12489, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12496, 12497, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12499, 12500, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12502, 12503, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12505, 12506, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12508, 12509, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12532, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12535, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12536, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12537, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, 12538, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, 12542, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 119134, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 119135, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 119136, 119137, 119138, 119139, 119140, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 119227, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 119228, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, 119229, 119231, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, + 119230, 119232, -1, -1, -1, }; + diff --git a/server/version.c b/server/version.c new file mode 100644 index 0000000..e572bbf --- /dev/null +++ b/server/version.c @@ -0,0 +1,51 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the version identification of the Zephyr server + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#include + +#include "zserver.h" +#include + +const char zephyr_version[] = "Zephyr system version" ZEPHYR_VERSION_STRING; + +#ifdef DEBUG +const char version[] = "Zephyr Server (DEBUG) " ZEPHYR_VERSION_STRING; +#else +const char version[] = "Zephyr Server " ZEPHYR_VERSION_STRING; +#endif + +#if !defined (lint) && !defined (SABER) +static const char copyright[] = + "Copyright (c) 1987,1988,1989,1990 Massachusetts Institute of Technology.\n"; +#endif + +char * +get_version(void) +{ + static char vers_buf[256]; + struct utsname un; + + if (vers_buf[0] == '\0') { + strcpy(vers_buf, version); + + (void) strcat(vers_buf, "/"); + + uname(&un); + (void) strcat(vers_buf, un.machine); + (void) strcat(vers_buf, "-"); + (void) strcat(vers_buf, un.sysname); + } + + return(vers_buf); +} diff --git a/server/zephyrd.8.in b/server/zephyrd.8.in new file mode 100644 index 0000000..eef9780 --- /dev/null +++ b/server/zephyrd.8.in @@ -0,0 +1,129 @@ +.\" $Id$ +.\" +.\" Copyright 1987 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.TH ZEPHYRD 8 "July 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zephyrd \- Zephyr server daemon +.SH SYNOPSIS +.I @sbindir@/zephyrd +[ +.BI \-d +] +.SH DESCRIPTION +.I zephyrd +is the central server for the Zephyr Notification System. +It maintains a location database of all currently logged-in users, and a +subscription database for each user's Zephyr clients. +.PP +.I zephyrd +communicates with daemons running on other Zephyr server hosts, to +provide a reliable service. +.PP +While running, any unusual conditions are recorded via +.I syslog(3) +to facility local6 at various levels. +The +.BI \-d +option enables logging of additional debugging information. +.PP +When a +.B zephyrd +is executed, it requests a list of server machines from Hesiod and +initializes its state from any +\fIzephyrd\fRs executing on the other known servers. This initialization +is only performed after the \fIzephyrd\fRs have authenticated themselves +to each other via Kerberos. +The server then enters a dispatch loop, servicing requests from clients and +other servers. +.SH SIGNALS +.B SIGUSR1 +enables logging of additional debugging information. +.br +.B SIGUSR2 +disables the logging of additional debugging information. +.br +.B SIGHUP +causes +.I zephyrd +to re-read the default subscription file and to re-query Hesiod about +valid peers. Any peers which are not responding and no longer +mentioned in Hesiod are flushed; any peers not previously named by +Hesiod are added. +.br +.B SIGINT \fRand\fB SIGTERM +cause +.I zephyrd +to gracefully shut down. +.br +.B SIGFPE +causes +.I zephyrd +to dump the location and subscription databases to +.I /var/tmp/zephyr.db +in an ASCII format. +.SH ACCESS CONTROL +Certain notice classes are restricted by the Zephyr server. Each such +class has access control lists enumerating who may transmit (xmt-*.acl) or +subscribe to that particular class. Subscriptions may be +restricted either absolutely (sub-*.acl files), or by instance restrictions. +iws-*.acl files control subscriptions to wildcarded instances. +iui-*.acl files control subscriptions to instances which are not the +Kerberos principal identity of the subscriber. +If an access control list of a given type is absent, there is no +restriction of that type on the class, except that any notices of the +class must be authenticated. +The class registry lists all classes which are restricted. +.SH FILES +.TP 10 +.I @sysconfdir@/zephyr/acl/class-registry.acl: +List of classes which are restricted +.TP +.I @sysconfdir@/zephyr/acl/iws-*.acl: +Access Control Lists for instance-wildcard restrictions +.TP +.I @sysconfdir@/zephyr/acl/iui-*.acl: +Access Control Lists for instance-identity restrictions +.TP +.I @sysconfdir@/zephyr/acl/sub-*.acl: +Access Control Lists for subscribing +.TP +.I @sysconfdir@/zephyr/acl/xmt-*.acl: +Access Control Lists for transmitting +.TP +.I @sysconfdir@/zephyr/srvtab: +Kerberos 4 Service keys +.TP +.I @sysconfdir@/zephyr/krb5.keytab: +Kerberos V Service keys +.TP +.I /var/run/zephyrd.tkt4: +Current Kerberos 4 tickets for exchange with other servers +.TP +.I /var/run/zephyrd.tkt: +Current Kerberos 5 tickets for exchange with other servers +.TP +.I /var/tmp/zephyr.db: +File containing an ASCII dump of the database. +.SH BUGS +The current implementation of the Zephyr server (\fIzephyrd(8)\fR) makes +no distinction between realm-announced, net-visible and net-announced +exposure levels. +.SH SEE ALSO +zephyr(1), zhm(8), kerberosintro(1), hesiod(3), access_control_lists(?), +syslog(3) +.br +Athena Technical Plan, Sections E.4.1 (Zephyr Notification Service) and +E.2.1 (Kerberos Authentication and Authorization System) +.SH AUTHOR +.PP +John T. Kohl, MIT Project Athena and Digital Equipment Corporation +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/server/zserver.h b/server/zserver.h new file mode 100644 index 0000000..38dc07b --- /dev/null +++ b/server/zserver.h @@ -0,0 +1,532 @@ +#ifndef __ZSERVER_H__ +#define __ZSERVER_H__ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains declarations for use in the server. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1987,1988,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#include +#ifdef HAVE_ARES +#include +#endif + +#include + +#include "zsrv_err.h" + +#include "timer.h" +#include "zsrv_conf.h" /* configuration params */ + +#include "zstring.h" +#include "access.h" +#include "acl.h" +#include "utf8proc.h" + + +/* Kerberos-specific library interfaces used only by the server. */ +#ifdef HAVE_KRB5 +extern krb5_keyblock *__Zephyr_keyblock; +#define ZGetSession() (__Zephyr_keyblock) +void ZSetSession(krb5_keyblock *keyblock); +krb5_error_code Z_krb5_init_keyblock(krb5_context, krb5_enctype, size_t, + krb5_keyblock **); +#endif + +#ifdef HAVE_KRB4 +void ZSetSessionDES(C_Block *key); + +Code_t ZFormatAuthenticNotice(ZNotice_t*, char*, int, int*, C_Block); + +#ifndef HAVE_KRB5 +extern C_Block __Zephyr_session; +#define ZGetSession() (__Zephyr_session) +#endif +#endif + +/* For krb_rd_req prototype and definition. */ +#ifndef KRB_INT32 +#define KRB_INT32 ZEPHYR_INT32 +#endif + +/* Current time as cached by main(); use instead of time(). */ +#define NOW t_local.tv_sec + +#ifdef HAVE_KRB4 +/* Kerberos shouldn't stick us with array types... */ +typedef struct { + des_key_schedule s; +} Sched; +#endif + +enum _ZRealm_state { + REALM_NEW, /* New realm; no servers yet */ + REALM_UP, /* ZRealm is up */ + REALM_TARDY, /* ZRealm due for a hello XXX */ + REALM_DEAD, /* ZRealm is considered dead */ + REALM_STARTING /* ZRealm is between dead and up */ +}; + +enum _Server_state { + SERV_UP, /* Server is up */ + SERV_TARDY, /* Server due for a hello */ + SERV_DEAD, /* Server is considered dead */ + SERV_STARTING /* Server is between dead and up */ +}; + +enum _Sent_type { + NOT_SENT, /* message was not xmitted */ + SENT, /* message was xmitted */ + AUTH_FAILED, /* authentication failed */ + NOT_FOUND /* user not found for uloc */ +}; + +typedef struct _Destination Destination; +typedef struct _Destlist Destlist; +typedef struct _ZRealm ZRealm; +typedef struct _ZRealmname ZRealmname; +typedef enum _ZRealm_state ZRealm_state; +typedef struct _ZRealm_server ZRealm_server; +typedef struct _Client Client; +typedef struct _Triplet Triplet; +typedef enum _Server_state Server_state; +typedef struct _Unacked Unacked; +typedef struct _Pending Pending; +typedef struct _Server Server; +typedef enum _Sent_type Sent_type; +typedef struct _Statistic Statistic; + +struct _Destination { + String *classname; + String *inst; + String *recip; +}; + +struct _Destlist { + Destination dest; + struct _Destlist *next, **prev_p; +}; + +struct _ZRealm_server { + String *name; /* server's hostname */ + struct sockaddr_in addr; /* server's address */ + ZRealm *realm; /* realm this server belongs to */ + Timer *timer; /* timer for name lookup */ + unsigned int dontsend :1; /* private server, do not send */ + unsigned int got_addr :1; /* IP address is valid */ + unsigned int deleted :1; /* server no longer exists */ +}; + +struct _ZRealm { + String *namestr; /* realm's name */ + char *name; /* always namestr->string */ + int count; + ZRealm_server **srvrs; + int idx; /* which server we are connected to */ + Destlist *subs; /* what their clients sub to */ + Destlist *remsubs; /* our subs on their end */ + Client *client; + int child_pid; + int have_tkt; + ZRealm_state state; +}; + +struct _ZRealmname { + String *name; + struct _ZRealm_server *servers; + int nused; + int nservers; +}; + +struct _Client { + struct sockaddr_in addr; /* ipaddr/port of client */ + Destlist *subs ; /* subscriptions */ +#ifdef HAVE_KRB5 + krb5_keyblock *session_keyblock; +#else +#ifdef HAVE_KRB4 + C_Block session_key; /* session key for this client */ +#endif /* HAVE_KRB4 */ +#endif + String *principal; /* krb principal of user */ + int last_send; /* Counter for last sent packet. */ + time_t last_ack; /* Time of last received ack */ + ZRealm *realm; + struct _Client *next, **prev_p; +}; + +struct _Triplet { + Destination dest; + Acl *acl; + Client **clients; + int clients_size; + struct _Triplet *next, **prev_p; +}; + +struct _Unacked { + Timer *timer; /* timer for retransmit */ + Client *client; /* responsible client, or NULL */ + short rexmits; /* number of retransmits */ + short packsz; /* size of packet */ + char *packet; /* ptr to packet */ + ZUnique_Id_t uid; /* uid of packet */ + struct sockaddr_in ack_addr; + union { /* address to send to */ + struct sockaddr_in addr; /* client address */ + int srv_idx; /* index of server */ + struct { + ZRealm *realm; /* pointer to realm */ + int rlm_srv_idx; /* index of server in realm */ + } rlm; + } dest; + struct _Unacked *next, **prev_p; +}; + +struct _Pending { + char *packet; /* the notice (in pkt form) */ + short len; /* len of pkt */ + unsigned int auth; /* whether it is authentic */ + struct sockaddr_in who; /* the addr of the sender */ + struct _Pending *next; +}; + +struct _Server { + Server_state state; /* server's state */ + struct sockaddr_in addr; /* server's address */ + long timeout; /* Length of timeout in sec */ + Timer *timer; /* timer for this server */ + Pending *queue; /* queue of packets to send + to this server when done dumping */ + Pending *queue_last; /* last packet on queue */ + short num_hello_sent; /* number of hello's sent */ + unsigned int dumping; /* 1 if dumping, so we should queue */ + char addr_str[16]; /* text version of address */ +}; + +/* statistics gathering */ +struct _Statistic { + int val; + char *str; +}; + +typedef enum _Exposure_type { + NONE, + OPSTAFF_VIS, + REALM_VIS, + REALM_ANN, + NET_VIS, + NET_ANN +} Exposure_type; + +typedef struct _Location { + String *user; + String *machine; + char *time; /* in ctime format */ + String *tty; + struct sockaddr_in addr; /* IP address and port of location */ + Exposure_type exposure; +} Location; + +/* Function declarations */ + +/* These macros instantiate inline functions that do the work of the formder + LIST_INSERT and LIST_DELETE functions, which unfortunately triggered gcc's + pedanticism. The comment before the *former* macros was: */ +/* These macros are for insertion into and deletion from a singly-linked list + * with back pointers to the previous element's next pointer. In order to + * make these macros act like expressions, they use the comma operator for + * sequenced evaluations of assignment, and "a && b" for "evaluate assignment + * b if expression a is true". */ + +#define MAKE_LIST_INSERT(type) inline static void type##_insert(type **head, type *elem) \ + {\ + (elem)->next = *(head); \ + if(*head) (*(head))->prev_p = &(elem)->next; \ + (*head) = (elem); \ + (elem)->prev_p = (head); \ + } + +#define MAKE_LIST_DELETE(type) inline static void type##_delete(type *elem) \ + {\ + *(elem)->prev_p = (elem)->next; \ + if((elem)->next) (elem)->next->prev_p = (elem)->prev_p; \ + } + +MAKE_LIST_INSERT(Destlist) +MAKE_LIST_DELETE(Destlist) +MAKE_LIST_INSERT(Client) +MAKE_LIST_DELETE(Client) +MAKE_LIST_INSERT(Triplet) +MAKE_LIST_DELETE(Triplet) +MAKE_LIST_INSERT(Unacked) +MAKE_LIST_DELETE(Unacked) + +/* found in bdump.c */ +void bdump_get(ZNotice_t *notice, int auth, struct sockaddr_in *who, + Server *server); +void bdump_send(void); +void bdump_offer(struct sockaddr_in *who); +Code_t bdump_send_list_tcp(ZNotice_Kind_t kind, struct sockaddr_in *addr, + char *class_name, char *inst, char *opcode, + char *sender, char *recip, char **lyst, + int num); +int get_tgt(void); + +/* found in class.c */ +extern String *class_control, *class_admin, *class_hm; +extern String *class_ulogin, *class_ulocate; +int ZDest_eq(Destination *d1, Destination *d2); +Code_t triplet_register(Client *client, Destination *dest, ZRealm *realm); +Code_t triplet_deregister(Client *client, Destination *dest, + ZRealm *realm); +Code_t class_restrict(char *class_name, Acl *acl); +Code_t class_setup_restricted(char *class_name, Acl *acl); +Client **triplet_lookup(Destination *dest); +Acl *class_get_acl(String *class_name); +int dest_eq(Destination *d1, Destination *d2); +int order_dest_strings(Destination *d1, Destination *d2); +void triplet_dump_subs(FILE *fp); + +/* found in client.c */ +Code_t client_register(ZNotice_t *notice, struct in_addr *host, + Client **client_p, int wantdefaults); +void client_deregister(Client *client, int flush); +void client_flush_host(struct in_addr *host); +void client_flush_princ(char *target); +void client_dump_clients(FILE *fp); +Client *client_find(struct in_addr *host, unsigned int port); +Code_t client_send_clients(void); + +/* found in common.c */ +char *strsave(const char *str); +unsigned long hash (const char *); +void dump_quote(char *p, FILE *fp); +void notice_extract_address(ZNotice_t *notice, struct sockaddr_in *addr); +int packets_waiting(void); + +/* found in dispatch.c */ +void handle_packet(void); +void clt_ack(ZNotice_t *notice, struct sockaddr_in *who, Sent_type sent); +void nack_release(Client *client); +void sendit(ZNotice_t *notice, int auth, struct sockaddr_in *who, + int external); +void rexmit(void *); +void xmit(ZNotice_t *notice, struct sockaddr_in *dest, int auth, + Client *client); +Code_t hostm_dispatch(ZNotice_t *notice, int auth, + struct sockaddr_in *who, Server *server); +Code_t control_dispatch(ZNotice_t *notice, int auth, + struct sockaddr_in *who, Server *server); +Code_t xmit_frag(ZNotice_t *notice, char *buf, int len, int waitforack); +void hostm_shutdown(void); + +/* found in kstuff.c */ +Code_t ZCheckSrvAuthentication(ZNotice_t *notice, struct sockaddr_in *from, char *realm); +#if defined(HAVE_KRB4) || defined(HAVE_KRB5) +Code_t ReadKerberosData(int, int *, char **, int *); +void sweep_ticket_hash_table(void *); +#endif +#ifdef HAVE_KRB4 +int GetKerberosData (int, struct in_addr, AUTH_DAT *, char *, char *); +Code_t SendKerberosData (int, KTEXT, char *, char *); +#endif +#ifdef HAVE_KRB5 +Code_t SendKrb5Data(int, krb5_data *); +Code_t GetKrb5Data(int, krb5_data *); +#endif + +/* found in server.c */ +void server_timo(void *which); +void server_dump_servers(FILE *fp); +void server_init(void); +void server_shutdown(void); +void server_forward(ZNotice_t *notice, int auth, + struct sockaddr_in *who); +void server_kill_clt(Client *client); +void server_pending_free(Pending *pending); +void server_self_queue(ZNotice_t *, int, struct sockaddr_in *); +void server_send_queue(Server *); +void server_reset(void); +Server *server_which_server(struct sockaddr_in *who); +Pending *server_dequeue(Server *server); +Code_t server_dispatch(ZNotice_t *notice, int auth, + struct sockaddr_in *who); +Code_t server_adispatch(ZNotice_t *notice, int auth, + struct sockaddr_in *who, Server *server); + +/* found in subscr.c */ +Code_t subscr_foreign_user(ZNotice_t *, struct sockaddr_in *, Server *, ZRealm *); +Code_t subscr_cancel(struct sockaddr_in *sin, ZNotice_t *notice); +Code_t subscr_subscribe(Client *who, ZNotice_t *notice, Server *server); +Code_t subscr_send_subs(Client *client); +void subscr_cancel_client(Client *client); +void subscr_sendlist(ZNotice_t *notice, int auth, + struct sockaddr_in *who); +void subscr_dump_subs(FILE *fp, Destlist *subs); +void subscr_reset(void); +Code_t subscr_def_subs(Client *who); +Code_t subscr_realm(ZRealm *, ZNotice_t *); +Code_t subscr_send_realm_subs(ZRealm *); +Code_t subscr_realm_subs(ZRealm *); +Code_t subscr_realm_cancel(struct sockaddr_in *, ZNotice_t *, ZRealm *); + +/* found in uloc.c */ +void uloc_hflush(struct in_addr *addr); +void uloc_flush_client(struct sockaddr_in *sin); +void uloc_dump_locs(FILE *fp); +Code_t ulogin_dispatch(ZNotice_t *notice, int auth, + struct sockaddr_in *who, Server *server); +Code_t ulocate_dispatch(ZNotice_t *notice, int auth, + struct sockaddr_in *who, Server *server); +Code_t uloc_send_locations(void); +void ulogin_relay_locate(ZNotice_t *, struct sockaddr_in *); +void ulogin_realm_locate(ZNotice_t *, struct sockaddr_in *, ZRealm *); + +/* found in realm.c */ +int realm_sender_in_realm(const char *realm, char *sender); +int realm_bound_for_realm(const char *realm, char *recip); +ZRealm *realm_which_realm(struct sockaddr_in *who); +ZRealm *realm_get_realm_by_name(char *name); +ZRealm *realm_get_realm_by_name_string(String *namestr); +ZRealm *realm_get_realm_by_pid(int); +void realm_handoff(ZNotice_t *, int, struct sockaddr_in *, ZRealm *, int); +const char *realm_expand_realm(char *); +void realm_init(void); +Code_t ZCheckZRealmAuthentication(ZNotice_t *, struct sockaddr_in *, + char *); +Code_t realm_control_dispatch(ZNotice_t *, int, struct sockaddr_in *, + Server *, ZRealm *); +void realm_shutdown(void); +void realm_deathgram(Server *); +Code_t realm_send_realms(void); +Code_t realm_dispatch(ZNotice_t *, int, struct sockaddr_in *, Server *); +void kill_realm_pids(void); +void realm_dump_realms(FILE *); + +/* found in version.c */ +char *get_version(void); + +/* found in access.c */ +int access_check(char *, struct sockaddr_in *, Acl *, Access); +int opstaff_check(char *); + +/* global identifiers */ + +/* found in global.c */ +extern struct sockaddr_in srv_addr; /* server socket address */ +extern unsigned short hm_port; /* host manager receiver port */ +extern unsigned short hm_srv_port; /* host manager server sending port */ +extern int srv_socket; /* dgram sockets for clients + and other servers */ +extern int bdump_socket; /* brain dump socket + (closed most of the time) */ +#ifdef HAVE_ARES +extern ares_channel achannel; +#endif + +extern fd_set interesting; /* the file descrips we are listening + to right now */ +extern int nfds; /* number to look at in select() */ +extern int zdebug; +#ifdef DEBUG +extern int zalone; +#endif +extern char myname[]; /* domain name of this host */ +extern char list_file[]; +#ifdef HAVE_KRB5 +extern char keytab_file[]; +extern krb5_ccache Z_krb5_ccache; +#endif +#ifdef HAVE_KRB4 +extern char srvtab_file[]; +#endif +extern char acl_dir[]; +extern char subs_file[]; +extern const char version[]; +extern u_long npackets; /* num of packets processed */ +extern time_t uptime; /* time we started */ +extern struct in_addr my_addr; /* my inet address */ +extern struct timeval t_local; /* current time */ +extern char *bdump_version; +extern int bdump_auth_proto; + +/* found in bdump.c */ +extern int bdumping; /* are we processing a bdump packet? */ +extern int bdump_concurrent; /* set while processing a packet + * concurrently during a braindump. */ + +/* found in dispatch.c */ +extern Statistic i_s_ctls, i_s_logins, i_s_admins, i_s_locates; +extern int rexmit_times[]; + +/* found in server.c */ +extern Server *otherservers; /* array of servers */ +extern int me_server_idx; /* me (in the array of servers) */ +extern int nservers; /* number of other servers*/ + +/* found in subscr.c */ +extern String *empty; +extern String *wildcard_instance; + +extern ZRealm **otherrealms; +extern int nrealms; + + +#define class_is_control(classname) (classname == class_control) +#define class_is_admin(classname) (classname == class_admin) +#define class_is_hm(classname) (classname == class_hm) +#define class_is_ulogin(classname) (classname == class_ulogin) +#define class_is_ulocate(classname) (classname == class_ulocate) + +#define ADMIN_HELLO "HELLO" /* Opcode: hello, are you there */ +#define ADMIN_IMHERE "IHEARDYOU" /* Opcode: yes, I am here */ +#define ADMIN_SHUTDOWN "GOODBYE" /* Opcode: I am shutting down */ +#define ADMIN_BDUMP "DUMP_AVAIL" /* Opcode: I will give you a dump */ +#define ADMIN_DONE "DUMP_DONE" /* Opcode: brain dump for this server + is complete */ +#define ADMIN_NEWCLT "NEXT_CLIENT" /* Opcode: this is a new client */ +#define ADMIN_KILL_CLT "KILL_CLIENT" /* Opcode: client is dead, remove */ +#define ADMIN_STATUS "STATUS" /* Opcode: please send status */ + +#define ADMIN_NEWREALM "NEXT_REALM" /* Opcode: this is a new realm */ +#define REALM_REQ_LOCATE "REQ_LOCATE" /* Opcode: request a location */ +#define REALM_ANS_LOCATE "ANS_LOCATE" /* Opcode: answer to location */ +#define REALM_BOOT "SENDSUBS" /* Opcode: first server in realm */ + +/* me_server_idx is the index into otherservers of this server descriptor. */ +/* the 'limbo' server is always the first server */ + +#define me_server (&otherservers[me_server_idx]) +#define limbo_server_idx() (0) +#define limbo_server (&otherservers[limbo_server_idx()]) + +#define msgs_queued() (ZQLength() || otherservers[me_server_idx].queue) + +#define ack(a,b) clt_ack(a,b,SENT) +#define nack(a,b) clt_ack(a,b,NOT_SENT) + +#define min(a,b) ((a) < (b) ? (a) : (b)) +#define max(a,b) ((a) > (b) ? (a) : (b)) + +#define START_CRITICAL_CODE +#define END_CRITICAL_CODE + +/* the instance that matches all instances */ +#define WILDCARD_INSTANCE "*" + +/* debugging macros */ +#ifdef DEBUG +#define zdbug(s1) if (zdebug) syslog s1; +#else /* !DEBUG */ +#define zdbug(s1) +#endif /* DEBUG */ + +#endif /* !__ZSERVER_H__ */ diff --git a/server/zsrv_conf.h b/server/zsrv_conf.h new file mode 100644 index 0000000..9c2f674 --- /dev/null +++ b/server/zsrv_conf.h @@ -0,0 +1,55 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains site-specific definitions for use in the server. + * + * Created by: John T. Kohl + * + * $Id$ + * + * Copyright (c) 1988 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef __ZSRV_CONF_H__ +#define __ZSRV_CONF_H__ +#include + +/* Path names are relative to CONFDIR, except for the class registry and + ticket files. */ + +#define SERVER_LIST_FILE "server.list" +#define REALM_LIST_FILE "realm.list" +#ifdef HAVE_KRB5 +#define ZEPHYR_KEYTAB "krb5.keytab" +#define ZEPHYR_TK5FILE "/var/run/zephyrd.tkt" +#endif +#ifdef HAVE_KRB4 +#define ZEPHYR_SRVTAB "srvtab" +#define ZEPHYR_TKFILE "/var/run/zephyrd.tkt4" +#endif +#define ZEPHYR_ACL_DIR "acl/" +#define ZEPHYR_CLASS_REGISTRY "class-registry.acl" +#define DEFAULT_SUBS_FILE "default.subscriptions" + +#define REXMIT_TIMES { 2, 2, 4, 4, 8, 8, 16, 32, 64, 128, 256, 512, -1 } +#define NUM_REXMIT_TIMES 12 +#define CLIENT_GIVEUP_MIN 512 + +/* hostmanager defines */ +#define LOSE_TIMO (60) /* time during which a losing host + must respond to a ping */ + +/* server-server defines */ +#define TIMO_UP ((long) 60) /* timeout between up and tardy */ +#define TIMO_TARDY ((long) 120) /* timeout btw tardy hellos */ +#define TIMO_DEAD ((long)(15*60)) /* timeout between hello's for dead */ + +#define H_NUM_TARDY 5 /* num hello's before going dead + when tardy */ +#define H_NUM_STARTING 2 /* num hello's before going dead + when starting */ + +#define SWEEP_INTERVAL 3600 /* Time between sweeps of the ticket + hash table */ + +#endif /* __ZSRV_CONF_H__ */ diff --git a/server/zsrv_err.et b/server/zsrv_err.et new file mode 100644 index 0000000..36d6a3f --- /dev/null +++ b/server/zsrv_err.et @@ -0,0 +1,43 @@ +# Copyright (c) 1987,1988 Massachusetts Institute of Technology +# +# For copying and distribution information, see the file +# "mit-copyright.h". +# +# $Id$ + et zsrv + +ec ZSRV_BADASSOC, + "Client not associated with class" +ec ZSRV_NOCLT, + "No such client" +ec ZSRV_NOSUB, + "No such subscription" +ec ZSRV_NOCLASS, + "Class unknown" +ec ZSRV_CLASSXISTS, + "Class already registered" +ec ZSRV_CLASSRESTRICTED, + "Class already restricted" +ec ZSRV_HNOTFOUND, + "Host manager unknown" +ec ZSRV_WRONGSRV, + "Host not on this server" +ec ZSRV_PKSHORT, + "Pkt length too short" +ec ZSRV_BUFSHORT, + "Buffer too short" +ec ZSRV_LEN, + "Read/Write length wrong" +ec ZSRV_UNKNOWNOPCODE, + "Unknown opcode" +ec ZSRV_REQUEUE, + "Requeue for later processing" +ec ZSRV_RCSID, + "$Id$" +ec ZSRV_BADSUBPORT, + "Illegal port specified in subscription" +ec ZSRV_NORLM, + "No such realm" +ec ZSRV_EMPTYCLASS, + "Class is now empty" + end diff --git a/server/zstring.c b/server/zstring.c new file mode 100644 index 0000000..e7d0820 --- /dev/null +++ b/server/zstring.c @@ -0,0 +1,191 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the main loop of the Zephyr server + * + * Created by: Lucien W. Van Elsen + * + * $Id$ + * + * Copyright (c) 1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "zserver.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_zstring_c[] = +"$Id$"; +#endif +#endif + +static String *zhash[STRING_HASH_TABLE_SIZE]; + +static int +valid_utf8_p(const char* s) +{ + ssize_t len; + int32_t uc; + + while ((len = utf8proc_iterate((const unsigned char *)s, -1, &uc))) { + if (len <=0) return 0; /* Not valid UTF-8 encoding. */ + if (!(utf8proc_codepoint_valid(uc))) return 0; /* Not valid unicode codepoint. */ + if (uc == 0) return 1; /* NULL, we're done. */ + s += len; + } + return 0; /* We shouldn't get here. */ +} + +static char *zdowncase(const char* s) +{ + unsigned char *new_s_u; /* Avoid strict aliasing violation */ + char *new_s, *p; + + if (valid_utf8_p(s)) { + /* Use utf8proc if we're dealing with UTF-8. + * Rather than downcase, casefold and normalize to NFKC. + */ + utf8proc_map((const unsigned char *)s, 0, (unsigned char **)&new_s_u, + UTF8PROC_NULLTERM | UTF8PROC_STABLE + | UTF8PROC_CASEFOLD | UTF8PROC_COMPAT + | UTF8PROC_COMPOSE); + new_s = (char *)new_s_u; + } else { + /* If not, fall back to old methods. */ + new_s = strsave(s); + p = new_s; + while(*p) { + if (isascii(*p) && isupper(*p)) + *p = tolower(*p); + p++; + } + } + return new_s; +} + +String * +make_string(char *s, + int downcase) +{ + char *new_s; + String *new_z,*hp; + int i; + + if (downcase) { + new_s = zdowncase(s); + } else { + new_s = s; + } + + new_z = find_string(new_s,0); + if (new_z != NULL) { + if (downcase) + free(new_s); + new_z->ref_count++; + return(new_z); + } + + /* Initialize new String */ + + if (!downcase) + new_s = strsave(s); + new_z = (String *) malloc(sizeof(String)); + new_z->string = new_s; + new_z->ref_count = 1; + + /* Add to beginning of hash table */ + new_z->hash_val = hash(new_s); + i = new_z->hash_val % STRING_HASH_TABLE_SIZE; + hp = zhash[i]; + new_z->next = hp; + if (hp != NULL) + hp->prev = new_z; + new_z->prev = NULL; + zhash[i] = new_z; + + return new_z; +} + +void +free_string(String *z) +{ + if (z == (String *) NULL) + return; + + z->ref_count--; + if (z->ref_count > 0) + return; + + /* delete string completely */ + if(z->prev == NULL) + zhash[hash(z->string) % STRING_HASH_TABLE_SIZE] = z->next; + else + z->prev->next = z->next; + + if (z->next != NULL) + z->next->prev = z->prev; + + free(z->string); + free(z); +} + +String * +find_string(char *s, + int downcase) +{ + char *new_s; + String *z; + + if (downcase) { + new_s = zdowncase(s); + } else { + new_s = s; + } + + z = zhash[hash(new_s) % STRING_HASH_TABLE_SIZE]; + while (z != NULL) { + if (strcmp(new_s, z->string) == 0) + break; + z = z->next; + } + + if (downcase) + free(new_s); + + return z; +} + +int +comp_string(String *a, + String *b) +{ + if (a->hash_val > b->hash_val) + return 1; + if (a->hash_val < b->hash_val) + return -1; + return strcmp(a->string,b->string); +} + +void +print_string_table(FILE *f) +{ + String *p; + int i; + + for(i = 0; i < STRING_HASH_TABLE_SIZE; i++) { + p = zhash[i]; + while (p != (String *) NULL) { + fprintf(f,"[%d] %s\n",p->ref_count,p->string); + p = p->next; + } + } +} + +String * +dup_string(String *z) +{ + z->ref_count++; + return z; +} + diff --git a/server/zstring.h b/server/zstring.h new file mode 100644 index 0000000..127c95b --- /dev/null +++ b/server/zstring.h @@ -0,0 +1,33 @@ +/* + * Copyright (C) 1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file "mit-copyright.h". + * + * $Id$ + */ + +#include + +#ifndef __zstring_h +#define __zstring_h __FILE__ + +#define STRING_HASH_TABLE_SIZE 1024 + +#include + +typedef struct _String +{ + char *string; /* the string itself */ + int ref_count; /* for gc */ + unsigned long hash_val; /* hash value for this string */ + struct _String *next, *prev; /* for linking in hash table */ +} String; + +String *make_string(char *s, int downcase); +void free_string(String *z); +String *find_string(char *s, int downcase); +String *dup_string(String *z); +int comp_string(String *a, String *b); +void print_string_table(FILE *f); + +#endif /* __zstring_h */ + diff --git a/zephyr.pc.in b/zephyr.pc.in new file mode 100644 index 0000000..00782f4 --- /dev/null +++ b/zephyr.pc.in @@ -0,0 +1,12 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Description: Project Athena's notification service +Version: @PACKAGE_VERSION@ +Requires: +Libs: -L${libdir} -l@PACKAGE_NAME@ +Libs.private: @HESIOD_LIBS@ @KRB4_LIBS@ @KRB5_LIBS@ @REGEX_LIBS@ +Cflags: -I${includedir} diff --git a/zhm/Makefile.in b/zhm/Makefile.in new file mode 100644 index 0000000..77bf2c0 --- /dev/null +++ b/zhm/Makefile.in @@ -0,0 +1,68 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +top_builddir=.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +INSTALL=@INSTALL@ + +editman = sed \ + -e 's|@datadir[@]|${datadir}|g' \ + -e 's|@sysconfdir[@]|${sysconfdir}|g' \ + -e 's|@sbindir[@]|${sbindir}|g' \ + -e 's|@lsbindir[@]|${lsbindir}|g' + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -I${top_srcdir}/h -I${BUILDTOP}/h ${CPPFLAGS} +LDFLAGS=@LDFLAGS@ +HESIOD_LIBS=@HESIOD_LIBS@ + +OBJS= timer.o queue.o zhm.o zhm_client.o zhm_server.o + +all: zhm zhm.8 + +zhm: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBZEPHYR} ${HESIOD_LIBS} -lcom_err + +zhm.8: ${srcdir}/zhm.8.in Makefile + ${editman} ${srcdir}/$@.in > $@.tmp + mv $@.tmp $@ + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +check: + +install: zhm zhm.8 + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zhm ${DESTDIR}${lsbindir} + ${INSTALL} -m 644 zhm.8 ${DESTDIR}${mandir}/man8 + +clean: + ${LIBTOOL} --mode=clean rm -f zhm + rm -f ${OBJS} + rm -f zhm.8 + +${OBJS}: zhm.h timer.h ${top_srcdir}/h/internal.h ${top_srcdir}/h/sysdep.h +${OBJS}: ${BUILDTOP}/h/config.h ${BUILDTOP}/h/zephyr/zephyr.h +${OBJS}: ${BUILDTOP}/h/zephyr/zephyr_err.h +zhm.o: ${BUILDTOP}/h/zephyr_version.h + +.PHONY: all check install clean + diff --git a/zhm/queue.c b/zhm/queue.c new file mode 100644 index 0000000..333bf3e --- /dev/null +++ b/zhm/queue.c @@ -0,0 +1,264 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the hostmanager queueing routines. + * + * Created by: David C. Jedlinsky + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include "zhm.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_queue_c[] = "$Id$"; +#endif /* SABER */ +#endif /* lint */ + +typedef struct _Queue { + Timer *timer; + int retries; + ZNotice_t notice; + void *packet; + int len; + struct sockaddr_in reply; + struct _Queue *next, **prev_p; +} Queue; + +static Queue *hm_queue; +static int retransmits_enabled = 0; + +static Queue *find_notice_in_queue(ZNotice_t *notice); +static void queue_timeout(void *arg); + +int rexmit_times[] = { 2, 2, 4, 4, 8, -1 }; + +#ifdef DEBUG +static void dump_queue(void); +#endif + +void +init_queue(void) +{ + Queue *q; + + while (hm_queue) { + q = hm_queue; + if (q->timer) + timer_reset(q->timer); + free(q->packet); + hm_queue = q->next; + free(q); + } + + DPR("Queue initialized and flushed.\n"); +} + +Code_t +add_notice_to_queue(ZNotice_t *notice, + char *packet, + struct sockaddr_in *repl, + int len) +{ + Queue *entry; + + DPR("Adding notice to queue...\n"); + if (!find_notice_in_queue(notice)) { + entry = (Queue *) malloc(sizeof(Queue)); + if (entry == NULL) + return(ZERR_NONOTICE); + entry->retries = 0; + entry->packet = (char *) malloc(Z_MAXPKTLEN); + if (entry->packet == NULL) { + free(entry); + return(ZERR_NONOTICE); + } + memcpy(entry->packet, packet, Z_MAXPKTLEN); + entry->len = len; + if (ZParseNotice(entry->packet, len, &entry->notice) != ZERR_NONE) { + syslog(LOG_ERR, "ZParseNotice failed, but succeeded before"); + free(entry->packet); + } else { + entry->reply = *repl; + /*LIST_INSERT(&hm_queue, entry);*/ + + (entry)->next = *(&hm_queue); + if (*&hm_queue) ((*(&hm_queue))->prev_p = &(entry)->next); + (*&hm_queue) = (entry); + (entry)->prev_p = (&hm_queue); + + } + entry->timer = (retransmits_enabled) ? + timer_set_rel(rexmit_times[0], queue_timeout, entry) : NULL; + } + return(ZERR_NONE); +} + +Code_t +remove_notice_from_queue(ZNotice_t *notice, + ZNotice_Kind_t *kind, + struct sockaddr_in *repl) +{ + Queue *entry; + + DPR("Removing notice from queue...\n"); + entry = find_notice_in_queue(notice); + if (entry == NULL) + return(ZERR_NONOTICE); + + *kind = entry->notice.z_kind; + *repl = entry->reply; + if (entry->timer) + timer_reset(entry->timer); + free(entry->packet); + /*LIST_DELETE(entry);*/ + *(entry)->prev_p = (entry)->next; + if((entry)->next) ((entry)->next->prev_p = (entry)->prev_p); +#ifdef DEBUG + dump_queue(); +#endif /* DEBUG */ + free(entry); + return(ZERR_NONE); +} + +/* We have a server; transmit all of our packets. */ +void +retransmit_queue(struct sockaddr_in *sin) +{ + Queue *entry; + Code_t ret; + + DPR("Retransmitting queue to new server...\n"); + ret = ZSetDestAddr(sin); + if (ret != ZERR_NONE) { + Zperr (ret); + com_err("queue", ret, "setting destination"); + } + for (entry = hm_queue; entry; entry = entry->next) { + DPR("notice:\n"); + DPR2("\tz_kind: %d\n", entry->notice.z_kind); + DPR2("\tz_port: %u\n", ntohs(entry->notice.z_port)); + DPR2("\tz_class: %s\n", entry->notice.z_class); + DPR2("\tz_clss_inst: %s\n", entry->notice.z_class_inst); + DPR2("\tz_opcode: %s\n", entry->notice.z_opcode); + DPR2("\tz_sender: %s\n", entry->notice.z_sender); + DPR2("\tz_recip: %s\n", entry->notice.z_recipient); + ret = ZSendPacket(entry->packet, entry->len, 0); + if (ret != ZERR_NONE) { + Zperr(ret); + com_err("queue", ret, "sending raw notice"); + } + entry->timer = timer_set_rel(rexmit_times[0], queue_timeout, entry); + entry->retries = 0; + } + retransmits_enabled = 1; +} + +/* We lost our server; nuke all of our timers. */ +void +disable_queue_retransmits(void) +{ + Queue *entry; + + for (entry = hm_queue; entry; entry = entry->next) { + if (entry->timer) + timer_reset(entry->timer); + entry->timer = NULL; + } + retransmits_enabled = 0; +} + +#ifdef DEBUG +static void +dump_queue(void) +{ + Queue *entry; + char *mp; + int ml; + + DPR("Dumping queue...\n"); + if (!hm_queue) { + printf("Queue is empty.\n"); + return; + } + + for (entry = hm_queue; entry; entry = entry->next) { + printf("notice:\n"); + printf("\tz_kind: %d\n", entry->notice.z_kind); + printf("\tz_port: %u\n", ntohs(entry->notice.z_port)); + printf("\tz_class: %s\n", entry->notice.z_class); + printf("\tz_clss_inst: %s\n", entry->notice.z_class_inst); + printf("\tz_opcode: %s\n", entry->notice.z_opcode); + printf("\tz_sender: %s\n", entry->notice.z_sender); + printf("\tz_recip: %s\n", entry->notice.z_recipient); + printf("\tMessage:\n"); + mp = entry->notice.z_message; + for (ml = strlen(mp) + 1; ml <= entry->notice.z_message_len; ml++) { + printf("\t%s\n", mp); + mp += strlen(mp)+1; + ml += strlen(mp); + } + } +} +#endif /* DEBUG */ + +int +queue_len(void) +{ + int length = 0; + Queue *entry; + + for (entry = hm_queue; entry; entry = entry->next) + length++; + return length; +} + +static Queue * +find_notice_in_queue(ZNotice_t *notice) +{ + Queue *entry; + + for (entry = hm_queue; entry; entry = entry->next) { + if (ZCompareUID(&entry->notice.z_uid, ¬ice->z_uid)) + return entry; + } + return NULL; +} + +static void +queue_timeout(void *arg) +{ + Queue *entry = (Queue *) arg; + Code_t ret; + + entry->timer = NULL; + ret = ZSetDestAddr(&serv_sin); + if (ret != ZERR_NONE) { + Zperr(ret); + com_err("queue", ret, "setting destination"); + } + entry->retries++; + if (rexmit_times[entry->retries] == -1) { + new_server(NULL); + return; + } + DPR("Resending notice:\n"); + DPR2("\tz_kind: %d\n", entry->notice.z_kind); + DPR2("\tz_port: %u\n", ntohs(entry->notice.z_port)); + DPR2("\tz_class: %s\n", entry->notice.z_class); + DPR2("\tz_clss_inst: %s\n", entry->notice.z_class_inst); + DPR2("\tz_opcode: %s\n", entry->notice.z_opcode); + DPR2("\tz_sender: %s\n", entry->notice.z_sender); + DPR2("\tz_recip: %s\n", entry->notice.z_recipient); + ret = ZSendPacket(entry->packet, entry->len, 0); + if (ret != ZERR_NONE) { + Zperr(ret); + com_err("queue", ret, "sending raw notice"); + } + entry->timer = timer_set_rel(rexmit_times[entry->retries], queue_timeout, + entry); +} + diff --git a/zhm/timer.c b/zhm/timer.c new file mode 100644 index 0000000..296b47e --- /dev/null +++ b/zhm/timer.c @@ -0,0 +1,251 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains functions for managing multiple timeouts. + * + * Created by: John T. Kohl + * Derived from timer_manager_ by Ken Raeburn + * + * $Id$ + * + */ + +#include "internal.h" +#include "timer.h" + +#ifndef SABER +#ifndef lint +static const char rcsid[] = +"$Id$"; +#endif /* lint */ +#endif /* SABER */ + +/* + * timer_manager_ -- routines for handling timers in login_shell + * (and elsewhere) + * + * Copyright 1986 Student Information Processing Board, + * Massachusetts Institute of Technology + * + * written by Ken Raeburn + + Permission to use, copy, modify, and distribute this + software and its documentation for any purpose and without + fee is hereby granted, provided that the above copyright + notice appear in all copies and that both that copyright + notice and this permission notice appear in supporting + documentation, and that the name of M.I.T. and the Student + Information Processing Board not be used in + advertising or publicity pertaining to distribution of the + software without specific, written prior permission. + M.I.T. and the Student Information Processing Board + make no representations about the suitability of + this software for any purpose. It is provided "as is" + without express or implied warranty. + + */ + + +/* + * External functions: + * + * Timer *timer_set_rel (time_rel, proc, arg) + * long time_rel; + * void (*proc)(); + * void *arg; + * Timer *timer_set_abs (time_abs, proc, arg) + * long time_abs; + * void (*proc)(); + * void *arg; + * + * void timer_reset(tmr) + * Timer *tmr; + * + * void timer_process() + * + */ + +/* DELTA is just an offset to keep the size a bit less than a power + * of two. It's measured in pointers, so it's 32 bytes on most + * systems. */ +#define DELTA 8 +#define INITIAL_HEAP_SIZE (1024 - DELTA) + +/* We have three operations which we need to be able to perform + * quickly: adding a timer, deleting a timer given a pointer to + * it, and determining which timer will be the next to go off. A + * heap is an ideal data structure for these purposes, so we use + * one. The heap is an array of pointers to timers, and each timer + * knows the position of its pointer in the heap. + * + * Okay, what is the heap, exactly? It's a data structure, + * represented as an array, with the invariant condition that + * the timeout of heap[i] is less than or equal to the timeout of + * heap[i * 2 + 1] and heap[i * 2 + 2] (assuming i * 2 + 1 and + * i * 2 + 2 are valid * indices). An obvious consequence of this + * is that heap[0] has the lowest timer value, so finding the first + * timer to go off is easy. We say that an index i has "children" + * i * 2 + 1 and i * 2 + 1, and the "parent" (i - 1) / 2. + * + * To add a timer to the heap, we start by adding it to the end, and + * then keep swapping it with its parent until it has a parent with + * a timer value less than its value. With a little bit of thought, + * you can see that this preserves the heap property on all indices + * of the array. + * + * To delete a timer at position i from the heap, we discard it and + * fill in its position with the last timer in the heap. In order + * to restore the heap, we have to consider two cases: the timer + * value at i is less than that of its parent, or the timer value at + * i is greater than that of one of its children. In the first case, + * we propagate the timer at i up the tree, swapping it with its + * parent, until the heap is restored; in the second case, we + * propagate the timer down the tree, swapping it with its least + * child, until the heap is restored. */ + +/* In order to ensure that the back pointers from timers are consistent + * with the heap pointers, all heap assignments should be done with the + * HEAP_ASSIGN() macro, which sets the back pointer and updates the + * heap at the same time. */ +#define PARENT(i) (((i) - 1) / 2) +#define CHILD1(i) ((i) * 2 + 1) +#define CHILD2(i) ((i) * 2 + 2) +#define TIME(i) (heap[i]->abstime) +#define HEAP_ASSIGN(pos, tmr) ((heap[pos] = (tmr))->heap_pos = (pos)) + +static Timer **heap; +static int num_timers = 0; +static int heap_size = 0; + +static void timer_botch (void*); +static Timer *add_timer (Timer *); + +Timer * +timer_set_rel(long time_rel, + void (*proc)(void *), + void *arg) +{ + Timer *new_t; + + new_t = (Timer *) malloc(sizeof(*new_t)); + if (new_t == NULL) + return(NULL); + new_t->abstime = time_rel + time(NULL); + new_t->func = proc; + new_t->arg = arg; + return add_timer(new_t); +} + +void +timer_reset(Timer *tmr) +{ + int pos, min; + + /* Free the timer, saving its heap position. */ + pos = tmr->heap_pos; + free(tmr); + + if (pos != num_timers - 1) { + /* Replace the timer with the last timer in the heap and + * restore the heap, propagating the timer either up or + * down, depending on which way it violates the heap + * property to insert the last timer in place of the + * deleted timer. */ + if (pos > 0 && TIME(num_timers - 1) < TIME(PARENT(pos))) { + do { + HEAP_ASSIGN(pos, heap[PARENT(pos)]); + pos = PARENT(pos); + } while (pos > 0 && TIME(num_timers - 1) < TIME(PARENT(pos))); + HEAP_ASSIGN(pos, heap[num_timers - 1]); + } else { + while (CHILD2(pos) < num_timers) { + min = num_timers - 1; + if (TIME(CHILD1(pos)) < TIME(min)) + min = CHILD1(pos); + if (TIME(CHILD2(pos)) < TIME(min)) + min = CHILD2(pos); + HEAP_ASSIGN(pos, heap[min]); + pos = min; + } + if (pos != num_timers - 1) + HEAP_ASSIGN(pos, heap[num_timers - 1]); + } + } + num_timers--; +} + + +#define set_timeval(t,s) ((t).tv_sec=(s),(t).tv_usec=0,(t)) + +static Timer * +add_timer(Timer *new) +{ + int pos; + + /* Create or resize the heap as necessary. */ + if (heap_size == 0) { + heap_size = INITIAL_HEAP_SIZE; + heap = (Timer **) malloc(heap_size * sizeof(Timer *)); + } else if (num_timers >= heap_size) { + heap_size = heap_size * 2 + DELTA; + heap = (Timer **) realloc(heap, heap_size * sizeof(Timer *)); + } + if (!heap) { + free(new); + return NULL; + } + + /* Insert the Timer *into the heap. */ + pos = num_timers; + while (pos > 0 && new->abstime < TIME(PARENT(pos))) { + HEAP_ASSIGN(pos, heap[PARENT(pos)]); + pos = PARENT(pos); + } + HEAP_ASSIGN(pos, new); + num_timers++; + + return new; +} + +void +timer_process(void) +{ + Timer *t; + timer_proc func; + void *arg; + + if (num_timers == 0 || heap[0]->abstime > time(NULL)) + return; + + /* Remove the first timer from the heap, remembering its + * function and argument. */ + t = heap[0]; + func = t->func; + arg = t->arg; + t->func = timer_botch; + t->arg = NULL; + timer_reset(t); + + /* Run the function. */ + func(arg); +} + +struct timeval * +timer_timeout(struct timeval *tvbuf) +{ + if (num_timers > 0) { + tvbuf->tv_sec = heap[0]->abstime - time(NULL); + if (tvbuf->tv_sec < 0) + tvbuf->tv_sec = 0; + tvbuf->tv_usec = 0; + return tvbuf; + } else { + return NULL; + } +} + +static void +timer_botch(void *arg) +{ + syslog(LOG_CRIT, "timer botch\n"); + abort(); +} + diff --git a/zhm/timer.h b/zhm/timer.h new file mode 100644 index 0000000..77595be --- /dev/null +++ b/zhm/timer.h @@ -0,0 +1,54 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains definitions used by timer.c + * + * Created by: John T. Kohl + * Derived from timer_manager_.h by Ken Raeburn + * + * $Id$ + * + */ + +#ifndef __TIMER_H + +/* + * timer_manager_ -- routines for handling timers in login_shell + * (and elsewhere) + * + * Copyright 1986 Student Information Processing Board, + * Massachusetts Institute of Technology + * + * written by Ken Raeburn + +Permission to use, copy, modify, and distribute this +software and its documentation for any purpose and without +fee is hereby granted, provided that the above copyright +notice appear in all copies and that both that copyright +notice and this permission notice appear in supporting +documentation, and that the name of M.I.T. and the Student +Information Processing Board not be used in +advertising or publicity pertaining to distribution of the +software without specific, written prior permission. +M.I.T. and the Student Information Processing Board +make no representations about the suitability of +this software for any purpose. It is provided "as is" +without express or implied warranty. + + */ + +typedef void (*timer_proc) __P((void *)); + +typedef struct _Timer { + int heap_pos; /* Position in timer heap */ + long abstime; + timer_proc func; + void *arg; +} Timer; + +Timer *timer_set_rel __P((long, timer_proc, void *)); +Timer *timer_set_abs __P((long, timer_proc, void *)); +void timer_reset __P((Timer *)); +void timer_process __P((void)); +struct timeval *timer_timeout __P((struct timeval *tvbuf)); + +#endif /* __TIMER_H */ + diff --git a/zhm/zhm.8.in b/zhm/zhm.8.in new file mode 100644 index 0000000..15961dd --- /dev/null +++ b/zhm/zhm.8.in @@ -0,0 +1,106 @@ +.\" $Id$ +.\" +.\" Copyright 1987, 1988 by the Massachusetts Institute of Technology +.\" All rights reserved. The file /usr/include/zephyr/mit-copyright.h +.\" specifies the terms and conditions for redistribution. +.\" +.\" +.TH ZHM 8 "November 1, 1988" "MIT Project Athena" +.ds ]W MIT Project Athena +.SH NAME +zhm \- Zephyr HostManager +.SH SYNOPSIS +.B @lsbindir@/zhm +[ +.BI -d +] [ +.BI -n +] [ +.BI -h +] [ +.BI -r +] [ +.BI -i +] [ +.BI -f +] [ +.BI -N +] [ +.BI server +.BI ... +] +.SH DESCRIPTION +.I Zhm +is the link between a client machine and the zephyr server. All +notices sent from programs on the client are funneled through +.I zhm. +This allows all client programs to be much simpler in function, since +the HostManager is responsible for handling errors, retransmitting +lost notices, and holding all notices until they are acknowledged. +.PP +The +.I -d +option turns on debugging mode, and sends its information to syslog +LOG_DAEMON messages. +.PP +The +.I -n +option causes zhm to not attempt to put itself in the background. +.PP +The +.I -h +option causes +.I zhm +to send a shutdown message and exit upon delivery of a SIGHUP signal. +The normal action on SIGHUP is to send a flush notice to the zephyr server. +.PP +The +.I -r +option causes +.I zhm +to send a boot notice to the server and exit when the notice is acknowledged. +.PP +The +.I -i +option indicates that +.I zhm +is being started by +.I inetd(8). +When this option is specified, +.I zhm +assumes that file descriptor zero (0) is bound to the UDP datagram port +designated for hostmanager use. In this mode, SIGHUP is handled as if the +.I -h +option were specified. +.PP +The +.I -f +option disables the "flush" operation which allows any client to flush +all subscriptions for the host. +.PP +The +.I -N +option supresses the initial "boot" message that flushes all subscriptions +for the host, which is useful if you're restarting zhm on a host that +people are using. +.PP +The optional +.I server +arguments are used to replace the set of server names supplied by +the +.I hesiod(3) +name server. +.SH SEE ALSO +zephyr(1), zephyrd(8), inetd(8) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification +Service' +.SH AUTHOR +.PP +David C. Jedlinsky, MIT Project Athena +.SH RESTRICTIONS +Copyright (c) 1987,1988 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/zhm/zhm.c b/zhm/zhm.c new file mode 100644 index 0000000..ec4696b --- /dev/null +++ b/zhm/zhm.c @@ -0,0 +1,623 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the hostmanager client program. + * + * Created by: David C. Jedlinsky + * + * $Id$ + * + * Copyright (c) 1987,1991 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include "zhm.h" +#include + +static const char rcsid_hm_c[] = "$Id$"; + +#ifdef HAVE_HESIOD +int use_hesiod = 0; +#endif + +#ifdef macII +#define srandom srand48 +#endif + +#define PIDDIR "/var/run/" + +int hmdebug, rebootflag, noflushflag, errflg, dieflag, inetd, oldpid, nofork; +int no_server = 1, nservchang, nserv, nclt; +int booting = 1, timeout_type, deactivated = 1; +int started = 0; +long starttime; +u_short cli_port; +struct sockaddr_in cli_sin, serv_sin, from; +int numserv; +char **serv_list = NULL; +char prim_serv[NS_MAXDNAME], cur_serv[NS_MAXDNAME]; +char *zcluster; +int deactivating = 0; +int terminating = 0; +struct hostent *hp; +char hostname[NS_MAXDNAME], loopback[4]; +char PidFile[128]; + +static RETSIGTYPE deactivate(int); +static RETSIGTYPE terminate(int); +static void choose_server(void); +static void init_hm(void); +#ifndef DEBUG +static void detach(void); +#endif +static void send_stats(ZNotice_t *, struct sockaddr_in *); +static char *strsave(const char *); + +static RETSIGTYPE +deactivate(int ignored) +{ + deactivating = 1; +} + +static RETSIGTYPE +terminate(int ignored) +{ + terminating = 1; +} + +int +main(int argc, + char *argv[]) +{ + ZNotice_t notice; + ZPacket_t packet; + Code_t ret; + int opt, pak_len, fd, count; + fd_set readers; + struct timeval tv; + + sprintf(PidFile, "%szhm.pid", PIDDIR); + + if (gethostname(hostname, sizeof(hostname)) < 0) { + printf("Can't find my hostname?!\n"); + exit(-1); + } + prim_serv[0] = '\0'; + while ((opt = getopt(argc, argv, "drhinfN")) != EOF) + switch(opt) { + case 'd': + hmdebug = 1; + break; + case 'h': + /* Die on SIGHUP */ + dieflag = 1; + break; + case 'r': + /* Reboot host -- send boot notice -- and exit */ + rebootflag= 1; + break; + case 'i': + /* inetd operation: don't do bind ourselves, fd 0 is + already connected to a socket. Implies -h */ + inetd = 1; + dieflag = 1; + break; + case 'n': + nofork = 1; + break; + case 'f': + noflushflag = 1; + break; + case 'N': + booting = 0; + break; + case '?': + default: + errflg++; + break; + } + if (errflg) { + fprintf(stderr, "Usage: %s [-d] [-h] [-r] [-n] [-f] [server]\n", + argv[0]); + exit(2); + } + + numserv = 0; + + /* Override server argument? */ + if (optind < argc) { + if ((hp = gethostbyname(argv[optind++])) == NULL) { + printf("Unknown server name: %s\n", argv[optind-1]); + } else { + strncpy(prim_serv, hp->h_name, sizeof(prim_serv)); + prim_serv[sizeof(prim_serv) - 1] = '\0'; + } + + /* argc-optind is the # of other servers on the command line */ + serv_list = (char **) malloc((argc - optind + 2) * sizeof(char *)); + if (serv_list == NULL) { + printf("Out of memory.\n"); + exit(-5); + } + serv_list[numserv++] = prim_serv; + for (; optind < argc; optind++) { + if ((hp = gethostbyname(argv[optind])) == NULL) { + printf("Unknown server name '%s', ignoring\n", argv[optind]); + continue; + } + serv_list[numserv++] = strsave(hp->h_name); + } + serv_list[numserv] = NULL; + } +#ifdef HAVE_HESIOD + else + use_hesiod = 1; +#endif + + choose_server(); + if (*prim_serv == '\0') { + printf("No valid primary server found, exiting.\n"); + exit(ZERR_SERVNAK); + } + init_hm(); + started = 1; + + DPR2("zephyr server port: %u\n", ntohs(serv_sin.sin_port)); + DPR2("zephyr client port: %u\n", ntohs(cli_port)); + + /* Main loop */ + for (;;) { + /* Wait for incoming packets or queue timeouts. */ + DPR("Waiting for a packet..."); + fd = ZGetFD(); + FD_ZERO(&readers); + FD_SET(fd, &readers); + count = select(fd + 1, &readers, NULL, NULL, timer_timeout(&tv)); + if (count == -1 && errno != EINTR) { + syslog(LOG_CRIT, "select() failed: %m"); + die_gracefully(); + } + + if (terminating) + die_gracefully(); + + if (deactivating) { + deactivating = 0; + if (dieflag) { + die_gracefully(); + } else { + choose_server(); + send_flush_notice(HM_FLUSH); + deactivated = 1; + } + } + + timer_process(); + + if (count > 0) { + ret = ZReceivePacket(packet, &pak_len, &from); + if ((ret != ZERR_NONE) && (ret != EINTR)){ + Zperr(ret); + com_err("hm", ret, "receiving notice"); + } else if (ret != EINTR) { + /* Where did it come from? */ + if ((ret = ZParseNotice(packet, pak_len, ¬ice)) + != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "parsing notice"); + } else { + DPR("Got a packet.\n"); + DPR("notice:\n"); + DPR2("\tz_kind: %d\n", notice.z_kind); + DPR2("\tz_port: %u\n", ntohs(notice.z_port)); + DPR2("\tz_class: %s\n", notice.z_class); + DPR2("\tz_class_inst: %s\n", notice.z_class_inst); + DPR2("\tz_opcode: %s\n", notice.z_opcode); + DPR2("\tz_sender: %s\n", notice.z_sender); + DPR2("\tz_recip: %s\n", notice.z_recipient); + DPR2("\tz_def_format: %s\n", notice.z_default_format); + DPR2("\tz_message: %s\n", notice.z_message); + if (memcmp(loopback, &from.sin_addr, 4) && + ((notice.z_kind == SERVACK) || + (notice.z_kind == SERVNAK) || + (notice.z_kind == HMCTL))) { + server_manager(¬ice); + } else { + if (!memcmp(loopback, &from.sin_addr, 4) && + ((notice.z_kind == UNSAFE) || + (notice.z_kind == UNACKED) || + (notice.z_kind == ACKED) || + (notice.z_kind == HMCTL))) { + /* Client program... */ + if (deactivated) { + send_boot_notice(HM_BOOT); + deactivated = 0; + } + transmission_tower(¬ice, packet, pak_len); + DPR2("Pending = %d\n", ZPending()); + } else { + if (notice.z_kind == STAT) { + send_stats(¬ice, &from); + } else { + syslog(LOG_INFO, + "Unknown notice type: %d", + notice.z_kind); + } + } + } + } + } + } + } +} + +static void +choose_server(void) +{ +#ifdef HAVE_HESIOD + int i = 0; + char **clust_info, **cpp; + + if (use_hesiod) { + + /* Free up any previously used resources */ + if (prim_serv[0]) + i = 1; + while (i < numserv) + free(serv_list[i++]); + if (serv_list) + free(serv_list); + + numserv = 0; + prim_serv[0] = '\0'; + + if ((clust_info = hes_resolve(hostname, "CLUSTER")) == NULL) { + zcluster = NULL; + } else { + for (cpp = clust_info; *cpp; cpp++) { + /* Remove the following check once we have changed over to + * new Hesiod format (i.e. ZCLUSTER.sloc lookup, no primary + * server + */ + if (!strncasecmp("ZEPHYR", *cpp, 6)) { + register char *c; + + if ((c = strchr(*cpp, ' ')) == 0) { + printf("Hesiod error getting primary server info.\n"); + } else { + strncpy(prim_serv, c+1, sizeof(prim_serv)); + prim_serv[sizeof(prim_serv) - 1] = '\0'; + } + break; + } + if (!strncasecmp("ZCLUSTER", *cpp, 9)) { + register char *c; + + if ((c = strchr(*cpp, ' ')) == 0) { + printf("Hesiod error getting zcluster info.\n"); + } else { + if ((zcluster = malloc((unsigned)(strlen(c+1)+1))) + != NULL) { + strcpy(zcluster, c+1); + } else { + printf("Out of memory.\n"); + exit(-5); + } + } + break; + } + } + for (cpp = clust_info; *cpp; cpp++) + free(*cpp); + } + + if (zcluster == NULL) { + if ((zcluster = malloc((unsigned)(strlen("zephyr")+1))) != NULL) + strcpy(zcluster, "zephyr"); + else { + printf("Out of memory.\n"); + exit(-5); + } + } + while ((serv_list = hes_resolve(zcluster, "sloc")) == (char **)NULL) { + syslog(LOG_ERR, "No servers or no hesiod"); + if (!started) + return; /* do not hang forever*/ + /* wait a bit, and try again */ + sleep(30); + } + cpp = (char **) malloc(2 * sizeof(char *)); + if (cpp == NULL) { + printf("Out of memory.\n"); + exit(-5); + } + if (prim_serv[0]) + cpp[numserv++] = prim_serv; + for (i = 0; serv_list[i]; i++) { + /* copy in non-duplicates */ + /* assume the names returned in the sloc are full domain names */ + if (!prim_serv[0] || strcasecmp(prim_serv, serv_list[i])) { + cpp = (char **) realloc(cpp, (numserv+2) * sizeof(char *)); + if (cpp == NULL) { + printf("Out of memory.\n"); + exit(-5); + } + cpp[numserv++] = strsave(serv_list[i]); + } + } + for (i = 0; serv_list[i]; i++) + free(serv_list[i]); + cpp[numserv] = NULL; + serv_list = cpp; + } +#endif + + if (!prim_serv[0] && numserv) { + srandom(time(NULL)); + strncpy(prim_serv, serv_list[random() % numserv], sizeof(prim_serv)); + prim_serv[sizeof(prim_serv) - 1] = '\0'; + } +} + +static void +init_hm(void) +{ + struct servent *sp; + Code_t ret; +#ifndef DEBUG + FILE *fp; +#endif +#ifdef _POSIX_VERSION + struct sigaction sa; +#endif + + starttime = time((time_t *)0); + OPENLOG("hm", LOG_PID, LOG_DAEMON); + + ZSetServerState(1); /* Aargh!!! */ + if ((ret = ZInitialize()) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "initializing"); + closelog(); + exit(-1); + } + init_queue(); + + if (*prim_serv == '\0') { + strncpy(prim_serv, *serv_list, sizeof(prim_serv)); + prim_serv[sizeof(prim_serv) - 1] = '\0'; + } + + loopback[0] = 127; + loopback[1] = 0; + loopback[2] = 0; + loopback[3] = 1; + + if (inetd) { + ZSetFD(0); /* fd 0 is on the socket, thanks to inetd */ + } else { + /* Open client socket, for receiving client and server notices */ + sp = getservbyname(HM_SVCNAME, "udp"); + cli_port = (sp) ? sp->s_port : HM_SVC_FALLBACK; + + if ((ret = ZOpenPort(&cli_port)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "opening port"); + exit(ret); + } + } + cli_sin = ZGetDestAddr(); + + sp = getservbyname(SERVER_SVCNAME, "udp"); + memset(&serv_sin, 0, sizeof(struct sockaddr_in)); + serv_sin.sin_port = (sp) ? sp->s_port : SERVER_SVC_FALLBACK; + +#ifndef DEBUG + if (!inetd && !nofork) + detach(); + + /* Write pid to file */ + fp = fopen(PidFile, "w"); + if (fp != NULL) { + fprintf(fp, "%d\n", getpid()); + fclose(fp); + } +#endif /* DEBUG */ + + if (hmdebug) { + syslog(LOG_INFO, "Debugging on."); + } + + /* Set up communications with server */ + /* target is SERVER_SVCNAME port on server machine */ + + serv_sin.sin_family = AF_INET; + + /* who to talk to */ + if ((hp = gethostbyname(prim_serv)) == NULL) { + DPR("gethostbyname failed\n"); + find_next_server(NULL); + } else { + DPR2("Server = %s\n", prim_serv); + strncpy(cur_serv, prim_serv, sizeof(cur_serv)); + cur_serv[sizeof(cur_serv) - 1] = '\0'; + memcpy(&serv_sin.sin_addr, hp->h_addr, 4); + } + + if (booting) + send_boot_notice(HM_BOOT); + else + send_boot_notice(HM_ATTACH); + deactivated = 0; + +#ifdef _POSIX_VERSION + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + sa.sa_handler = deactivate; + sigaction(SIGHUP, &sa, (struct sigaction *)0); + sa.sa_handler = terminate; + sigaction(SIGTERM, &sa, (struct sigaction *)0); +#else + signal(SIGHUP, deactivate); + signal(SIGTERM, terminate); +#endif +} + +#ifndef DEBUG +static void +detach(void) +{ + /* detach from terminal and fork. */ + register int i, x = ZGetFD(); + register long size; + + i = fork(); + if (i) { + if (i < 0) + perror("fork"); + exit(0); + } +#ifdef _POSIX_VERSION + size = sysconf(_SC_OPEN_MAX); +#else + size = getdtablesize(); +#endif + for (i = 0; i < size; i++) + if (i != x) + close(i); + + if ((i = open("/dev/tty", O_RDWR, 0666)) < 0) + ; /* Can't open tty, but don't flame about it. */ + else { +#ifdef TIOCNOTTY + /* Necessary for old non-POSIX systems which automatically assign + * an opened tty as the controlling terminal of a process which + * doesn't already have one. POSIX systems won't include + * (see ../h/sysdep.h); if TIOCNOTTY is defined anyway, + * this is unnecessary but won't hurt. */ + ioctl(i, TIOCNOTTY, NULL); +#endif + close(i); + } +#ifdef _POSIX_VERSION + setsid(); +#endif +} +#endif + +static char version[BUFSIZ]; + +static char * +stats_malloc(size_t size) +{ + char *p = malloc(size); + + if (p == NULL) { + printf("Out of memory.\n"); /*XXXXXXXXXXX ? */ + exit(-5); + } + + return p; +} + +static void +send_stats(ZNotice_t *notice, + struct sockaddr_in *sin) +{ + ZNotice_t newnotice; + Code_t ret; + char *bfr; + char *list[20]; + int len, i, nitems = 10; + unsigned long size; + extern int Zauthtype; /* XXX this may be changing in the future */ + + newnotice = *notice; + + if ((ret = ZSetDestAddr(sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + newnotice.z_kind = HMACK; + + list[0] = stats_malloc(NS_MAXDNAME); + strcpy(list[0], cur_serv); + + list[1] = stats_malloc(64); + sprintf(list[1], "%d", queue_len()); + + list[2] = stats_malloc(64); + sprintf(list[2], "%d", nclt); + + list[3] = stats_malloc(64); + sprintf(list[3], "%d", nserv); + + list[4] = stats_malloc(64); + sprintf(list[4], "%d", nservchang); + + list[5] = stats_malloc(256); + snprintf(list[5], 256, "%s (%d)", ZEPHYR_VERSION_STRING, Zauthtype); + list[5][255] = '\0'; + + list[6] = stats_malloc(64); + if (no_server) + sprintf(list[6], "yes"); + else + sprintf(list[6], "no"); + + list[7] = stats_malloc(64); + sprintf(list[7], "%ld", time((time_t *)0) - starttime); + +#ifdef adjust_size + size = (unsigned long)sbrk(0); + adjust_size (size); +#else + size = -1; +#endif + list[8] = stats_malloc(64); + sprintf(list[8], "%ld", size); + + list[9] = stats_malloc(32); + strncpy(list[9], MACHINE_TYPE, 32); + list[9][31] = '\0'; + + /* Since ZFormatRaw* won't change the version number on notices, + we need to set the version number explicitly. This code is taken + from Zinternal.c, function Z_FormatHeader */ + if (!*version) + sprintf(version, "%s%d.%d", ZVERSIONHDR, ZVERSIONMAJOR, + ZVERSIONMINOR); + newnotice.z_version = version; + + if ((ret = ZFormatRawNoticeList(&newnotice, list, nitems, &bfr, + &len)) != ZERR_NONE) { + syslog(LOG_INFO, "Couldn't format stats packet"); + } else { + if ((ret = ZSendPacket(bfr, len, 0)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending stats"); + } + } + free(bfr); + for(i=0;i +#include +#include +#include +#include +#include +#include "timer.h" + +/* These macros are for insertion into and deletion from a singly-linked list + * with back pointers to the previous element's next pointer. In order to + * make these macros act like expressions, they use the comma operator for + * sequenced evaluations of assignment, and "a && b" for "evaluate assignment + * b if expression a is true". */ +#define LIST_INSERT(head, elem) \ + ((elem)->next = *(head), \ + (*head) && ((*(head))->prev_p = &(elem)->next), \ + (*head) = (elem), (elem)->prev_p = (head)) +#define LIST_DELETE(elem) \ + (*(elem)->prev_p = (elem)->next, \ + (elem)->next && ((elem)->next->prev_p = (elem)->prev_p)) + +#ifdef DEBUG +#define DPR(a) fprintf(stderr, a); fflush(stderr) +#define DPR2(a,b) fprintf(stderr, a, b); fflush(stderr) +#define Zperr(e) fprintf(stderr, "Error = %d\n", e) +#else +#define DPR(a) +#define DPR2(a,b) +#define Zperr(e) +#endif + +#define BOOTING 1 +#define NOTICES 2 + +/* main.c */ +void die_gracefully(void); + +/* zhm_client.c */ +void transmission_tower(ZNotice_t *, char *, int); +Code_t send_outgoing(ZNotice_t *); + +/* queue.c */ +void init_queue(void); +Code_t add_notice_to_queue(ZNotice_t *, char *, struct sockaddr_in *, + int); +Code_t remove_notice_from_queue(ZNotice_t *, ZNotice_Kind_t *, + struct sockaddr_in *); +void retransmit_queue(struct sockaddr_in *); +void disable_queue_retransmits(void); +int queue_len(void); + +/* zhm.c */ +extern void new_server(char *sugg_serv); +extern void send_boot_notice(char *); +extern void send_flush_notice(char *); + +/* zhm_server.c */ +extern void find_next_server(char *); +extern void server_manager(ZNotice_t *); + +extern u_short cli_port; +extern char **serv_list; +extern char cur_serv[], prim_serv[]; +extern struct sockaddr_in cli_sin, serv_sin, from; +extern int no_server, deactivated, noflushflag, rebootflag; +extern int timeout_type, hmdebug, nservchang, booting, nclt, nserv, numserv; +extern int rexmit_times[]; + +#ifdef HAVE_ETEXT +extern int etext; +#define adjust_size(size) size -= (unsigned long) &etext; +#else +/* Pick a var that tends to be near the start of data section. */ +extern char **environ; +#define adjust_size(size) size -= (uintptr_t) &environ +#endif + +#endif diff --git a/zhm/zhm_client.c b/zhm/zhm_client.c new file mode 100644 index 0000000..36c81ed --- /dev/null +++ b/zhm/zhm_client.c @@ -0,0 +1,101 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the hostmanager <--> client interaction routines. + * + * Created by: David C. Jedlinsky + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include "zhm.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_hm_client_c[] = "$Id$"; +#endif /* SABER */ +#endif /* lint */ + +void transmission_tower(ZNotice_t *notice, + char *packet, + int pak_len) +{ + ZNotice_t gack; + Code_t ret; + struct sockaddr_in gsin; + + nclt++; + if (notice->z_kind == HMCTL) { + if (!strcmp(notice->z_opcode, CLIENT_FLUSH)) { + if (noflushflag) + syslog(LOG_INFO, "Client requested hm flush (disabled)."); + else { + send_flush_notice(HM_FLUSH); + deactivated = 1; + } + } else if (!strcmp(notice->z_opcode, CLIENT_NEW_SERVER)) { + new_server((char *)NULL); + } else { + syslog (LOG_INFO, "Bad control notice from client."); + } + return; + } else { + if (notice->z_kind != UNSAFE) { + gack = *notice; + gack.z_kind = HMACK; + gack.z_message_len = 0; + gack.z_multinotice = ""; + gsin = cli_sin; + gsin.sin_port = from.sin_port; + if (gack.z_port == 0) + gack.z_port = from.sin_port; + DPR2 ("Client Port = %u\n", ntohs(gack.z_port)); + notice->z_port = gack.z_port; + if ((ret = ZSetDestAddr(&gsin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + /* Bounce ACK to library */ + if ((ret = send_outgoing(&gack)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending raw notice"); + } + } + } + if (!no_server) { + DPR2 ("Server Port = %u\n", ntohs(serv_sin.sin_port)); + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = ZSendPacket(packet, pak_len, 0)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "while sending raw notice"); + } + } + if (add_notice_to_queue(notice, packet, &gsin, pak_len) != ZERR_NONE) + syslog(LOG_INFO, "Hey! Insufficient memory to add notice to queue!"); +} + +Code_t +send_outgoing(ZNotice_t *notice) +{ + Code_t retval; + char *packet; + int length; + + if (!(packet = (char *) malloc((unsigned)sizeof(ZPacket_t)))) + return(ENOMEM); + + if ((retval = ZFormatSmallRawNotice(notice, packet, &length)) + != ZERR_NONE) { + free(packet); + return(retval); + } + retval = ZSendPacket(packet, length, 0); + free(packet); + return(retval); +} + diff --git a/zhm/zhm_server.c b/zhm/zhm_server.c new file mode 100644 index 0000000..4c58428 --- /dev/null +++ b/zhm/zhm_server.c @@ -0,0 +1,313 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It contains the hostmanager <--> server interaction routines. + * + * Created by: David C. Jedlinsky + * + * $Id$ + * + * Copyright (c) 1987 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include "zhm.h" + +#ifndef lint +#ifndef SABER +static const char rcsid_hm_server_c[] = "$Id$"; +#endif /* SABER */ +#endif /* lint */ + +static void boot_timeout __P((void *)); +static int get_serv_timeout __P((void)); + +static Timer *boot_timer = NULL; +static int serv_rexmit_times[] = { 5, 10, 20, 40 }; +static int serv_timeouts = 0; + +int serv_loop = 0; + +void hm_control(ZNotice_t *); +void send_back(ZNotice_t *); + +/* Argument is whether we are actually booting, or just attaching + * after a server switch */ +void +send_boot_notice(char *op) +{ + ZNotice_t notice; + Code_t ret; + + memset(¬ice, 0, sizeof(ZNotice_t)); + /* Set up server notice */ + notice.z_kind = HMCTL; + notice.z_port = cli_port; + notice.z_class = ZEPHYR_CTL_CLASS; + notice.z_class_inst = ZEPHYR_CTL_HM; + notice.z_opcode = op; + notice.z_sender = "HM"; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_num_other_fields = 0; + notice.z_message_len = 0; + + /* Notify server that this host is here */ + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending startup notice"); + } + boot_timer = timer_set_rel(get_serv_timeout(), boot_timeout, NULL); +} + +/* Argument is whether we are detaching or really going down */ +void +send_flush_notice(char *op) +{ + ZNotice_t notice; + Code_t ret; + + memset(¬ice, 0, sizeof(ZNotice_t)); + /* Set up server notice */ + notice.z_kind = HMCTL; + notice.z_port = cli_port; + notice.z_class = ZEPHYR_CTL_CLASS; + notice.z_class_inst = ZEPHYR_CTL_HM; + notice.z_opcode = op; + notice.z_sender = "HM"; + notice.z_recipient = ""; + notice.z_default_format = ""; + notice.z_num_other_fields = 0; + notice.z_message_len = 0; + + /* Tell server to lose us */ + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = ZSendNotice(¬ice, ZNOAUTH)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending flush notice"); + } +} + +void +find_next_server(char *sugg_serv) +{ + struct hostent *hp = 0; + int done = 0; + char **parse = serv_list; + char *new_serv; + + if (sugg_serv) { + do { + if (!strcmp(*parse, sugg_serv)) + done = 1; + } while ((done == 0) && (*++parse != NULL)); + } + if (done) { + if ((hp = gethostbyname(sugg_serv)) != NULL) { + DPR2 ("Server = %s\n", sugg_serv); + (void)strncpy(cur_serv, sugg_serv, NS_MAXDNAME); + cur_serv[NS_MAXDNAME - 1] = '\0'; + if (hmdebug) + syslog(LOG_DEBUG, "Suggested server: %s\n", sugg_serv); + } else { + done = 0; + } + } + while (!done) { + if ((++serv_loop > 3) && (strcmp(cur_serv, prim_serv))) { + serv_loop = 0; + if ((hp = gethostbyname(prim_serv)) != NULL) { + DPR2 ("Server = %s\n", prim_serv); + (void)strncpy(cur_serv, prim_serv, NS_MAXDNAME); + cur_serv[NS_MAXDNAME - 1] = '\0'; + done = 1; + break; + } + } + + switch (numserv) { + case 1: + if ((hp = gethostbyname(*serv_list)) != NULL) { + DPR2 ("Server = %s\n", *serv_list); + (void)strncpy(cur_serv, *serv_list, NS_MAXDNAME); + cur_serv[NS_MAXDNAME - 1] = '\0'; + done = 1; + break; + } + /* fall through */ + case 0: + if (rebootflag) + die_gracefully(); + else + sleep(1); + break; + default: + do { + new_serv = serv_list[random() % numserv]; + } while (!strcmp(new_serv, cur_serv)); + + if ((hp = gethostbyname(new_serv)) != NULL) { + DPR2 ("Server = %s\n", new_serv); + (void)strncpy(cur_serv, new_serv, NS_MAXDNAME); + cur_serv[NS_MAXDNAME - 1] = '\0'; + done = 1; + } else + sleep(1); + + break; + } + } + (void) memcpy((char *)&serv_sin.sin_addr, hp->h_addr, 4); + nservchang++; +} + +void +server_manager(ZNotice_t *notice) +{ + if (memcmp((char *)&serv_sin.sin_addr, (char *)&from.sin_addr, 4) || + (serv_sin.sin_port != from.sin_port)) { + syslog (LOG_INFO, "Bad notice from port %u.", notice->z_port); + } else { + /* This is our server, handle the notice */ + booting = 0; + serv_timeouts = 0; + if (boot_timer) { + timer_reset(boot_timer); + boot_timer = NULL; + } + DPR ("A notice came in from the server.\n"); + nserv++; + switch(notice->z_kind) { + case HMCTL: + hm_control(notice); + break; + case SERVNAK: + case SERVACK: + send_back(notice); + break; + default: + syslog (LOG_INFO, "Bad notice kind!?"); + break; + } + } +} + +void +hm_control(ZNotice_t *notice) +{ + Code_t ret; + struct hostent *hp; + char suggested_server[NS_MAXDNAME]; + unsigned long addr; + + DPR("Control message!\n"); + if (!strcmp(notice->z_opcode, SERVER_SHUTDOWN)) { + if (notice->z_message_len) { + addr = inet_addr(notice->z_message); + hp = gethostbyaddr((char *) &addr, sizeof(addr), AF_INET); + if (hp != NULL) { + strncpy(suggested_server, hp->h_name, sizeof(suggested_server)); + suggested_server[sizeof(suggested_server) - 1] = '\0'; + new_server(suggested_server); + } else { + new_server(NULL); + } + } else { + new_server((char *)NULL); + } + } else if (!strcmp(notice->z_opcode, SERVER_PING)) { + notice->z_kind = HMACK; + if ((ret = ZSetDestAddr(&serv_sin)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = send_outgoing(notice)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending ACK"); + } + if (no_server) { + no_server = 0; + retransmit_queue(&serv_sin); + } + } else { + syslog (LOG_INFO, "Bad control message."); + } +} + +void +send_back(ZNotice_t *notice) +{ + ZNotice_Kind_t kind; + struct sockaddr_in repl; + Code_t ret; + + if (!strcmp(notice->z_opcode, HM_BOOT) || + !strcmp(notice->z_opcode, HM_ATTACH)) { + /* ignore message, just an ack from boot, but exit if we + * are rebooting. + */ + if (rebootflag) + die_gracefully(); + } else { + if (remove_notice_from_queue(notice, &kind, &repl) != ZERR_NONE) { + syslog (LOG_INFO, "Hey! This packet isn't in my queue!"); + } else { + /* check if client wants an ACK, and send it */ + if (kind == ACKED) { + DPR2 ("Client ACK port: %u\n", ntohs(repl.sin_port)); + if ((ret = ZSetDestAddr(&repl)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "setting destination"); + } + if ((ret = send_outgoing(notice)) != ZERR_NONE) { + Zperr(ret); + com_err("hm", ret, "sending ACK"); + } + } + } + } + if (no_server) { + no_server = 0; + retransmit_queue(&serv_sin); + } +} + +void +new_server(char *sugg_serv) +{ + no_server = 1; + syslog (LOG_INFO, "Server went down, finding new server."); + send_flush_notice(HM_DETACH); + find_next_server(sugg_serv); + if (booting || deactivated) { + send_boot_notice(HM_BOOT); + deactivated = 0; + } else { + send_boot_notice(HM_ATTACH); + } + disable_queue_retransmits(); +} + +static void +boot_timeout(void *arg) +{ + serv_timeouts++; + new_server(NULL); +} + +static int get_serv_timeout(void) +{ + int ind, ntimeouts; + + ind = (numserv == 0) ? serv_timeouts : serv_timeouts / numserv; + ntimeouts = sizeof(serv_rexmit_times) / sizeof(*serv_rexmit_times); + if (ind >= ntimeouts) + ind = ntimeouts - 1; + return serv_rexmit_times[ind]; +} diff --git a/zwgc/.gitattributes b/zwgc/.gitattributes new file mode 100644 index 0000000..9fe31b6 --- /dev/null +++ b/zwgc/.gitattributes @@ -0,0 +1,4 @@ +instantiate ident +zwgc_resources ident +zwgc.desc ident +zwgc.el ident diff --git a/zwgc/Makefile.in b/zwgc/Makefile.in new file mode 100644 index 0000000..aa18dae --- /dev/null +++ b/zwgc/Makefile.in @@ -0,0 +1,167 @@ +SHELL=@SHELL@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +datadir=@datadir@ +sysconfdir=@sysconfdir@ +sbindir=@sbindir@ +lsbindir=@lsbindir@ +datarootdir=@datarootdir@ + +includedir=@includedir@ +mandir=@mandir@ +libdir=@libdir@ +bindir=@bindir@ +top_builddir=.. + +srcdir=@srcdir@ +top_srcdir=@top_srcdir@ +BUILDTOP=.. +VPATH=@srcdir@ +LIBTOOL=@LIBTOOL@ +CC=@CC@ +YACC=@YACC@ +INSTALL=@INSTALL@ +INSTANTIATE=${srcdir}/instantiate + +editman = sed \ + -e 's|@datadir[@]|${datadir}|g' \ + -e 's|@sysconfdir[@]|${sysconfdir}|g' \ + -e 's|@sbindir[@]|${sbindir}|g' \ + -e 's|@lsbindir[@]|${lsbindir}|g' + +LIBZEPHYR=${BUILDTOP}/lib/libzephyr.la +CPPFLAGS=@CPPFLAGS@ +CFLAGS=@CFLAGS@ +ALL_CFLAGS=${CFLAGS} -DDATADIR=\"${datadir}\" -I${top_srcdir}/h \ + -I${BUILDTOP}/h -I${srcdir} -I. @X_CFLAGS@ ${CPPFLAGS} +YFLAGS=-d +LDFLAGS=@X_LIBS@ @LDFLAGS@ +LIBS=${LIBZEPHYR} @LIBS@ -lcom_err @ZWGC_LIBX11@ @X_EXTRA_LIBS@ \ + @TLIB@ @REGEX_LIBS@ @ARES_LIBS@ + +OBJS= port_dictionary.o pointer_dictionary.o unsigned_long_dictionary.o \ + string_dictionary.o int_dictionary.o string_dictionary_aux.o \ + parser.o lexer.o node.o exec.o buffer.o main.o zephyr.o X_driver.o \ + substitute.o port.o xshow.o mux.o eval.o subscriptions.o notice.o \ + xcut.o regexp.o character_class.o text_operations.o file.o error.o \ + variables.o formatter.o X_fonts.o X_gram.o tty_filter.o \ + standard_ports.o xselect.o xmark.o xrevstack.o xerror.o \ + new_string.o new_memory.o plus.o + +all: zwgc zwgc.1 + +zwgc: ${OBJS} ${LIBZEPHYR} + ${LIBTOOL} --mode=link ${CC} ${LDFLAGS} -o $@ ${OBJS} ${LIBS} + +port_dictionary.c port_dictionary.h: dictionary.c dictionary.h + ${INSTANTIATE} ${srcdir} dictionary port port.h + +pointer_dictionary.c pointer_dictionary.h: dictionary.c dictionary.h + ${INSTANTIATE} ${srcdir} dictionary pointer pointer.h + +unsigned_long_dictionary.c unsigned_long_dictionary.h: dictionary.c \ + dictionary.h + ${INSTANTIATE} ${srcdir} dictionary unsigned_long unsigned_long.h + +string_dictionary.c string_dictionary.h: dictionary.c dictionary.h + ${INSTANTIATE} ${srcdir} dictionary string new_string.h + +int_dictionary.c int_dictionary.h: dictionary.c dictionary.h + ${INSTANTIATE} ${srcdir} dictionary int + +char_stack.h: stack.h + ${INSTANTIATE} ${srcdir} stack char + +string_stack.h: stack.h + ${INSTANTIATE} ${srcdir} stack string + +xmode_stack.h: stack.h + ${INSTANTIATE} ${srcdir} stack xmode + +lexer.o: y.tab.h + +parser.o: y.tab.c y.tab.h + ${CC} -c ${ALL_CFLAGS} -o $@ y.tab.c + +y.tab.c y.tab.h: ${srcdir}/parser.y + ${YACC} ${YFLAGS} ${srcdir}/parser.y + +.c.o: + ${CC} -c ${ALL_CFLAGS} $< + +zwgc.1: ${srcdir}/zwgc.1.in Makefile + ${editman} ${srcdir}/$@.in > $@.tmp + mv $@.tmp $@ + +check: + +install: zwgc zwgc.1 + ${LIBTOOL} --mode=install ${INSTALL} -m 755 zwgc ${DESTDIR}${bindir} + ${INSTALL} -m 644 zwgc.1 ${DESTDIR}${mandir}/man1 + ${INSTALL} -m 644 ${srcdir}/zwgc.desc ${DESTDIR}${datadir}/zephyr + ${INSTALL} -m 644 ${srcdir}/zwgc_resources ${DESTDIR}${datadir}/zephyr + +clean: + ${LIBTOOL} --mode=clean rm -f zwgc + rm -f ${OBJS} port_dictionary.[ch] pointer_dictionary.[ch] + rm -f unsigned_long_dictionary.[ch] string_dictionary.[ch] + rm -f int_dictionary.[ch] char_stack.h string_stack.h xmode_stack.h + rm -f y.tab.[ch] + rm -f zwgc.1 + +${OBJS}: ${top_srcdir}/h/sysdep.h ${BUILDTOP}/h/config.h +zephyr.o: ${BUILDTOP}/h/zephyr/zephyr.h ${BUILDTOP}/h/zephyr/zephyr_err.h + +port_dictionary.o: port.h string_stack.h new_string.h new_memory.h +pointer_dictionary.o: pointer.h new_string.h new_memory.h +unsigned_long_dictionary.o: new_string.h new_memory.h +string_dictionary.o: new_string.h new_memory.h +int_dictionary.o: new_string.h new_memory.h +X_driver.o: X_driver.h new_memory.h formatter.h mux.h variables.h error.h +X_driver.o: X_gram.h xselect.h unsigned_long_dictionary.h +X_fonts.o: X_fonts.h new_memory.h new_string.h error.h pointer_dictionary.h +X_fonts.o: zwgc.h +X_gram.o: X_gram.h xmark.h zwgc.h X_driver.h X_fonts.h error.h new_string.h +X_gram.o: xrevstack.h xerror.h xselect.h +browser.o: zwgc.h +buffer.o: new_memory.h buffer.h +character_class.o: character_class.h +eval.o: new_memory.h node.h eval.h substitute.h port.h buffer.h regexp.h +eval.o: text_operations.h zwgc.h variables.h +exec.o: new_memory.h exec.h eval.h node.h buffer.h port.h variables.h notice.h +file.o: new_memory.h new_string.h error.h +formatter.o: new_memory.h char_stack.h string_dictionary.h formatter.h +formatter.o: text_operations.h +lexer.o: new_memory.h new_string.h int_dictionary.h lexer.h parser.h +main.o: new_memory.h zwgc.h parser.h node.h exec.h zephyr.h notice.h +main.o: subscriptions.h file.h mux.h port.h variables.h main.h +mux.o: mux.h error.h zwgc.h pointer.h +new_memory.o: new_memory.h int_dictionary.h +new_string.o: new_memory.h +node.o: new_memory.h node.h +notice.o: new_memory.h error.h variables.h notice.h +port.o: new_string.h port_dictionary.h port.h notice.h variables.h +regexp.o: regexp.h +standard_ports.o: new_memory.h port.h variables.h error.h main.h +string_dictionary_aux.o: new_memory.h string_dictionary.h +subscriptions.o: new_memory.h new_string.h int_dictionary.h zwgc.h +subscriptions.o: subscriptions.h error.h file.h main.h +substitute.o: new_memory.h lexer.h substitute.h +text_operations.o: new_memory.h text_operations.h char_stack.h +tty_filter.o: new_memory.h new_string.h string_dictionary_aux.h formatter.h +tty_filter.o: zwgc.h error.h +variables.o: new_memory.h notice.h string_dictionary_aux.h variables.h +xcut.o: new_memory.h new_string.h X_gram.h zwgc.h xselect.h xmark.h error.h +xcut.o: xrevstack.h +xerror.o: mux.h +xmark.o: X_gram.h X_fonts.h xmark.h new_string.h +xrevstack.o: X_gram.h zwgc.h +xselect.o: new_string.h xselect.h +xshow.o: pointer_dictionary.h new_memory.h formatter.h variables.h zwgc.h +xshow.o: X_fonts.h X_gram.h xmode_stack.h +zephyr.o: new_string.h zephyr.h error.h mux.h subscriptions.h variables.h +zephyr.o: pointer.h X_driver.h + +.PHONY: all check install clean + diff --git a/zwgc/X_driver.c b/zwgc/X_driver.c new file mode 100644 index 0000000..374b9fd --- /dev/null +++ b/zwgc/X_driver.c @@ -0,0 +1,412 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_X_driver_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* The X driver: */ +/* */ +/****************************************************************************/ + +#ifndef X_DISPLAY_MISSING + +#include +#include "new_string.h" +#include "X_driver.h" +#include +#include "new_memory.h" +#include "formatter.h" +#include "mux.h" +#include "variables.h" +#include "error.h" +#include "X_gram.h" +#include "xselect.h" +#include "unsigned_long_dictionary.h" +#include "zephyr.h" + +char *app_instance; + +/* + * x_dpy - the display we are outputting to + */ + +Display *x_dpy = NULL; + +/****************************************************************************/ +/* */ +/* Code to deal with getting X resources: */ +/* */ +/****************************************************************************/ + +/* + * + */ + +#ifndef APPNAME +#define APPNAME "zwgc" +#endif + +/* + * + */ + +#ifndef APPCLASS +#define APPCLASS "Zwgc" +#endif + +/* + * x_resources - our X resources from application resources, command line, + * and user's X resources. + */ + +static XrmDatabase x_resources = NULL; + +/* + * Internal Routine: + * + * int convert_string_to_bool(string text) + * Effects: If text represents yes/true/on, return 1. If text + * representes no/false/off, return 0. Otherwise, + * returns -1. + */ + +static int +convert_string_to_bool(string text) +{ + if (!strcasecmp("yes", text) || !strcasecmp("y", text) || + !strcasecmp("true", text) || !strcasecmp("t", text) || + !strcasecmp("on", text)) + return(1); + else if (!strcasecmp("no", text) || !strcasecmp("n", text) || + !strcasecmp("false", text) || !strcasecmp("f", text) || + !strcasecmp("off", text)) + return(0); + else + return(-1); +} + +/* + * + */ + +char * +get_string_resource(string name, + string class) +{ + string full_name, full_class; + int status; + char *type; + XrmValue value; + + full_name = string_Concat(APPNAME, "."); + full_name = string_Concat2(full_name, name); + full_class = string_Concat(APPCLASS, "."); + full_class = string_Concat2(full_class, class); + + status = XrmGetResource(x_resources, full_name, full_class, &type, &value); + free(full_name); + free(full_class); + + if (status != True) + return(NULL); + + if (string_Neq(type, "String")) + return(NULL); + + return(value.addr); +} + +/* + * + */ + +int +get_bool_resource(string name, + string class, + int default_value) +{ + int result; + char *temp; + + if (!(temp = get_string_resource(name, class))) + return(default_value); + + result = convert_string_to_bool(temp); + if (result == -1) + result = default_value; + + return(result); +} + +static unsigned_long_dictionary color_dict = NULL; + +/* Requires: name points to color name or hex string. name must be free'd + * eventually by the caller. + * Effects: returns unsigned long pixel value, or default if the + * color is not known by the server. If name is NULL, returns + * default; + * + * comment: caches return values from X server round trips. If name does + * not resolve, this fact is NOT cached, and will result in a round + * trip each time. + */ + +unsigned long +x_string_to_color(char *name, + unsigned long def) +{ + unsigned_long_dictionary_binding *binding; + int exists; + XColor xc; + + if (name == NULL) + return(def); + + binding = unsigned_long_dictionary_Define(color_dict,name,&exists); + + if (exists) { + return((unsigned long) binding->value); + } else { + if (XParseColor(x_dpy, + DefaultColormapOfScreen(DefaultScreenOfDisplay(x_dpy)), + name,&xc)) { + if (XAllocColor(x_dpy, + DefaultColormapOfScreen(DefaultScreenOfDisplay(x_dpy)), + &xc)) { + binding->value = (unsigned long) xc.pixel; + return(xc.pixel); + } else { + ERROR2("Error in XAllocColor on \"%s\": using default color\n", + name); + } + } else { + ERROR2("Error in XParseColor on \"%s\": using default color\n", + name); + } + unsigned_long_dictionary_Delete(color_dict,binding); + return(def); + } + /*NOTREACHED*/ +} + +/* + * Standard X Toolkit command line options: + */ + +static XrmOptionDescRec cmd_options[] = { + {"+rv", "*reverseVideo", XrmoptionNoArg, (XPointer) "off"}, + {"+synchronous", "*synchronous", XrmoptionNoArg, (XPointer) "off"}, + {"-background", "*background", XrmoptionSepArg, (XPointer) NULL}, + {"-bd", "*borderColor", XrmoptionSepArg, (XPointer) NULL}, + {"-bg", "*background", XrmoptionSepArg, (XPointer) NULL}, + {"-bordercolor", "*borderColor", XrmoptionSepArg, (XPointer) NULL}, + {"-borderwidth", ".borderWidth", XrmoptionSepArg, (XPointer) NULL}, + {"-bw", ".borderWidth", XrmoptionSepArg, (XPointer) NULL}, + {"-display", ".display", XrmoptionSepArg, (XPointer) NULL}, + {"-fg", "*foreground", XrmoptionSepArg, (XPointer) NULL}, + {"-fn", "*font", XrmoptionSepArg, (XPointer) NULL}, + {"-font", "*font", XrmoptionSepArg, (XPointer) NULL}, + {"-foreground", "*foreground", XrmoptionSepArg, (XPointer) NULL}, + {"-geometry", ".geometry", XrmoptionSepArg, (XPointer) NULL}, + {"-iconname", ".iconName", XrmoptionSepArg, (XPointer) NULL}, +#ifdef CMU_ZWGCPLUS + {"-lifespan", "*lifespan", XrmoptionSepArg, (XPointer) NULL}, +#endif + {"-name", ".name", XrmoptionSepArg, (XPointer) NULL}, + {"-reverse", "*reverseVideo", XrmoptionNoArg, (XPointer) "on"}, + {"-rv", "*reverseVideo", XrmoptionNoArg, (XPointer) "on"}, + {"-transient", "*transient", XrmoptionNoArg, (XPointer) "on"}, + {"-synchronous", "*synchronous", XrmoptionNoArg, (XPointer) "on"}, + {"-title", ".title", XrmoptionSepArg, (XPointer) NULL}, + {"-xrm", NULL, XrmoptionResArg, (XPointer) NULL} }; + +#define NUMBER_OF_OPTIONS ((sizeof (cmd_options))/ sizeof(cmd_options[0])) + +/* + * + */ + +static int +open_display_and_load_resources(int *pargc, + char **argv) +{ + XrmDatabase temp_db1, temp_db2, temp_db3; + char *filename, *res, *xdef; + char dbasename[128]; + + /* Initialize X resource manager: */ + XrmInitialize(); + + /* + * Parse X toolkit command line arguments (including -display) + * into resources: + */ + XrmParseCommand(&x_resources, cmd_options, NUMBER_OF_OPTIONS, APPNAME, + pargc, argv); + + /* + * Try and open the display using the display specified if given. + * If can't open the display, return an error code. + */ + x_dpy = XOpenDisplay(get_string_resource("display", "display")); + if (!x_dpy) + return(1); + + /* Read in our application-specific resources: */ + sprintf(dbasename, "%s/zephyr/zwgc_resources", DATADIR); + temp_db1 = XrmGetFileDatabase(dbasename); + + /* + * Get resources from the just opened display: + */ + xdef = XResourceManagerString(x_dpy); + if (xdef) + temp_db2 = XrmGetStringDatabase(xdef); + else + temp_db2 = NULL; + + /* + * Merge the 4 sets of resources together such that when searching + * for resources, they are checking in the following order: + * command arguments, XENVIRONMENT resources, server resources, + * application resources + */ + XrmMergeDatabases(temp_db2, &temp_db1); + +#if XlibSpecificationRelease > 4 + /* X11 R5 per-screen resources */ + res = XScreenResourceString (DefaultScreenOfDisplay (x_dpy)); + if (res != NULL) + XrmMergeDatabases(XrmGetStringDatabase(res), &temp_db1); +#endif + + /* + * Get XENVIRONMENT resources, if they exist, and merge + */ + filename = getenv("XENVIRONMENT"); + if (filename) + { + temp_db3 = XrmGetFileDatabase(filename); + XrmMergeDatabases(temp_db3, &temp_db1); + } + XrmMergeDatabases(x_resources, &temp_db1); + x_resources = temp_db1; + + return(0); +} + +/* + * X_driver_ioerror: called by Xlib in case of an X IO error. + * Shouldn't return (according to man page). + * + * on IO error, we clean up and exit. + * + * XXX it would be better to set mux_end_loop_p, but we can't return to + * get there (Xlib will exit if this routine returns). + * + */ + +static int +X_driver_ioerror(Display *display) +{ + ERROR2("X IO error on display '%s'--exiting\n", DisplayString(display)); + finalize_zephyr(); + exit(1); + return 1; +} +/****************************************************************************/ +/* */ +/* Code to deal with initializing the driver: */ +/* */ +/****************************************************************************/ + +/*ARGSUSED*/ +int +X_driver_init(char *drivername, + char notfirst, + int *pargc, + char **argv) +{ + string temp; + int is_sync; + + /* + * Attempt to open display and read resources, including from the + * command line. If fail, exit with error code, disabling this + * driver: + */ + if (open_display_and_load_resources(pargc, argv)) { + ERROR("Unable to open X display -- disabling X driver.\n"); + return(1); + } + + XSetIOErrorHandler(X_driver_ioerror); + + /* + * For now, set some useful variables using resources: + */ + is_sync = get_bool_resource("synchronous", "Synchronous", 0); + if (is_sync) + XSynchronize(x_dpy, is_sync); + temp = get_string_resource("geometry", "Geometry"); + if (temp) + var_set_variable("default_X_geometry", temp); + + temp=strrchr(argv[0],'/'); + + app_instance=string_Copy(temp?temp+1:argv[0]); + + color_dict = unsigned_long_dictionary_Create(37); + + xshowinit(); + x_gram_init(x_dpy); + xicccmInitAtoms(x_dpy); + + mux_add_input_source(ConnectionNumber(x_dpy), + (void(*)(void *))x_get_input, x_dpy); + + return(0); +} + +/****************************************************************************/ +/* */ +/* The display routine itself: */ +/* */ +/****************************************************************************/ + +char * +X_driver(string text) +{ + string text_copy; + desctype *desc; + int numstr, numnl; + + text_copy = string_Copy(text); + desc = disp_get_cmds(text_copy, &numstr, &numnl); + + xshow(x_dpy, desc, numstr, numnl); + + free(text_copy); + free_desc(desc); + return(NULL); +} + +#endif /* X_DISPLAY_MISSING */ + diff --git a/zwgc/X_driver.h b/zwgc/X_driver.h new file mode 100644 index 0000000..7a77b91 --- /dev/null +++ b/zwgc/X_driver.h @@ -0,0 +1,32 @@ +#ifndef x_driver_MODULE +#define x_driver_MODULE + +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#include + +#include "new_string.h" + +extern Display *x_dpy; + +extern char *X_driver(string); +extern int X_driver_init(char *, char, int *, char **); +extern char *get_string_resource(string, string); +extern int get_bool_resource(string, string, int); +extern unsigned long x_string_to_color(char *, unsigned long); + +#endif diff --git a/zwgc/X_fonts.c b/zwgc/X_fonts.c new file mode 100644 index 0000000..7e13032 --- /dev/null +++ b/zwgc/X_fonts.c @@ -0,0 +1,255 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_X_fonts_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Code dealing with X fonts: */ +/* */ +/****************************************************************************/ + +#ifndef X_DISPLAY_MISSING + +#include "X_fonts.h" +#include "new_memory.h" +#include "new_string.h" +#include "error.h" +#include "pointer_dictionary.h" +#include "zwgc.h" + +/* + * font_dict - Lookup cache for fonts (the value pointers are XFontSet's) + */ + +static pointer_dictionary family_dict = NULL; +static pointer_dictionary fontname_dict = NULL; +static pointer_dictionary fontst_dict = NULL; + +/* + * {face,size}_to_string - lookup tables for converting {face,size} int + * constants to ascii strings: + */ + +static string face_to_string[] = { "roman", "bold", "italic", "bolditalic" }; +static string size_to_string[] = { "small", "medium", "large" }; + +static char * +get_family(char *style, char *substyle) +{ + char *desc; + pointer_dictionary_binding *binding; + int exists; + char *family; + + desc=string_Concat("style.", style); + desc=string_Concat2(desc, ".substyle."); + desc=string_Concat2(desc, substyle); + desc=string_Concat2(desc, ".fontfamily"); + + if (!family_dict) + family_dict = pointer_dictionary_Create(37); + binding = pointer_dictionary_Define(family_dict, desc, &exists); + + if (exists) { + free(desc); + return((string) binding->value); + } else { + family = get_string_resource(desc, + "StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.FontfamilyKey"); + free(desc); + if (family == NULL) + pointer_dictionary_Delete(family_dict, binding); + else + binding->value = (pointer)family; + return(family); /* If resource returns NULL, return NULL also */ + } +} + +static char * +get_specific_fontname(char *family, + int size, + int face) +{ + char *desc; + pointer_dictionary_binding *binding; + int exists; + char *fontname; + + desc = string_Concat("fontfamily.", family); + desc = string_Concat2(desc, "."); + desc = string_Concat2(desc, size_to_string[size]); + desc = string_Concat2(desc, "."); + desc = string_Concat2(desc, face_to_string[face]); + + if (!fontname_dict) + fontname_dict = pointer_dictionary_Create(37); + binding = pointer_dictionary_Define(fontname_dict, desc, &exists); + + if (exists) { + free(desc); + return (string)binding->value; + } else { + fontname = get_string_resource(desc, "FontfamilyKey.Fontfamily.Size.Face"); + free(desc); + if (fontname == NULL) + pointer_dictionary_Delete(fontname_dict, binding); + else + binding->value = (pointer)fontname; + return fontname; /* If resource returns NULL, return NULL also */ + } +} + +static XFontSet +get_fontst(Display *dpy, char *fontname) +{ + pointer_dictionary_binding *binding; + int exists; + XFontSet fontst; + char **missing_list; + int missing_count; + char *def_string; + + if (!fontst_dict) + fontst_dict = pointer_dictionary_Create(37); + binding = pointer_dictionary_Define(fontst_dict, fontname, &exists); + + if (exists) + return((XFontSet)binding->value); + + fontst = XCreateFontSet(dpy, fontname, &missing_list, &missing_count, + &def_string); + XFreeStringList(missing_list); + + if (fontst == NULL) + pointer_dictionary_Delete(fontst_dict,binding); + else + binding->value = (pointer)fontst; + + return(fontst); /* If resource returns NULL, return NULL also */ +} + +static char * +get_fontname(char *family, int size, int face) +{ + char *fontname; + + fontname = get_specific_fontname(family, size, face); + if (!fontname) + fontname = get_specific_fontname(family, size, ROMAN_FACE); + if (!fontname) + fontname = get_specific_fontname(family, MEDIUM_SIZE, face); + if (!fontname) + fontname = get_specific_fontname(family, MEDIUM_SIZE, ROMAN_FACE); + return(fontname); +} + +static XFontSet +complete_get_fontst(Display *dpy, + string style, + string substyle, + int size, + int face) +{ + char *family, *fontname; + XFontSet fontst; + + family = get_family(style, substyle); + if (!family) + return NULL; + fontname = get_fontname(family, size, face); + if (!fontname) + return NULL; + fontst = get_fontst(dpy, fontname); + if (!fontst) + return NULL; + + return fontst; +} + +/* + * XFontSet get_font(string style, substyle; int size, face) + * Requires: size is one of SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE and + * face is one of ROMAN_FACE, BOLD_FACE, ITALIC_FACE, + * BOLDITALIC_FACE. + * Effects: unknown + */ + +XFontSet +get_font(Display *dpy, + string style, + string substyle, + int size, + int face) +{ + char *family,*fontname; + XFontSet fontst = NULL; + + if (size == SPECIAL_SIZE) { + /* attempt to process @font explicitly */ + fontst = get_fontst(dpy, substyle); + } else { + family = get_family(style, substyle); + + if (family) + fontname = get_fontname(family, size, face); + else + fontname = get_fontname(substyle, size, face); + + if (fontname) { + fontst = get_fontst(dpy, fontname); + if (fontst) + return fontst; + } + + /* At this point, the no-failure case didn't happen, and the case + of substyle being the fontfamily didn't happen, either. */ + + fontst = complete_get_fontst(dpy, style, "text", size, face); + if (!fontst) + fontst = complete_get_fontst(dpy, "default", substyle, size, face); + if (!fontst) + fontst = complete_get_fontst(dpy, "default", "text", size, face); + if (!fontst) { + fontname = get_fontname("default", size, face); + if (fontname) + fontst = get_fontst(dpy, fontname); + } + } + if (fontst) + return fontst; + + /* If all else fails, try fixed */ + + fontst = get_fontst(dpy, "fixed"); + + if (fontst) + return fontst; + + /* No fonts available. Die. */ + + ERROR("Unable to open font \"fixed\". Aborting..."); +#ifdef DEBUG + abort(); +#else + exit(1); +#endif +} + +#endif /* X_DISPLAY_MISSING */ diff --git a/zwgc/X_fonts.h b/zwgc/X_fonts.h new file mode 100644 index 0000000..8e40ed8 --- /dev/null +++ b/zwgc/X_fonts.h @@ -0,0 +1,46 @@ +#ifndef x_fonts_MODULE +#define x_fonts_MODULE + +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#include "X_driver.h" + +#define SPECIAL_FACE -1 +#define ROMAN_FACE 0 +#define BOLD_FACE 1 +#define ITALIC_FACE 2 +#define BOLD_ITALIC_FACE 3 + +#define SPECIAL_SIZE -1 +#define SMALL_SIZE 0 +#define MEDIUM_SIZE 1 +#define LARGE_SIZE 2 + +/* + * XFontSet get_font(string family; int size, face) + * Requires: size is one of SMALL_SIZE, MEDIUM_SIZE, LARGE_SIZE and + * face is one of ROMAN_FACE, BOLD_FACE, ITALIC_FACE, + * BOLDITALIC_FACE. + * Effects: Looks up the font specified by the above in the + * X resources. If that font is not specified by in + * the X resources or it can't be loaded, the font + * specified by default.medium.roman is used. <<<>>> + */ + +extern XFontSet get_font(Display *, string, string, int, int); + +#endif diff --git a/zwgc/X_gram.c b/zwgc/X_gram.c new file mode 100644 index 0000000..bd80dde --- /dev/null +++ b/zwgc/X_gram.c @@ -0,0 +1,562 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_X_gram_c[] = "$Id$"; +#endif + +#include + +#ifndef X_DISPLAY_MISSING + +#include +#include "X_gram.h" +#include "xmark.h" +#include +#include +#include +#include "zwgc.h" +#include "X_driver.h" +#include "X_fonts.h" +#include "error.h" +#include "new_string.h" +#include "xrevstack.h" +#include "xerror.h" +#include "xselect.h" +#ifdef CMU_ZWGCPLUS +#include "plus.h" +#endif + +extern XContext desc_context; +extern char *app_instance; + +/* + * + */ + +int internal_border_width = 2; + +unsigned long default_fgcolor; +unsigned long default_bgcolor; +unsigned long default_bordercolor; +long ttl = 0; +static int reset_saver; +static int border_width = 1; +static int cursor_code = XC_sailboat; +static int set_transient; +static int enable_delete; +static char *title_name,*icon_name; +static Cursor cursor; +static Window group_leader; /* In order to have transient windows, + * I need a top-level window to always exist + */ +static XClassHint classhint; +static XSetWindowAttributes xattributes; +static unsigned long xattributes_mask; +static int set_all_desktops = True; +static Atom net_wm_desktop = None; +static Atom net_wm_window_type = None; +static Atom net_wm_window_type_utility = None; + +/* ICCCM note: + * + * the following properties must be set on all top-level windows: + * + * WM_NAME XStoreName(dpy,w,name); + * WM_ICON_NAME XSetIconName(dpy,w,name); + * WM_NORMAL_HINTS XSetNormalHints(dpy,w,sizehints); + * WM_HINTS XSetWMHints(dpy,w,wmhints); + * WM_CLASS XSetClassHint(dpy,w,classhint); + * + * and for individual zgrams: + * + * WM_TRANSIENT_FOR XSetTransientForHint(dpy,w,main_window); + * WM_PROTOCOLS XSetWMProtocols(dpy,w,protocols,cnt); + */ + +/* set all properties defined in ICCCM. If main_window == 0, + * per-zgram initialization is not done. + */ + +/*ARGSUSED*/ +static void +x_set_icccm_hints(Display *dpy, + Window w, + char *name, + char *wm_icon_name, + XSizeHints *psizehints, + XWMHints *pwmhints, + Window main_window) +{ + XStoreName(dpy,w,name); + XSetIconName(dpy,w,wm_icon_name); + XSetWMNormalHints(dpy,w,psizehints); + XSetWMHints(dpy,w,pwmhints); + XSetClassHint(dpy,w,&classhint); + /* in order for some wm's to iconify, the window shouldn't be transient. + e.g. Motif wm */ + if (main_window != None) { + if (set_transient) + XSetTransientForHint(dpy,w,main_window); + } + if (enable_delete) + XSetWMProtocols(dpy,w,&XA_WM_DELETE_WINDOW,1); +} + +void +x_gram_init(Display *dpy) +{ + char *temp; + XSizeHints sizehints; + XWMHints wmhints; + unsigned long rv,tc; + + default_fgcolor = BlackPixelOfScreen(DefaultScreenOfDisplay(dpy)); + default_bgcolor = WhitePixelOfScreen(DefaultScreenOfDisplay(dpy)); + rv = get_bool_resource("reverseVideo", "ReverseVideo", 0); + if (rv) { + tc = default_fgcolor; + default_fgcolor = default_bgcolor; + default_bgcolor = tc; + } + temp = get_string_resource("foreground", "Foreground"); + if (temp) + default_fgcolor = x_string_to_color(temp, default_fgcolor); + temp = get_string_resource("background", "Background"); + if (temp) + default_bgcolor = x_string_to_color(temp, default_bgcolor); + default_bordercolor = default_fgcolor; + temp = get_string_resource("borderColor", "BorderColor"); + if (temp) + default_bordercolor = x_string_to_color(temp, default_bordercolor); + + temp = get_string_resource("minTimeToLive", "MinTimeToLive"); + if (temp && atoi(temp)>=0) + ttl = atoi(temp); + +#ifdef CMU_ZWGCPLUS + if (ttl == 0) { + temp = get_string_resource("lifespan", "LifeSpan"); + if (temp && atoi(temp)>=0) + ttl = atoi(temp); + } + + get_full_names = get_bool_resource("getFullNames", "GetFullNames", 0); +#endif + + reverse_stack = get_bool_resource("reverseStack", "ReverseStack", 0); + reset_saver = get_bool_resource("resetSaver", "ResetSaver", 1); + /* The default here should be 1, but mwm sucks */ + set_transient = get_bool_resource("transient", "Transient", 0); + enable_delete = get_bool_resource("enableDelete", "EnableDelete", 1); + + temp = get_string_resource("borderWidth", "BorderWidth"); + /* <<<>>> */ + if (temp && atoi(temp)>=0) + border_width = atoi(temp); + + temp = get_string_resource("internalBorder", "InternalBorder"); + /* <<<>>> */ + if (temp && atoi(temp)>=0) + internal_border_width = atoi(temp); + + temp = get_string_resource("cursorCode", "CursorCode"); + /* <<<>>> */ + if (temp && atoi(temp)) + cursor_code = atoi(temp); + + cursor = XCreateFontCursor(dpy, cursor_code); + if (!cursor) + cursor = XCreateFontCursor(dpy, XC_sailboat); + + temp = get_string_resource("pointerColor", "Foreground"); + if (temp) { + char *temp2; + XColor cursor_fore, cursor_back; + /* XXX need to do our own parsing here, since the RecolorCursor + routine requires an XColor, not an unsigned long (pixel) */ + if (!(temp2 = get_string_resource("background","Background"))) { + if (default_bgcolor == WhitePixelOfScreen(DefaultScreenOfDisplay(dpy))) + temp2 = "white"; + else + temp2 = "black"; + } + if (XParseColor(dpy, + DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)), + temp, &cursor_fore) && + XParseColor(dpy, + DefaultColormapOfScreen(DefaultScreenOfDisplay(dpy)), + temp2, &cursor_back)) { + XRecolorCursor(dpy, cursor, &cursor_fore, &cursor_back); + } + } + if (!(title_name=get_string_resource("title","Title"))) + if (!(title_name=get_string_resource("name","Name"))) + title_name=app_instance; + + if (!(icon_name=get_string_resource("iconName","IconName"))) + if (!(icon_name=get_string_resource("name","Name"))) + icon_name=app_instance; + + if (!(temp=get_string_resource("name","Name"))) + if (!(temp=(char *) getenv("RESOURCE_NAME"))) + temp=app_instance; + classhint.res_name=string_Copy(temp); + classhint.res_class="Zwgc"; + + if (set_transient) { + group_leader=XCreateSimpleWindow(dpy,DefaultRootWindow(dpy),0,0,100,100, + 0,default_bordercolor,default_bgcolor); + sizehints.x = 0; + sizehints.y = 0; + sizehints.width = 100; + sizehints.height = 100; + sizehints.flags = PPosition | PSize; + + wmhints.input = False; + wmhints.initial_state = DontCareState; + wmhints.flags = InputHint | StateHint; + + x_set_icccm_hints(dpy,group_leader,"ZwgcGroup","ZwgcGroup",&sizehints, + &wmhints,0); + } + xattributes.border_pixel = default_bordercolor; + xattributes.cursor = cursor; + xattributes.event_mask = (ExposureMask|ButtonReleaseMask|ButtonPressMask + |LeaveWindowMask|Button1MotionMask +#ifdef CMU_ZWGCPLUS + |KeyPressMask +#endif + |Button3MotionMask|StructureNotifyMask); + xattributes_mask = (CWBackPixel|CWBorderPixel|CWEventMask|CWCursor); + + set_all_desktops = get_bool_resource("allDesktops", "AllDesktops", True); + net_wm_desktop = XInternAtom(dpy, "_NET_WM_DESKTOP", False); + net_wm_window_type = XInternAtom(dpy, "_NET_WM_WINDOW_TYPE", False); + net_wm_window_type_utility = XInternAtom(dpy, + "_NET_WM_WINDOW_TYPE_UTILITY", + False); + + temp = get_string_resource ("backingStore", "BackingStore"); + if (!temp) + return; + xattributes_mask |= CWBackingStore; + if (!strcasecmp (temp, "notuseful")) + xattributes.backing_store = NotUseful; + else if (!strcasecmp (temp, "whenmapped")) + xattributes.backing_store = WhenMapped; + else if (!strcasecmp (temp, "always")) + xattributes.backing_store = Always; + else if (!strcasecmp (temp, "default")) + xattributes_mask &= ~CWBackingStore; + else { + switch (get_bool_resource ("backingStore", "BackingStore", -1)) { + case 0: + xattributes.backing_store = NotUseful; + break; + case 1: + xattributes.backing_store = WhenMapped; + break; + case -1: + fprintf (stderr, + "zwgc: Cannot interpret backing-store resource value `%s'.\n", + temp); + xattributes_mask &= ~CWBackingStore; + break; + } + } +} + +static int +x_calc_gravity(int xalign, + int yalign) +{ + if (yalign > 0) { /* North */ + return (xalign > 0) ? NorthWestGravity + : (xalign == 0) ? NorthGravity + : NorthEastGravity; + } else if (yalign == 0) { /* Center */ + return (xalign > 0) ? WestGravity + : (xalign == 0) ? CenterGravity + : EastGravity; + } else { /* South */ + return (xalign > 0) ? SouthWestGravity + : (xalign == 0) ? SouthGravity + : SouthEastGravity; + } +} + +void +x_gram_create(Display *dpy, + x_gram *gram, + int xalign, + int yalign, + int xpos, + int ypos, + int xsize, + int ysize, + int beepcount) +{ + Window w; + XSizeHints sizehints; + XWMHints wmhints; + XSetWindowAttributes attributes; + unsigned long all_desktops = 0xFFFFFFFF; + + /* + * Adjust xpos, ypos based on the alignments xalign, yalign and the sizes: + */ + if (xalign < 0) + xpos = WidthOfScreen(DefaultScreenOfDisplay(dpy)) + - xpos - xsize - 2 * border_width; + else if (xalign == 0) + xpos = ((WidthOfScreen(DefaultScreenOfDisplay(dpy)) + - xsize - 2 * border_width) >> 1) + xpos; + + if (yalign<0) + ypos = HeightOfScreen(DefaultScreenOfDisplay(dpy)) + - ypos - ysize - 2 * border_width; + else if (yalign == 0) + ypos = ((HeightOfScreen(DefaultScreenOfDisplay(dpy)) + - ysize - 2 * border_width) >> 1) + ypos; + + /* + * Create the window: + */ + attributes = xattributes; + attributes.background_pixel = gram->bgcolor; + + gram->w = w = XCreateWindow (dpy, DefaultRootWindow (dpy), xpos, ypos, + xsize, ysize, border_width, 0, + CopyFromParent, CopyFromParent, + xattributes_mask, &attributes); + + sizehints.x = xpos; + sizehints.y = ypos; + sizehints.width = xsize; + sizehints.height = ysize; + sizehints.win_gravity = x_calc_gravity(xalign, yalign); + sizehints.flags = USPosition | USSize | PWinGravity; + + wmhints.input = False; + wmhints.initial_state = NormalState; + if (set_transient) { + wmhints.window_group = group_leader; + wmhints.flags = InputHint | StateHint | WindowGroupHint; + + x_set_icccm_hints(dpy, w, title_name, icon_name, &sizehints, &wmhints, + group_leader); + } else { + wmhints.flags = InputHint | StateHint; + + x_set_icccm_hints(dpy, w, title_name, icon_name, &sizehints, &wmhints, 0); + } + + if (net_wm_window_type != None && net_wm_window_type_utility != None) + XChangeProperty(dpy, w, net_wm_window_type, XA_ATOM, 32, PropModeReplace, + (unsigned char *) &net_wm_window_type_utility, 1); + if (set_all_desktops && net_wm_desktop != None) + XChangeProperty(dpy, w, net_wm_desktop, XA_CARDINAL, 32, PropModeReplace, + (unsigned char *) &all_desktops, 1); + + XSaveContext(dpy, w, desc_context, (XPointer)gram); + + gram->can_die.tv_sec = 0; + + XMapWindow(dpy, w); + + if (beepcount) + XBell(dpy, 0); + + xerror_happened = 0; + if (reverse_stack && bottom_gram) { + XWindowChanges winchanges; + + winchanges.sibling = bottom_gram->w; + winchanges.stack_mode = Below; + /* Metacity may use border_width even if it's not specified in + * the value mask, so we must initialize it. See: + * http://bugzilla.gnome.org/show_bug.cgi?id=305257 */ + winchanges.border_width = border_width; + + begin_xerror_trap (dpy); + XReconfigureWMWindow (dpy, w, DefaultScreen (dpy), + CWSibling | CWStackMode, &winchanges); + end_xerror_trap (dpy); + if (xerror_happened) { + /* The event didn't go. Print an error message, and continue. */ + ERROR ("Error configuring window to the bottom of the stack.\n"); + } + } + /* we always need to keep a linked list of windows */ + add_to_bottom(gram); + if (xerror_happened) + pull_to_top(gram); + + if (reset_saver) + XResetScreenSaver(dpy); + + XFlush(dpy); + /* Because the flushing/syncing/etc with the error trapping can cause + events to be read into the Xlib queue, we need to go through the queue + here before exiting so that any pending events get processed. + */ + x_get_input(dpy); +} + +inline static void +SetFG(Display *dpy, GC gc, unsigned long foreground) { + XGCValues gcvals; + + gcvals.foreground = foreground; + XChangeGC(dpy, gc, GCForeground, &gcvals); +} + +static void +x_gram_draw(Display *dpy, Window w, x_gram *gram, Region region) +{ + int i; + GC gc; + XGCValues gcvals; + xblock *xb; +#ifdef X_HAVE_UTF8_STRING + XmbTextItem text; +#else + XwcTextItem text; +#endif + int startblock, endblock, startpixel = 0, endpixel = 0; + + gc = XCreateGC(dpy, w, 0, &gcvals); + XSetRegion(dpy, gc, region); + + if ((markgram == gram) && (STARTBLOCK != -1) && (ENDBLOCK != -1)) { + if (xmarkSecond() == XMARK_END_BOUND) { + startblock = STARTBLOCK; + endblock = ENDBLOCK; + startpixel = STARTPIXEL; + endpixel = ENDPIXEL; + } else { + startblock = ENDBLOCK; + endblock = STARTBLOCK; + startpixel = ENDPIXEL; + endpixel = STARTPIXEL; + } + } else { + startblock = -1; + endblock = -1; + } + + for (i=0, xb = gram->blocks; i < gram->numblocks; i++, xb++) { + if (XRectInRegion(region, xb->x1, xb->y1, xb->x2 - xb->x1, + xb->y2 - xb->y1) != RectangleOut) { + if (i == startblock) { + if (i == endblock) { + SetFG(dpy, gc, gram->bgcolor); + XFillRectangle(dpy, w, gc, xb->x1, xb->y1, startpixel, + xb->y2 - xb->y1); + SetFG(dpy, gc, xb->fgcolor); + XFillRectangle(dpy, w, gc, xb->x1 + startpixel, xb->y1, + endpixel - startpixel, xb->y2 - xb->y1); + SetFG(dpy, gc, gram->bgcolor); + XFillRectangle(dpy, w, gc, xb->x1 + endpixel, xb->y1, + xb->x2 - xb->x1 - endpixel, xb->y2 - xb->y1); + } else { + SetFG(dpy, gc, gram->bgcolor); + XFillRectangle(dpy, w, gc, xb->x1, xb->y1, startpixel, + xb->y2 - xb->y1); + SetFG(dpy, gc, xb->fgcolor); + XFillRectangle(dpy, w, gc, xb->x1 + startpixel, xb->y1, + xb->x2 - xb->x1 - startpixel,xb->y2 - xb->y1); + } + } else if (i == endblock) { + SetFG(dpy, gc, xb->fgcolor); + XFillRectangle(dpy, w, gc, xb->x1, xb->y1, endpixel, + xb->y2 - xb->y1); + SetFG(dpy, gc, gram->bgcolor); + XFillRectangle(dpy, w, gc, xb->x1 + endpixel, xb->y1, + xb->x2 - xb->x1 - endpixel, xb->y2 - xb->y1); + } else { + if (startblock < i && i < endblock) { + SetFG(dpy, gc, xb->fgcolor); + } else { + SetFG(dpy, gc, gram->bgcolor); + } + XFillRectangle(dpy, w, gc, xb->x1, xb->y1, xb->x2 - xb->x1, + xb->y2 - xb->y1); + } + } + } + + gcvals.function = GXxor; + XChangeGC(dpy, gc, GCFunction, &gcvals); + + for (i=0, xb = gram->blocks; i < gram->numblocks; i++, xb++) { + if (XRectInRegion(region, xb->x1, xb->y1, xb->x2 - xb->x1, + xb->y2 - xb->y1) != RectangleOut) { + SetFG(dpy, gc, gram->bgcolor ^ xb->fgcolor); +#ifdef X_HAVE_UTF8_STRING + text.chars = xb->wstr; +#else + text.chars = (wchar_t *)xb->wstr; +#endif + text.nchars = xb->wlen; + text.delta = 0; + text.font_set = xb->font; +#ifdef X_HAVE_UTF8_STRING + Xutf8DrawText(dpy, w, gc, xb->x, xb->y, &text, 1); +#else + XwcDrawText(dpy, w, gc, xb->x, xb->y, &text, 1); +#endif + } + } + + XFreeGC(dpy, gc); +} + +void +x_gram_expose(Display *dpy, + Window w, + x_gram *gram, + XExposeEvent *event) +{ + static Region region; + static int partregion; + XRectangle rect; + + rect.x = (short) event->x; + rect.y = (short) event->y; + rect.width = (unsigned short) event->width; + rect.height = (unsigned short) event->height; + +#ifdef MARK_DEBUG + printf("----- xeventExpose:\nx=%d y=%d w=%d h=%d\n-----", + event->x,event->y,event->width,event->height); +#endif + + if (! partregion) { + region=XCreateRegion(); + partregion = 1; + } + + if (rect.width && rect.height) XUnionRectWithRegion(&rect,region,region); + + if (event->count == 0) { + x_gram_draw(dpy,w,gram,region); + partregion = 0; + XDestroyRegion(region); + } +} + +#endif /* X_DISPLAY_MISSING */ diff --git a/zwgc/X_gram.h b/zwgc/X_gram.h new file mode 100644 index 0000000..fe591be --- /dev/null +++ b/zwgc/X_gram.h @@ -0,0 +1,92 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef x_gram_TYPE +#define x_gram_TYPE + +#include +#include +#include + +#include "formatter.h" + +typedef struct _xblock { + unsigned long fgcolor; + XFontSet font; + int x,y; + int x1,y1,x2,y2; /* bounds of block. used for cut and paste. */ + int strindex; + int strlen; + char *wstr; + int wlen; +} xblock; + +typedef struct _x_gram { + unsigned long bgcolor; + int numblocks; + xblock *blocks; + char *text; + struct _x_gram *below,*above; + Window w; +#ifdef CMU_ZWGCPLUS + ZNotice_t *notice; +#endif + struct timeval can_die; +} x_gram; + +typedef struct _xauxblock { + int align; + XFontSet font; + char *str; + int len; + int width; +} xauxblock; + +typedef struct _xmode { + int bold; + int italic; + int size; + int align; + int expcolor; + unsigned long color; + char *substyle; + char *font; +} xmode; + +typedef struct _xlinedesc { + int startblock; + int numblock; + int lsize; + int csize; + int rsize; + int ascent; + int descent; +} xlinedesc; + +/* alignment values: */ +#define LEFTALIGN 0 +#define CENTERALIGN 1 +#define RIGHTALIGN 2 + +extern void x_gram_init(Display *); +extern void x_gram_create(Display *, x_gram *, int, int, int, int, int, int, int); +extern void x_gram_expose(Display *, Window, x_gram *, XExposeEvent *); +extern void xshow(Display *, desctype *, int, int); +extern void xcut(Display *, XEvent *, XContext); +extern void x_get_input(Display *); +extern void xshowinit(void); + +#endif diff --git a/zwgc/browser.c b/zwgc/browser.c new file mode 100644 index 0000000..7389a51 --- /dev/null +++ b/zwgc/browser.c @@ -0,0 +1,55 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#if (!defined(lint) && !defined(SABER)) +static char rcsid_browser_c[] = "$Id$"; +#endif + +#include + +#include +#include +#include +#include "zwgc.h" + +static int browser_fd; +struct sockaddr_un sun; + +int BOpenSocket() +{ + int fd,len; + char *temp; + + if ((fd=socket(PF_UNIX,SOCK_STREAM,0)) == -1) + return(-1); + + sun.sun_family=AF_UNIX; + if (temp=getenv("WGSOCK")) + strncpy(sun.sunpath,temp,sizeof(sun.sunpath)); + else + sprintf(sun.sun_path,"/tmp/.zwgc.%d",getuid()); + if (bind(fd,(struct sockaddr *) &sun, + (len=strlen(sun.sunpath)) > sizeof(sun.sunpath)? + sizeof(sun.sunpath):len) == -1) { + close(fd); + return(-1); + } + + if (listen(fd,5) == -1) { + unlink(sun.sunpath); + close(fd); + return(-1); + } + + return(fd); +} diff --git a/zwgc/browser.h b/zwgc/browser.h new file mode 100644 index 0000000..7076915 --- /dev/null +++ b/zwgc/browser.h @@ -0,0 +1,40 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#define BROWSER_NEW_REQ 1 +#define BROWSER_NEW_REQ_RESP 2 +#define BROWSER_ZPACKET 3 +#define BROWSER_ZPACKET_RESP 4 +#define BROWSER_TEXT 5 +#define BROWSER_WINDOW_ID 6 +#define BROWSER_VAR_REQ 7 +#define BROWSER_VAR_REQ_RESP 8 + + +#define BROWSER_TYPE_OVERRIDE 11 +#define BROWSER_TYPE_DRIVER 12 +#define BROWSER_TYPE_WM 13 +#define BROWSER_TYPE_SIMPLE 14 + +#define BROWSER_ACK 21 +#define BROWSER_NAK 22 + +#define BROWSER_KEEP 31 +#define BROWSER_LOSE 32 + +extern int ZBOpenConnection(); +extern void ZBCloseConnection( /* int fd */ ); +extern char *var_get_variable( /* char *varname */ ); diff --git a/zwgc/buffer.c b/zwgc/buffer.c new file mode 100644 index 0000000..8c047af --- /dev/null +++ b/zwgc/buffer.c @@ -0,0 +1,46 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_buffer_c[] = "$Id$"; +#endif + +#include + +#include "new_memory.h" +#include "buffer.h" + +static char *buffer = 0; + +string +buffer_to_string(void) +{ + return(buffer); +} + +void +clear_buffer(void) +{ + if (buffer) + free(buffer); + + buffer = string_Copy(""); +} + +void +append_buffer(char *str) +{ + buffer = string_Concat2(buffer, str); +} diff --git a/zwgc/buffer.h b/zwgc/buffer.h new file mode 100644 index 0000000..db3f2ea --- /dev/null +++ b/zwgc/buffer.h @@ -0,0 +1,26 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef buffer_MODULE +#define buffer_MODULE + +#include "new_string.h" + +extern string buffer_to_string(void); +extern void clear_buffer(void); +extern void append_buffer(char *); + +#endif diff --git a/zwgc/character_class.c b/zwgc/character_class.c new file mode 100644 index 0000000..41716cb --- /dev/null +++ b/zwgc/character_class.c @@ -0,0 +1,45 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_character_class_c[] = "$Id$"; +#endif + +#include +#include +#include "character_class.h" + +/* + * It may look like we are passing the cache by value, but since it's + * really an array we are passing by reference. C strikes again.... + */ + +static character_class cache; + +/* character_class */ +char * +string_to_character_class(string str) +{ + int i, l; + + (void) memset(cache, 0, sizeof(cache)); + + l = strlen(str); + + for (i = 0; i < l; i++) + cache[(unsigned char)str[i]] = 1; + + return(cache); +} diff --git a/zwgc/character_class.h b/zwgc/character_class.h new file mode 100644 index 0000000..050b282 --- /dev/null +++ b/zwgc/character_class.h @@ -0,0 +1,28 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef character_class_TYPE +#define character_class_TYPE + +#include "new_string.h" + +#define NUMBER_OF_CHARACTERS 256 + +typedef char character_class[NUMBER_OF_CHARACTERS]; + +extern /* character_class */ char * string_to_character_class(string); + +#endif diff --git a/zwgc/dictionary.c b/zwgc/dictionary.c new file mode 100644 index 0000000..f6a3c74 --- /dev/null +++ b/zwgc/dictionary.c @@ -0,0 +1,260 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_dictionary_c[] = "$Id$"; +#endif + +/* + * dictionary - a module implementing a generic dictionary. That is, + * any type can be used for the values that keys are bound to. + * Keys are always strings. + * + * Overview: + * + * A dictionary is a set of bindings which bind values of some + * type (this type is the generic parameter of the dictionary) to + * strings. At most one value can be bound to any one string. + * The value that a string is bound to can be changed later. + * Bindings can also be deleted later. It is also possible to + * enumerate all of the bindings in a dictionary. Dictionarys + * are heap based and must be created & destroyed accordingly. + * + * Note: This module assumes that malloc NEVER returns 0 for reasonable + * requests. It is the users responsibility to either ensure that + * this happens or supply a version of malloc with error + * handling. + * + * Dictionarys are mutable. + * + * Implementation: + * + * A standard chaining hash table is used to implement dictionarys. + * Each dictionary has an associated size (# of slots), allowing + * different size dictionaries as needed. + */ + +#include "TYPE_T_dictionary.h" +#include "new_string.h" +#include "new_memory.h" + +#ifndef NULL +#define NULL 0 +#endif + +/* + * TYPE_T_dictionary TYPE_T_dictionary_Create(int size): + * Requires: size > 0 + * Effects: Returns a new empty dictionary containing no bindings. + * The returned dictionary must be destroyed using + * TYPE_T_dictionary_Destroy. Size is a time vs space + * parameter. For this implementation, space used is + * proportional to size and time used is proportional + * to number of bindings divided by size. It is preferable + * that size is a prime number. + */ + +TYPE_T_dictionary +TYPE_T_dictionary_Create(int size) +{ + int i; + TYPE_T_dictionary result; + + result = (TYPE_T_dictionary)malloc(sizeof(struct _TYPE_T_dictionary)); + result->size = size; + result->slots = (TYPE_T_dictionary_binding **)malloc( + size*sizeof(TYPE_T_dictionary_binding *)); + + for (i=0; islots[i] = NULL; + + return(result); +} + +/* + * void TYPE_T_dictionary_Destroy(TYPE_T_dictionary d): + * Requires: d is a non-destroyed TYPE_T_dictionary + * Modifies: d + * Effects: Destroys dictionary d freeing up the space it consumes. + * Dictionary d should never be referenced again. Note that + * free is NOT called on the values of the bindings. If + * this is needed, the client must do this first using + * TYPE_T_dictionary_Enumerate. + */ + +void +TYPE_T_dictionary_Destroy(TYPE_T_dictionary d) +{ + int i; + TYPE_T_dictionary_binding *binding_ptr, *new_binding_ptr; + + for (i=0; isize; i++) { + binding_ptr = d->slots[i]; + while (binding_ptr) { + new_binding_ptr = binding_ptr->next; + free(binding_ptr->key); + free(binding_ptr); + binding_ptr = new_binding_ptr; + } + } + free(d->slots); + free(d); +} + +/* + * void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d; void (*proc)()): + * Requires: proc is a void procedure taking 1 argument, a + * TYPE_T_dictionary_binding pointer, which does not + * make any calls using dictionary d. + * Effects: Calls proc once with each binding in dictionary d. + * Order of bindings passed is undefined. Note that + * only the value field of the binding should be considered + * writable by proc. + */ + +void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d, + void (*proc)(TYPE_T_dictionary_binding *)) +{ + int i; + TYPE_T_dictionary_binding *binding_ptr; + + for (i=0; isize; i++) { + binding_ptr = d->slots[i]; + while (binding_ptr) { + proc(binding_ptr); + binding_ptr = binding_ptr->next; + } + } +} + +/* + * Private routine: + * + * unsigned int dictionary__hash(char *s): + * Effects: Hashs s to an unsigned integer. This number mod the + * hash table size is supposed to roughly evenly distribute + * keys over the table's slots. + */ + +static unsigned int +dictionary__hash(char *s) +{ + unsigned int result = 0; + + if (!s) + return(result); + + while (s[0]) { + result <<= 1; + result += s[0]; + s++; + } + + return(result); +} + +/* + * TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary d, + * char *key): + * Effects: If key is not bound in d, returns 0. Othersize, + * returns a pointer to the binding that binds key. + * Note the access restrictions on bindings... + */ + +TYPE_T_dictionary_binding * +TYPE_T_dictionary_Lookup(TYPE_T_dictionary d, + char *key) +{ + TYPE_T_dictionary_binding *binding_ptr; + + binding_ptr = d->slots[dictionary__hash(key)%(d->size)]; + while (binding_ptr) { + if (string_Eq(key, binding_ptr->key)) + return(binding_ptr); + binding_ptr = binding_ptr->next; + } + + return(NULL); +} + +/* + * TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary d, + * char *key, + * int *already_existed): + * Modifies: d + * Effects: If key is bound in d, returns a pointer to the binding + * that binds key. Otherwise, adds a binding of key to + * d and returns its address. If already_existed is non-zero + * then *already_existed is set to 0 if key was not + * previously bound in d and 1 otherwise. + * Note the access restrictions on bindings... Note also + * that the value that key is bounded to if a binding is + * created is undefined. The caller should set the value + * in this case. + */ + +TYPE_T_dictionary_binding * +TYPE_T_dictionary_Define(TYPE_T_dictionary d, + char *key, + int *already_existed) +{ + TYPE_T_dictionary_binding **ptr_to_the_slot, *binding_ptr; + + ptr_to_the_slot = &(d->slots[dictionary__hash(key)%(d->size)]); + + binding_ptr = *ptr_to_the_slot; + while (binding_ptr) { + if (string_Eq(binding_ptr->key, key)) { + if (already_existed) + *already_existed = 1; + return(binding_ptr); + } + binding_ptr = binding_ptr->next; + } + + if (already_existed) + *already_existed = 0; + binding_ptr = (TYPE_T_dictionary_binding *)malloc( + sizeof(TYPE_T_dictionary_binding)); + binding_ptr->next = *ptr_to_the_slot; + binding_ptr->key = string_Copy(key); + *ptr_to_the_slot = binding_ptr; + return(binding_ptr); +} + +/* + * void TYPE_T_dictionary_Delete(TYPE_T_dictionary d, + * TYPE_T_dictionary_binding *b): + * Requires: *b is a binding in d. + * Modifies: d + * Effects: Removes the binding *b from d. Note that if + * b->value needs to be freed, it should be freed + * before making this call. + */ + +void TYPE_T_dictionary_Delete(TYPE_T_dictionary d, + TYPE_T_dictionary_binding *b) +{ + TYPE_T_dictionary_binding **ptr_to_binding_ptr; + + ptr_to_binding_ptr = &(d->slots[dictionary__hash(b->key)%(d->size)]); + + while (*ptr_to_binding_ptr != b) + ptr_to_binding_ptr = &((*ptr_to_binding_ptr)->next); + + *ptr_to_binding_ptr = b->next; + free(b->key); + free(b); +} diff --git a/zwgc/dictionary.h b/zwgc/dictionary.h new file mode 100644 index 0000000..d3f77be --- /dev/null +++ b/zwgc/dictionary.h @@ -0,0 +1,112 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef TYPE_T_dictionary_TYPE +#define TYPE_T_dictionary_TYPE + +typedef struct _TYPE_T_dictionary_binding { + struct _TYPE_T_dictionary_binding *next; /* PRIVATE */ + char *key; /* READ-ONLY */ + TYPE_T value; +} TYPE_T_dictionary_binding; + +typedef struct _TYPE_T_dictionary { /* PRIVATE */ + int size; + TYPE_T_dictionary_binding **slots; +} *TYPE_T_dictionary; + +/* + * TYPE_T_dictionary TYPE_T_dictionary_Create(int size): + * Requires: size > 0 + * Effects: Returns a new empty dictionary containing no bindings. + * The returned dictionary must be destroyed using + * TYPE_T_dictionary_Destroy. Size is a time vs space + * parameter. For this implementation, space used is + * proportional to size and time used is proportional + * to number of bindings divided by size. It is preferable + * that size is a prime number. + */ + +extern TYPE_T_dictionary TYPE_T_dictionary_Create(int); + +/* + * void TYPE_T_dictionary_Destroy(TYPE_T_dictionary d): + * Requires: d is a non-destroyed TYPE_T_dictionary + * Modifies: d + * Effects: Destroys dictionary d freeing up the space it consumes. + * Dictionary d should never be referenced again. Note that + * free is NOT called on the values of the bindings. If + * this is needed, the client must do this first using + * TYPE_T_dictionary_Enumerate. + */ + +extern void TYPE_T_dictionary_Destroy(TYPE_T_dictionary); + +/* + * void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary d; + * void (*proc)(TYPE_T_dictionary_binding *b)): + * Requires: proc is a void procedure taking 1 argument, a + * TYPE_T_dictionary_binding pointer, which does not + * make any calls using dictionary d. + * Effects: Calls proc once with each binding in dictionary d. + * Order of bindings passed is undefined. Note that + * only the value field of the binding should be considered + * writable by proc. + */ + +extern void TYPE_T_dictionary_Enumerate(TYPE_T_dictionary, void (*)(TYPE_T_dictionary_binding *)); + +/* + * TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary d, + * char *key): + * Effects: If key is not bound in d, returns 0. Othersize, + * returns a pointer to the binding that binds key. + * Note the access restrictions on bindings... + */ + +extern TYPE_T_dictionary_binding *TYPE_T_dictionary_Lookup(TYPE_T_dictionary, + char *); + +/* + * TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary d, + * char *key, + * int *already_existed): + * Modifies: d + * Effects: If key is bound in d, returns a pointer to the binding + * that binds key. Otherwise, adds a binding of key to + * d and returns its address. If already_existed is non-zero + * then *already_existed is set to 0 if key was not + * previously bound in d and 1 otherwise. + * Note the access restrictions on bindings... Note also + * that the value that key is bounded to if a binding is + * created is undefined. The caller should set the value + * in this case. + */ + +extern TYPE_T_dictionary_binding *TYPE_T_dictionary_Define(TYPE_T_dictionary, + char *, int *); + +/* + * void TYPE_T_dictionary_Delete(TYPE_T_dictionary d, + * TYPE_T_dictionary_binding *b): + * Requires: *b is a binding in d. + * Modifies: d + * Effects: Removes the binding *b from d. Note that if + * b->value needs to be freed, it should be freed + * before making this call. + */ + +extern void TYPE_T_dictionary_Delete(TYPE_T_dictionary, + TYPE_T_dictionary_binding *); + +#endif diff --git a/zwgc/error.c b/zwgc/error.c new file mode 100644 index 0000000..b8e78de --- /dev/null +++ b/zwgc/error.c @@ -0,0 +1,22 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_error_c[] = "$Id$"; +#endif + +#include + +int error_code; diff --git a/zwgc/error.h b/zwgc/error.h new file mode 100644 index 0000000..dfa0242 --- /dev/null +++ b/zwgc/error.h @@ -0,0 +1,59 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef error_MODULE +#define error_MODULE + +#include +#include +#include + +extern int error_code; + +#define FATAL_TRAP(function_call, message) \ + { error_code = (function_call);\ + if (error_code) {\ + com_err("zwgc", error_code,\ + message);\ + exit(3);\ + }\ + } + +#define TRAP(function_call, message) \ + { error_code = (function_call);\ + if (error_code) {\ + com_err("zwgc", error_code,\ + message);\ + }\ + } + +#define ERROR(a) { fprintf(stderr, "zwgc: "); \ + fprintf(stderr, a);\ + fflush(stderr); } + +#define ERROR2(a,b) { fprintf(stderr, "zwgc: "); \ + fprintf(stderr, a, b);\ + fflush(stderr); } + +#define ERROR3(a,b,c) { fprintf(stderr, "zwgc: "); \ + fprintf(stderr, a, b, c);\ + fflush(stderr); } + +#define ERROR4(a,b,c,d) { fprintf(stderr, "zwgc: "); \ + fprintf(stderr, a, b, c, d);\ + fflush(stderr); } + +#endif diff --git a/zwgc/eval.c b/zwgc/eval.c new file mode 100644 index 0000000..b33ea6d --- /dev/null +++ b/zwgc/eval.c @@ -0,0 +1,300 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_eval_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Code to evaluate an expression: */ +/* */ +/****************************************************************************/ + +#include +#include "new_memory.h" +#include "node.h" +#include "eval.h" +#include "substitute.h" +#include "port.h" +#include "buffer.h" +#include "regexp.h" +#include "formatter.h" +#include "text_operations.h" +#include "zwgc.h" +#include "variables.h" + +/****************************************************************************/ +/* */ +/* Code to deal with string/boolean conversion: */ +/* */ +/****************************************************************************/ + +/* + * Internal Routine: + * + * int string_to_bool(string str) + * Effects: Returns true iff the string str represents true. + * True is represented by any string which is equal to + * "true" when case is disregraded. + */ + +#define string_to_bool(str) (!strcasecmp(str,"true")) + +/* + * Internal Routine: + * + * string bool_to_string(int bool) + * Effects: Returns a string representive for the C boolean bool. + * (In C, true == non-zero) I.e., + * string_to_bool(bool_to_string(x)) == !!x. + * The string returned is on the heap & must be freed + * eventually. + */ + +static string +bool_to_string(int bool) +{ + return(bool ? string_Copy("TRUE") : string_Copy("FALSE")); +} + +/* + * int eval_bool_expr(Node *expr) + * Modifies: dict + * Requires: expr is a proper expression or NULL. (see node.c) + * Effects: Evaluates expr to its boolean value which is returned. + * NULL is defined to have the boolean value true. + */ + +int +eval_bool_expr(Node *expr) +{ + string temp; + int result; + + if (!expr) + return(1); + + temp = eval_expr(expr); + result = string_to_bool(temp); + free(temp); + + return(result); +} + +/****************************************************************************/ +/* */ +/* Code to evaluate an expression: */ +/* */ +/****************************************************************************/ + +/* + * string eval_expr(Node *expr) + * Modifies: dict + * Requires: expr is a proper expression (NOT NULL). (see node.c) + * Effects: Evaluates expr to its string value which is returned. + * The returned string is on the heap and must be freed + * eventually. + */ + +string +eval_expr(Node *expr) +{ + int opcode = expr->opcode; + int bool_result = 0; + string first, second; + char *result = NULL; + string *text_ptr; + + /* + * Dispatch based on the opcode of the top node in the expression: + */ + switch (opcode) { + case STRING_CONSTANT_OPCODE: + return(string_Copy(expr->d.string_constant)); + + case VARREF_OPCODE: + return(string_Copy(var_get_variable(expr->d.string_constant))); + + case BUFFER_OPCODE: + return(string_Copy(buffer_to_string())); + + /* + * Handle unary expressions: + */ + case NOT_OPCODE: + case SUBSTITUTE_OPCODE: + case PROTECT_OPCODE: + case VERBATIM_OPCODE: + case STYLESTRIP_OPCODE: + case GETENV_OPCODE: + case UPCASE_OPCODE: + case DOWNCASE_OPCODE: + case ZVAR_OPCODE: + case GET_OPCODE: + first = eval_expr(expr->d.nodes.first); + + switch (opcode) { + case NOT_OPCODE: + result = bool_to_string(! string_to_bool(first)); + break; + + case SUBSTITUTE_OPCODE: + result = substitute(var_get_variable, first); + break; + + case PROTECT_OPCODE: + result=protect(first); + break; + + case VERBATIM_OPCODE: + return(verbatim(first,0)); + + case STYLESTRIP_OPCODE: + return(stylestrip(first)); + + case GETENV_OPCODE: + result = getenv(first); + if (!result) + result = string_Copy(""); + else + result = string_Copy(result); + break; + + case UPCASE_OPCODE: + return(string_Upcase(first)); + + case DOWNCASE_OPCODE: + return(string_Downcase(first)); + + case ZVAR_OPCODE: + result = ZGetVariable(first); + if (!result) + result = string_Copy(""); + else + result = string_Copy(result); + break; + + case GET_OPCODE: + result = read_from_port(first); + break; + } + free(first); + break; + + /* + * Handle binary operators: + */ + case PLUS_OPCODE: + case AND_OPCODE: + case OR_OPCODE: + case EQ_OPCODE: + case NEQ_OPCODE: + case REGEQ_OPCODE: + case REGNEQ_OPCODE: + first = eval_expr(expr->d.nodes.first); + second = eval_expr(expr->d.nodes.second); + + switch (opcode) { + case PLUS_OPCODE: + result = string_Concat(first, second); + free(first); + free(second); + return(result); + + case AND_OPCODE: + bool_result = string_to_bool(first) && string_to_bool(second); + break; + + case OR_OPCODE: + bool_result = string_to_bool(first) || string_to_bool(second); + break; + + case EQ_OPCODE: + bool_result = string_Eq(first, second); + break; + + case NEQ_OPCODE: + bool_result = string_Neq(first, second); + break; + + case REGEQ_OPCODE: + bool_result = ed_regexp_match_p(first, second); + break; + + case REGNEQ_OPCODE: + bool_result = !ed_regexp_match_p(first, second); + break; + } + free(first); + free(second); + result = bool_to_string(bool_result); + break; + + /* + * Handle text-manipulation operators: + */ + case LANY_OPCODE: case RANY_OPCODE: + case LBREAK_OPCODE: case RBREAK_OPCODE: + case LSPAN_OPCODE: case RSPAN_OPCODE: + first = eval_expr(expr->d.nodes.first); + second = eval_expr(expr->d.nodes.second); + text_ptr = &first; + + switch (opcode) { + case LANY_OPCODE: + result = lany(text_ptr, second); + break; + + case RANY_OPCODE: + result = rany(text_ptr, second); + break; + + case LBREAK_OPCODE: + result = lbreak(text_ptr, string_to_character_class(second)); + break; + + case RBREAK_OPCODE: + result = rbreak(text_ptr, string_to_character_class(second)); + break; + + case LSPAN_OPCODE: + result = lspan(text_ptr, string_to_character_class(second)); + break; + + case RSPAN_OPCODE: + result = rspan(text_ptr, string_to_character_class(second)); + break; + } + + if (expr->d.nodes.first->opcode == VARREF_OPCODE) + var_set_variable(expr->d.nodes.first->d.string_constant, first); + free(first); + free(second); + break; + +#ifdef DEBUG + default: + printf("zwgc: internal error: attempt to evaluate the following non-expression:\n"); fflush(stdout); + node_display(expr); + printf("\n\n"); + exit(2); +#endif + } + + return(result); +} diff --git a/zwgc/eval.h b/zwgc/eval.h new file mode 100644 index 0000000..427f713 --- /dev/null +++ b/zwgc/eval.h @@ -0,0 +1,43 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef eval_MODULE +#define eval_MODULE + +#include "new_string.h" + +/* + * string eval_expr(Node *expr) + * Modifies: dict + * Requires: expr is a proper expression (NOT NULL). (see node.c) + * Effects: Evaluates expr to its string value which is returned. + * The returned string is on the heap and must be freed + * eventually. + */ + +extern string eval_expr(Node *); + +/* + * int eval_bool_expr(Node *expr) + * Modifies: dict + * Requires: expr is a proper expression or NULL. (see node.c) + * Effects: Evaluates expr to its boolean value which is returned. + * NULL is defined to have the boolean value true. + */ + +extern int eval_bool_expr(Node *); + +#endif diff --git a/zwgc/exec.c b/zwgc/exec.c new file mode 100644 index 0000000..36d22c0 --- /dev/null +++ b/zwgc/exec.c @@ -0,0 +1,482 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_exec_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Module containing code to execute a program: */ +/* */ +/****************************************************************************/ + +#include +#include "new_memory.h" +#include "node.h" +#include "exec.h" +#include "eval.h" +#include "buffer.h" +#include "port.h" +#include "variables.h" +#include "notice.h" +#ifdef CMU_ZWGCPLUS +#include "plus.h" +#endif + +static int exec_subtree(Node *); +static int exec_fields(Node *); + +/****************************************************************************/ +/* */ +/* Utility subroutines: */ +/* */ +/****************************************************************************/ + +static string +eval_exprlist_to_string(Node *exprlist) +{ + string result = string_Copy(""); + string temp; + int first_time = 1; + + for (; exprlist; exprlist=exprlist->next) { + if (!first_time) + result = string_Concat2(result, " "); + else + first_time = 0; + + temp = eval_expr(exprlist); + result = string_Concat2(result, temp); + free(temp); + } + + return(result); +} + +static char ** +eval_exprlist_to_args(Node *exprlist) +{ + char **result = (char **)malloc(sizeof(char *)); + int argc = 0; + + for (; exprlist; exprlist=exprlist->next) { + result[argc] = eval_expr(exprlist); + argc++; + result = (char **)realloc(result, (argc+1)*sizeof(char *)); + } + + result[argc] = NULL; + return(result); +} + +static void +free_args(char **args) +{ + char **p; + + for (p=args; *p; p++) { + free(*p); + } + + free(args); +} + +/****************************************************************************/ +/* */ +/* Subroutines to handle each particular statement type: */ +/* */ +/****************************************************************************/ + +#define NOBREAK 0 +#define BREAK 1 +#define EXIT 2 + +/*ARGSUSED*/ +static int +exec_noop(Node *node) +{ + return(NOBREAK); +} + +/*ARGSUSED*/ +static int +exec_break(Node *node) +{ + return(BREAK); +} + +/*ARGSUSED*/ +static int +exec_exit(Node *node) +{ + return(EXIT); +} + +static int +exec_set(Node *node) +{ + var_set_variable_then_free_value(node->d.nodes.first->d.string_constant, + eval_expr(node->d.nodes.second)); + + return(NOBREAK); +} + +static int +exec_execport(Node *node) +{ + string name = eval_expr(node->d.nodes.first); + char **argv = eval_exprlist_to_args(node->d.nodes.second); + + create_subprocess_port(name, argv); + + free(name); + free_args(argv); + return(NOBREAK); +} + +static int +exec_appendport(Node *node) +{ + string name, filename; + + name = eval_expr(node->d.nodes.first); + filename = eval_expr(node->d.nodes.second); + + create_file_append_port(name, filename); + + free(name); + free(filename); + return(NOBREAK); +} + +static int +exec_inputport(Node *node) +{ + string name, filename; + + name = eval_expr(node->d.nodes.first); + filename = eval_expr(node->d.nodes.second); + + create_file_input_port(name, filename); + + free(name); + free(filename); + return(NOBREAK); +} + +static int +exec_outputport(Node *node) +{ + string name, filename; + + name = eval_expr(node->d.nodes.first); + filename = eval_expr(node->d.nodes.second); + + create_file_output_port(name, filename); + + free(name); + free(filename); + return(NOBREAK); +} + +static int +exec_closeinput(Node *node) +{ + string name; + + name = eval_expr(node->d.nodes.first); + close_port_input(name); + + free(name); + return(NOBREAK); +} + +static int +exec_closeoutput(Node *node) +{ + string name; + + name = eval_expr(node->d.nodes.first); + close_port_output(name); + + free(name); + return(NOBREAK); +} + +static int +exec_closeport(Node *node) +{ + string name; + + name = eval_expr(node->d.nodes.first); + close_port_input(name); + close_port_output(name); + + free(name); + return(NOBREAK); +} + +static int +exec_put(Node *node) +{ + string name, temp; + + if (node->d.nodes.second) + temp = eval_exprlist_to_string(node->d.nodes.second); + else + temp = string_Copy(buffer_to_string()); + + if (node->d.nodes.first) { + name = eval_expr(node->d.nodes.first); + + write_on_port(name, temp, strlen(temp)); + free(name); + } else + write_on_port(var_get_variable("output_driver"), temp, strlen(temp)); + + free(temp); + return(NOBREAK); +} + +static int +exec_print(Node *node) +{ + string temp; + + temp = eval_exprlist_to_string(node->d.nodes.first); + append_buffer(temp); + free(temp); + + return(NOBREAK); +} + +/*ARGSUSED*/ +static int +exec_clearbuf(Node *node) +{ + clear_buffer(); + + return(NOBREAK); +} + +static int +exec_case(Node *node) +{ + string constant,temp; + Node *match, *cond; + int equal_p; + + constant = string_Downcase(eval_expr(node->d.nodes.first)); + + for (match=node->d.nodes.second; match; match=match->next) { + cond = match->d.nodes.first; + if (!cond) { /* default case */ + free(constant); + return(exec_subtree(match->d.nodes.second)); + } + for (; cond; cond=cond->next) { + temp = string_Downcase(eval_expr(cond)); + equal_p = string_Eq(constant, temp); + free(temp); + if (equal_p) { + free(constant); + return(exec_subtree(match->d.nodes.second)); + } + } + } + + free(constant); + return(NOBREAK); +} + +static int +exec_while(Node *node) +{ + int continue_code = NOBREAK; + + while (eval_bool_expr(node->d.nodes.first)) { + continue_code = exec_subtree(node->d.nodes.second); + if (continue_code != NOBREAK) + break; + } + + if (continue_code == BREAK) + continue_code = NOBREAK; + + return(continue_code); +} + +static int +exec_if(Node *node) +{ + Node *conds; + + for (conds=node->d.nodes.first; conds; conds=conds->next) + if (eval_bool_expr(conds->d.nodes.first)) + return(exec_subtree(conds->d.nodes.second)); + + return(NOBREAK); +} + +static int +exec_exec(Node *node) +{ + int pid; + char **argv = eval_exprlist_to_args(node->d.nodes.first); + + pid = fork(); + if (pid == -1) { + fprintf(stderr, "zwgc: error while attempting to fork: "); + perror(""); + } else if (pid == 0) { /* in child */ + execvp(argv[0], argv); + fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]); + perror(""); + _exit(errno); + } + + free_args(argv); + return(NOBREAK); +} + +static struct _Opstuff { + int (*exec)(Node *); +} const opstuff[] = { + { exec_noop }, /* string_constant */ + { exec_noop }, /* varref */ + { exec_noop }, /* varname */ + { exec_noop }, /* not */ + { exec_noop }, /* plus */ + { exec_noop }, /* and */ + { exec_noop }, /* or */ + { exec_noop }, /* eq */ + { exec_noop }, /* neq */ + { exec_noop }, /* regeq */ + { exec_noop }, /* regneq */ + { exec_noop }, /* buffer */ + { exec_noop }, /* substitute */ + { exec_noop }, /* protect */ + { exec_noop }, /* verbatim */ + { exec_noop }, /* stylestrip */ + { exec_noop }, /* getenv */ + { exec_noop }, /* upcase */ + { exec_noop }, /* downcase */ + { exec_noop }, /* zvar */ + { exec_noop }, /* get */ + { exec_noop }, /* lany */ + { exec_noop }, /* rany */ + { exec_noop }, /* lbreak */ + { exec_noop }, /* rbreak */ + { exec_noop }, /* lspan */ + { exec_noop }, /* rspan */ + + { exec_noop }, /* noop statement */ + { exec_set }, + { exec_fields }, + + { exec_print }, + { exec_clearbuf }, + + { exec_appendport }, + { exec_execport }, + { exec_inputport }, + { exec_outputport }, + { exec_put }, + { exec_closeinput }, + { exec_closeoutput }, + { exec_closeport }, + + { exec_exec }, + + { exec_if }, + { exec_case }, + { exec_while }, + { exec_break }, + { exec_exit }, + + { exec_noop }, /* if */ + { exec_noop }, /* elseif */ + { exec_noop }, /* else */ + { exec_noop }, /* matchlist */ + { exec_noop }, /* default */ +}; + +static int +exec_subtree(Node *node) +{ + int retval = NOBREAK; + + for (; node; node=node->next) { + retval = (opstuff[node->opcode].exec)(node); + if (retval != NOBREAK) + return(retval); + } + + return(NOBREAK); +} + +/***************************************************************************/ + +static char *notice_fields; +static int notice_fields_length = 0; +static int number_of_fields = 0; + +static int +exec_fields(Node *node) +{ + for (node=node->d.nodes.first; node; node=node->next) { + var_set_variable_then_free_value(node->d.string_constant, + get_next_field(¬ice_fields, + ¬ice_fields_length)); + if (number_of_fields) + number_of_fields--; + } + + var_set_variable_to_number("number_of_fields", number_of_fields); + + return(NOBREAK); +} + +void +exec_process_packet(Node *program, + ZNotice_t *notice) +{ +#ifdef CMU_ZWGCPLUS + set_stored_notice(notice); +#endif + + notice_fields = notice->z_message; + notice_fields_length = notice->z_message_len; + + var_set_number_variables_to_fields(notice_fields, notice_fields_length); + + number_of_fields = count_nulls(notice_fields, notice_fields_length)+1; + /* workaround for bug in old zwrite */ + if (notice_fields[notice_fields_length-1] == '\0') + number_of_fields--; + var_set_variable_to_number("number_of_fields", number_of_fields); + + clear_buffer(); + (void)exec_subtree(program); + +#ifdef CMU_ZWGCPLUS + plus_queue_notice(notice); + plus_window_deletions(notice); /* OOPS */ + set_stored_notice(NULL); +#endif +} diff --git a/zwgc/exec.h b/zwgc/exec.h new file mode 100644 index 0000000..db691dd --- /dev/null +++ b/zwgc/exec.h @@ -0,0 +1,22 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef exec_MODULE +#define exec_MODULE + +extern void exec_process_packet(Node *, ZNotice_t *); + +#endif diff --git a/zwgc/file.c b/zwgc/file.c new file mode 100644 index 0000000..8d5bdd0 --- /dev/null +++ b/zwgc/file.c @@ -0,0 +1,119 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_file_c[] = "$Id$"; +#endif + +#include + +#include +#include "new_memory.h" +#include "new_string.h" +#include "error.h" +#include "file.h" + +/* + * char *get_home_directory() + * + * Effects: Attempts to locate the user's (by user, the owner of this + * process is meant) home directory & return its pathname. + * Returns NULL if unable to do so. Does so by first checking + * the environment variable HOME. If it is unset, falls back + * on the user's password entry. + * Note: The returned pointer may point to a static buffer & hence + * go away on further calls to getenv, get_home_directory, + * getpwuid, or related calls. The caller should copy it + * if necessary. + */ + +static char +*get_home_directory(void) +{ + char *result; + struct passwd *passwd_entry; + + result = getenv("HOME"); + if (result) + return(result); + + if (!(passwd_entry = getpwuid(getuid()))) + return(NULL); + + return(passwd_entry->pw_dir); +} + +/* + * + */ + +FILE *locate_file(char *override_filename, + char *home_dir_filename, + char *fallback_filename) +{ + char *filename; + FILE *result; + + errno = 0; + + if (override_filename) { + if (string_Eq(override_filename, "-")) + return(stdin); + + result = fopen(override_filename, "r"); + if (!(result = fopen(override_filename, "r"))) { + /* <<<>>> */ + fprintf(stderr, "zwgc: error while opening %s for reading: ", + override_filename); + perror(""); + } + return(result); + } + + if (home_dir_filename) { + filename = get_home_directory(); + if (filename) { + filename = string_Concat(filename, "/"); + filename = string_Concat2(filename, home_dir_filename); + result = fopen(filename, "r"); + if (result) { + free(filename); + return(result); + } + if (errno != ENOENT) { + /* <<<>>> */ + fprintf(stderr, "zwgc: error while opening %s for reading: ", + filename); + perror(""); + free(filename); + return(result); + } + free(filename); + } else + ERROR("unable to find your home directory.\n"); + } + + if (fallback_filename) { + if (!(result = fopen(fallback_filename, "r"))) { + /* <<<>>> */ + fprintf(stderr, "zwgc: error while opening %s for reading: ", + fallback_filename); + perror(""); + } + return(result); + } + + return(NULL); +} diff --git a/zwgc/file.h b/zwgc/file.h new file mode 100644 index 0000000..3f185bf --- /dev/null +++ b/zwgc/file.h @@ -0,0 +1,24 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef file_MODULE +#define file_MODULE + +#include + +extern FILE *locate_file(char *, char *, char *); + +#endif diff --git a/zwgc/formatter.c b/zwgc/formatter.c new file mode 100644 index 0000000..65ac5c3 --- /dev/null +++ b/zwgc/formatter.c @@ -0,0 +1,562 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_formatter_c[] = "$Id$"; +#endif + +#include +#include + +#include "new_memory.h" +#include "char_stack.h" +#include "string_dictionary.h" +#include "formatter.h" +#include "text_operations.h" + +#if !defined(__STDC__) && !defined(const) +#define const +#endif + +static int pure_text_length(char *, char); +static int env_length(char *); + +#ifdef notdef +static character_class atsign_set = { /* '@' = 0x40 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; +#endif + +static const character_class paren_set = { /* '(' = 0x28, ')' = 0x29 */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + +static const character_class sbracket_set = { /* '[' = 0x5b, ']' = 0x5d */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + +static const character_class abracket_set = { /* '<' = 0x3c, '>' = 0x3e */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + +static const character_class cbracket_set = { /* '{' = 0x7b, '}' = 0x7d */ + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + +static const character_class allbracket_set = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + +static const character_class allmaskable_set = { + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0, + 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + }; + +static char brackets[]="()<>[]{}@"; +static char *openbracket[]={"@<","@<","@[","@[","@{","@{","@(","@(","@("}; +static char *closebracket[]={">",">","]","]","}","}",")",")",")"}; + +static int +not_contains(string str, + const character_class set) +{ + while (*str && ! set[(int)*str]) str++; + return (! *str); +} + +static int +pure_text_length(char *text, + char terminator) +{ + int len=0; + + while (1) { + while (*text!='@' && *text!=terminator && *text) { + text++; + len++; + } + + if (*text!='@') + return(len); + + if (*(text+1)=='@') { + text++; + len++; + } else if (env_length(text+1) != -1) + return(len); + + text++; + len++; + } +} + +static char +otherside(char opener) +{ + switch (opener) { + case '(': + return(')'); + case '{': + return('}'); + case '[': + return(']'); + case '<': + return('>'); + } + +#ifdef DEBUG + abort(); +#endif + return 0; +} + +/* the char * that str points to is free'd by this function. + * if you want to keep it, save it yourself + */ +string +verbatim(string str, int bracketsonly) +{ + char *temp,*temp2; + int bracketnum,len; + + len = strlen(str); + if (len == pure_text_length(str,0)) { + /* No environments, so consider the fast-and-easy methods */ + + if (not_contains(str,allbracket_set)) { + temp = string_Copy(str); + free(str); + return(temp); + } + + if (not_contains(str,abracket_set)) { + temp=(char *) malloc((len=strlen(str))+4); + temp[0]='@'; + temp[1]='<'; + (void) memcpy(temp+2,str,len); + temp[len+2]='>'; + temp[len+3]='\0'; + free(str); + return(temp); + } + if (not_contains(str,sbracket_set)) { + temp=(char *) malloc((len=strlen(str))+4); + temp[0]='@'; + temp[1]='['; + (void) memcpy(temp+2,str,len); + temp[len+2]=']'; + temp[len+3]='\0'; + free(str); + return(temp); + } + if (not_contains(str,cbracket_set)) { + temp=(char *) malloc((len=strlen(str))+4); + temp[0]='@'; + temp[1]='{'; + (void) memcpy(temp+2,str,len); + temp[len+2]='}'; + temp[len+3]='\0'; + free(str); + return(temp); + } + if (not_contains(str,paren_set)) { + temp=(char *) malloc((len=strlen(str))+4); + temp[0]='@'; + temp[1]='('; + (void) memcpy(temp+2,str,len); + temp[len+2]=')'; + temp[len+3]='\0'; + free(str); + return(temp); + } + } + + temp=lbreak(&str,bracketsonly?allbracket_set:allmaskable_set); + while(*str) { + bracketnum=(int) (strchr(brackets,str[0])-brackets); + temp=string_Concat2(temp,openbracket[bracketnum]); + temp=string_Concat2(temp,temp2=lany(&str," ")); + free(temp2); + temp=string_Concat2(temp,closebracket[bracketnum]); + temp=string_Concat2(temp,temp2=lbreak(&str,bracketsonly? + allbracket_set:allmaskable_set)); + free(temp2); + } + free(str); /* str is "" at this point, anyway */ + + return(temp); +} + +/* text points to beginning of text string. return value is + length of string, up to but not including the passed terminator + or the default terminator \0. The text will not be modified, + and @@ will be counted twice */ + +string +protect(string str) +{ + string temp,temp2,temp3; + int len,templen; + char_stack chs; + char tos; + + temp = string_Copy(""); + templen = 1; + chs = char_stack_create(); + + while(*str) { + tos = (char_stack_empty(chs)?0:char_stack_top(chs)); + + if (*str == tos) { + /* if the character is the next terminator */ + + temp = (char *) realloc(temp,++templen); + temp[templen-2] = *str++; + char_stack_pop(chs); + temp[templen-1] = '\0'; + } else if ((len = pure_text_length(str,tos))) { + if (tos) { + /* if the block is text in an environment, just copy it */ + + temp2 = string_CreateFromData(str,len); + str += len; + temp = string_Concat2(temp,temp2); + templen += len; + free(temp2); + } else { + /* if the block is top level text, verbatim brackets only + (not @'s) and add text to temp */ + + temp2 = string_CreateFromData(str,len); + str += len; + temp3 = verbatim(temp2,1); + temp = string_Concat2(temp,temp3); + templen += strlen(temp3); + free(temp3); + } + } else { + /* if the block is an environment, copy it, push delimiter */ + + len = env_length(str+1); + char_stack_push(chs,otherside(str[len+1])); + len += 2; + temp2 = string_CreateFromData(str,len); + str += len; + temp = string_Concat2(temp,temp2); + templen += len; + free(temp2); + } + } + /* all blocks have been copied. */ + + while (!char_stack_empty(chs)) { + temp = (char *) realloc(temp,++templen); + temp[templen-2] = char_stack_top(chs); + char_stack_pop(chs); + } + temp[templen-1] = '\0'; + + return(temp); +} + +/* str points to a string. return value is another string + which is the original with all styles removed. */ +string +stylestrip(string str) +{ + int templen = 0, otherchar; + char *temp = (char *) malloc(string_Length(str) + 1); + char_stack chs; + string ostr = str; + + chs = char_stack_create(); + + while (*str) { + if (*str == '@') { + int len = env_length(str + 1); + if (len != -1) { + otherchar = 0; + if ((len == 4 && !strncasecmp(str + 1, "font", 4)) + || (len == 5 && !strncasecmp(str + 1, "color", 5))) + otherchar = 0x80; + otherchar |= otherside(str[len + 1]); + char_stack_push(chs, otherchar); + str += len + 2; + continue; + } + } + if (!char_stack_empty(chs) && *str == (char_stack_top(chs) & 0x7f)) { + char_stack_pop(chs); + str++; + continue; + } + if (!char_stack_empty(chs) && (char_stack_top(chs) & 0x80)) + str++; + else + temp[templen++] = *str++; + } + temp[templen] = 0; + + while (!char_stack_empty(chs)) + char_stack_pop(chs); + free(ostr); + + return(temp); +} + +void +free_desc(desctype *desc) +{ + desctype *next_desc; + + while (desc->code != DT_EOF) { + next_desc = desc->next; + free(desc); + desc = next_desc; + } + free(desc); +} + +/* text points to beginning of possible env name. return value is + length of env name, not including @ or opener, or -1 if not a + possible env name. */ +static int +env_length(char *text) +{ + int len=0; + + while (*text && (isalnum(*text) || *text=='_')) { + text++; + len++; + } + + if ((*text=='(') || (*text=='{') || (*text=='[') || (*text=='<')) + return(len); + else + return(-1); +} + +/* text points to beginning of text string. return value is + length of string, up to but not including the passed terminator + or the default terminators \0 \n @. This can modify text, and 0 + is a valid return value. */ +static int +text_length(char *text, + char terminator) +{ + int len=0; + + while (1) { + while (*text!='@' && *text!='\n' && *text!=terminator && *text) { + text++; + len++; + } + + if (*text!='@') + return(len); + + if (*(text+1)=='@') + (void) memmove(text+1,text+2,strlen(text+1)); + else if (env_length(text+1) != -1) + return(len); + + text++; + len++; + } +} + +/* parses str into a desc linked list. Returns number of strings and + newlines in *pstr and *pnl */ + +desctype * +disp_get_cmds(char *str, + int *pstr, + int *pnl) +{ + desctype *desc,*here; + int len; + char_stack terminators = char_stack_create(); + char terminator; + int nstr=0, nnl=0; + char *curstr; + + desc=(desctype *) malloc(sizeof(desctype)); + here=desc; + curstr=str; + terminator = '\0'; + + while (*curstr) { + if (*curstr=='\n') { + here->code=DT_NL; + curstr++; + nnl++; + } else if (*curstr==terminator) { /* if this is the end of an env */ + here->code=DT_END; + terminator = char_stack_top(terminators); + char_stack_pop(terminators); + curstr++; + } else if ((len=text_length(curstr, terminator))) { /* if there is a text + block here */ + here->code=DT_STR; + here->str=curstr; + here->len=len; + curstr+=len; + nstr++; + } else if (*curstr=='@') { /* if this is the beginning of an env */ + len=env_length(curstr+1); + here->code=DT_ENV; + here->str=curstr+1; + here->len=len; + char_stack_push(terminators, terminator); + terminator=otherside(*(curstr+1+len)); + curstr+=(len+2); /* jump over @, env name, and opener */ + } + + here->next=(desctype *) malloc(sizeof(desctype)); + here=here->next; + } + + while (!char_stack_empty(terminators)) { + here->code=DT_END; + terminator = char_stack_top(terminators); + char_stack_pop(terminators); + here->next=(desctype *) malloc(sizeof(desctype)); + here=here->next; + } + here->code=DT_EOF; + *pstr=nstr; + *pnl=nnl; + +#ifdef DEBUG_PRINTOUT + { string temp; + here = desc; + while (here->code != DT_EOF) { + if (here->code == DT_STR || here->code == DT_ENV) { + temp = string_CreateFromData(here->str, here->len); + printf("[%d <%s>]\n", here->code, temp); + free(temp); + } else + printf("[%d]\n", here->code); + here=here->next; + } + } +#endif + + return(desc); +} diff --git a/zwgc/formatter.h b/zwgc/formatter.h new file mode 100644 index 0000000..d2cf0f0 --- /dev/null +++ b/zwgc/formatter.h @@ -0,0 +1,43 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#include "new_string.h" + +#ifndef formatter_MODULE +#define formatter_MODULE + +typedef struct _desctype { + struct _desctype *next; + + short int code; +#define DT_EOF 0 /* End of message. */ +#define DT_ENV 1 /* Open environment. */ +#define DT_STR 2 /* Display string. */ +#define DT_END 3 /* Close environment. */ +#define DT_NL 4 /* Newline. */ + + char *str; /* Name of environment, string to be displayed. */ + int len; /* Length of string/environment name for + ENV, STR, END. Undefined for EOF */ +} desctype; + +extern desctype *disp_get_cmds(char *, int *, int *); +extern void free_desc(desctype *); + +extern string protect(string); +extern string verbatim(string, int); +extern string stylestrip(string); +#endif diff --git a/zwgc/instantiate b/zwgc/instantiate new file mode 100755 index 0000000..dae134d --- /dev/null +++ b/zwgc/instantiate @@ -0,0 +1,39 @@ +#!/bin/sh - + +# This file is part of the Project Athena Zephyr Notification System. +# It is one of the source files comprising zwgc, the Zephyr WindowGram +# client. +# +# $Id$ +# +# Copyright (c) 1989,1993 by the Massachusetts Institute of Technology. +# For copying and distribution information, see the file +# "mit-copyright.h". +# + +if [ "$1" = "" ]; then + echo "Usage: generate_instance []" + exit 1 +fi + +source=$1 +type=$2 +name=$3 +incfile=$4 + +if [ "$type" != "stack" ]; then + if [ ! -f ${source}/${type}.c ]; then + echo "$0: unable to open ${source}/${type}.c" + exit 2 + fi + sed "s/TYPE_T/$name/g" ${source}/${type}.c > ${name}_${type}.c +fi + +if [ "$incfile" != "" ]; then + echo "#include \"$incfile\"" > ${name}_${type}.h +fi +if [ ! -f ${source}/${type}.h ]; then + echo "$0: unable to open ${source}/${type}.h" + exit 2 +fi +sed "s/TYPE_T/$name/g" ${source}/${type}.h >> ${name}_${type}.h diff --git a/zwgc/lexer.c b/zwgc/lexer.c new file mode 100644 index 0000000..f59cdb8 --- /dev/null +++ b/zwgc/lexer.c @@ -0,0 +1,673 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_lexer_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* The lexer for the zwgc description language: */ +/* */ +/****************************************************************************/ + +#include "new_memory.h" +#include "new_string.h" +#include "int_dictionary.h" +#include "lexer.h" +#include "parser.h" +#include "y.tab.h" + +/* + * yylineno - this holds the current line # we are on. Updated automatically + * by input() and unput(). + */ + +int yylineno; + +/* + * keyword_dict - this dictionary maps keyword names to their token numbers. + */ + +static int_dictionary keyword_dict = NULL; + +/****************************************************************************/ +/* */ +/* I/O functions: */ +/* */ +/****************************************************************************/ + +/* + * input_file - this holds the FILE pointer to the file currently being lexed. + */ + +static FILE *input_file; + +/* + * pushback - if not -1, holds a character that was pushed back by unput but + * not yet read by input. + */ + +static int pushback = -1; + +static char +input(void) +{ + int c; + + if (pushback != -1) { + c = pushback; + pushback = -1; + if (c=='\n') + yylineno++; + return(c); + } + + c = getc(input_file); + if (c=='\n') + yylineno++; + if (c==EOF) + c = 0; + + return(c); +} + +static void +unput(int c) +{ +#ifdef DEBUG + if (pushback != -1) { + printf("Attempt to push back 2 characters at one time!\n"); + exit(1); + } +#endif + + pushback = c; + if (c == '\n') + yylineno--; +} + +/****************************************************************************/ +/* */ +/* Initialization routines: */ +/* */ +/****************************************************************************/ + +struct keyword_info { + string keyword; + int keyword_number; +}; + +/* + * keywords - This table holds a copy of the mapping from keyword name to + * token number and is used to initialize keyword_dict: + */ + +static struct keyword_info keywords[] = { + { "and", '&' }, + { "appendport", APPENDPORT }, + { "buffer", BUFFER }, + { "break", BREAK }, + { "closeinput", CLOSEINPUT }, + { "closeoutput", CLOSEOUTPUT }, + { "closeport", CLOSEPORT }, + { "case", CASE }, + { "clearbuf", CLEARBUF }, + { "default", DEFAULT }, + { "do", DO }, + { "downcase", DOWNCASE }, + { "else", ELSE }, + { "elseif", ELSEIF }, + { "endcase", ENDCASE }, + { "endif", ENDIF }, + { "endwhile", ENDWHILE }, + { "exec", EXEC }, + { "execport", EXECPORT }, + { "exit", EXIT }, + { "fields", FIELDS }, + { "get", GET }, + { "getenv", GETENV }, + { "if", IF }, + { "inputport", INPUTPORT }, + { "lany", LANY }, + { "lbreak", LBREAK }, + { "lspan", LSPAN }, + { "match", MATCH }, + { "noop", NOOP }, + { "not", '!' }, + { "or", '|' }, + { "outputport", OUTPUTPORT }, + { "print", PRINT }, + { "protect", PROTECT }, + { "put", PUT }, + { "rany", RANY }, + { "rbreak", RBREAK }, + { "rspan", RSPAN }, + { "set", SET }, + { "show", SHOW }, + { "stylestrip", STYLESTRIP }, + { "substitute", SUBSTITUTE }, + { "then", THEN }, + { "upcase", UPCASE }, + { "while", WHILE }, + { "verbatim", VERBATIM }, + { "zvar", ZVAR } }; + +/* + * lex_open - this routine [re]initializes the lexer & prepares it to lex + * a file. Resets current line # to 1. + */ + +void +lex_open(FILE *file) +{ + /* + * Initialize I/O: + */ + input_file = file; + yylineno = 1; + pushback = -1; + + /* + * Initialize keyword_dict from keywords if needed: + */ + if (!keyword_dict) { + unsigned int i; + + keyword_dict = int_dictionary_Create(101); + + for (i=0; ivalue = keywords[i].keyword_number; + } +} + +/****************************************************************************/ +/* */ +/* lex subroutines: */ +/* */ +/****************************************************************************/ + +/* + * eat_escape_code - this rountine eats an escape code & returns the character + * it codes for or 0 if it codes for "". + * (an escape code is what follows a '\\' in a quoted + * string) Current escape codes are: + * + * "n" == '\n' + * "t" == '\t' + * "b" == '\b' + * "\n" == "" (i.e., returns 0) + * == "" + * [0-7]{1,3} == the character represented by the code + * interpreted as an octal number. + * [^ntb0-7\n] == the same character. I.e., "*" == '*' + */ + +#define is_octal_digit(c) (((c)>='0') && ((c)<='7')) + +static char +eat_escape_code(void) +{ + int c, coded_char; + + c = input(); + + switch (c) { + case 0: /* i.e., EOF */ + unput(c); + return(c); + case '\n': + return(0); + case 'n': + return('\n'); + case 't': + return('\t'); + case 'b': + return('\b'); + case '0': case '1': case '2': case '3': + case '4': case '5': case '6': case '7': + coded_char = c - '0'; + c = input(); + if (!is_octal_digit(c)) { + unput(c); + return(coded_char); + } + coded_char = coded_char*8 + c-'0'; + c = input(); + if (!is_octal_digit(c)) { + unput(c); + return(coded_char); + } + return(coded_char*8 + c-'0'); + default: + return(c); + } +} + +/* + * eat_string - this routine eats characters allowing escape codes via '\\' + * until a '"' is eaten. If no '"' is seen before a '\n' or + * the , a parse_error is set & 0 is returned. Otherwise, + * the string represented by what has been eaten is returned. + * I.e., 'hello \n there"' would cause "hello \n there" to be + * returned. (thats not a in the first case, a in the + * second) The returned string is on the heap & must be freed + * eventually. This routine should be passed the line # that the + * string we are eating started on. + */ + +static char * +eat_string(int starting_line) +{ + int c; + char buffer[500]; + char *ptr = buffer; + + for (;;) { + /* + * Get the next input character, handling EOF: + */ + c = input(); + if (!c) { + unput(c); + report_parse_error("unterminated string found beginning", + starting_line); + return(0); + } + + /* + * Deal with special characters ('\\', '"', and '\n'): + */ + if (c=='\\') { + c = eat_escape_code(); + if (!c) + continue; + } else if (c == '"') { + *ptr = 0; + return(string_Copy(buffer)); + } else if (c == '\n') { + unput(c); /* fix line # reference to right line # */ + report_parse_error("carriage return found in string", yylineno); + return(0); + } + + /* + * Add the character c to the current string: + */ + *ptr = c; + ptr++; + + /* + * If out of buffer space, do a recursive call then + * concatanate the result to the string read in so far to get the + * entire string and return that: + */ + if (ptr>buffer+sizeof(buffer)-20) { + string rest_of_string, result; + + rest_of_string = eat_string(starting_line); + if (!rest_of_string) + return(0); + + *ptr = 0; + result = string_Concat(buffer, rest_of_string); + free(rest_of_string); + return(result); + } + } +} + +/* + * eat_show_line - internal routine for eat_show: + * + * This routine reads in a physical line of text allowing escape + * codes via '\\'. If the line ends with a newline, the newline is eaten. + * If the line ends with a EOF, the EOF is not eaten. The string + * represented by what has been eaten is returned. The returned string + * is on the heap & must be freed eventually. If test_for_endshow is + * true and the line read in starts off with "endshow" exactly + * (i.e., no escape codes) followed by any non-identifier-char, then + * instead of doing the above, we just eat the "endshow" & return 0. + */ + +static char * +eat_show_line(int test_for_endshow) +{ + int c; + int saw_escape_code = 0; + int starting_line = yylineno; + char buffer[200]; /* This must be large enough to hold "endshow" */ + char *ptr = buffer; + + while (yylineno == starting_line) { + c = input(); + if (!c) { + unput(c); + *ptr = '\0'; + return(string_Copy(buffer)); + } else if (c == '\\') { + saw_escape_code = 1; + c = eat_escape_code(); + if (!c) + continue; + } + + *ptr = c; + ptr++; + + if ((ptr==buffer+strlen("endshow")) && test_for_endshow) + if (!strncmp(buffer, "endshow", strlen("endshow")) + && !saw_escape_code) { + c = input(); + unput(c); + if (!is_identifier_char(c)) + return(0); + } + + if (ptr>buffer+sizeof(buffer)-2) { + string the_line; + string rest_of_line = eat_show_line(0); + + *ptr = '\0'; + the_line = string_Concat(buffer, rest_of_line); + free(rest_of_line); + return(the_line); + } + } + + *ptr = '\0'; + return(string_Copy(buffer)); +} + +/* + * eat_til_endshow - this routine eats characters allowing escape codes via + * '\\' up to a endshow\{nonalpha} found at the + * start of a line not counting leading whitespace. + * If is seen before the terminator, a parse_error + * is set & 0 returned. Otherwise, the string represented + * by what has been eaten (escape codes replaced by what + * they stand for and leading spaces and tabs removed from + * each physical line) is returned. The returned string + * is on the heap & must be freed eventually. Note that + * to embed endshow in a message, endsho\w can be used. + * This routine should be passed the line # of the show + * command it is being used to process for use in error + * messages. + */ + +static char * +eat_til_endshow(int start_line_no) +{ + register int c; + string text_so_far = string_Copy(""); + string next_line; + + for (;;) { + /* + * Skip the spaces & tabs at the start of the current line: + */ + while ((c=input()), c==' ' || c=='\t') ; + unput(c); + + /* + * Handle unterminated shows: + */ + if (!c) { + report_parse_error("unterminated show beginning", start_line_no); + free(text_so_far); + return(0); + } + + /* + * Read in rest of the line (including the at end), allowing + * for escape codes and checking for "endshow{nonalpha}" at the + * start of the line. (Note: \ is considered the + * end of a line here!) + */ + next_line = eat_show_line(1); + + if (!next_line) /* i.e., is this the endshow line? */ + return(text_so_far); + + text_so_far = string_Concat2(text_so_far, next_line); + free(next_line); + } +} + +/* + * handle_show - this routine is called after "show"\{nonalpha} is + * found to handle up to the endshow. The token # is + * returned. + */ + +static int +handle_show(void) +{ + int c; + int start_line_no = yylineno; + + /* + * Eat up ' ' and '\t's after show. If the next character is a newline, + * eat it. This is so we don't get an extra newline when we call + * eat_til_endshow: + */ + while (c=input(), c==' ' || c=='\t') ; + if (c!='\n') + unput(c); + + yylval.text = eat_til_endshow(start_line_no); + if (yylval.text) + return(SHOW); + else + return(ERROR); +} + +/****************************************************************************/ +/* */ +/* The main lexer itself: */ +/* */ +/****************************************************************************/ + +/* + * yylex - performs as per. the yacc manual's requirements + */ + +int yylex(void) +{ + register int c, last_char; + register char *ptr; + int start_line_no; + int_dictionary_binding *binding; + char varname[MAX_IDENTIFIER_LENGTH+1]; + + for (;;) { + switch (c = input()) { + + /* + * Skip whitespace: + */ + case ' ': case '\t': case '\n': + continue; + + /* + * '#' comments out everything up to the and including + * the next : + */ + case '#': + while ( (c=input()) && (c!='\n') ) ; + if (!c) + unput(c); + continue; + + /* + * Handle c-style comments. Note that "/[^*]" is not the start + * of any valid token. + */ + case '/': + start_line_no = yylineno; + + /* verify that next character is a '*': */ + if ((c=input()) != '*') + return(ERROR); + + /* Scan until "*\/" or : */ + for (last_char=0; ; last_char=c) { + c = input(); + if (c == '/' && (last_char=='*')) + break; + if (!c) { + unput(c); + report_parse_error("unterminated c style comment found beginning", start_line_no); + return(ERROR); + } + } + continue; + + /* + * The following characters lex as themselves: + * '+', '|', '&', '(', ')', '.', ',' and : + */ + case 0: case '+': case '|': case '&': case '(': + case ')': case '.': case ',': + return(c); + + /* + * Handle "=[^~=]", "=~", and "==": + */ + case '=': + switch (c = input()) { + case '~': + return(REGEQ); + case '=': + return(EQ); + default: + unput(c); + return('='); + } + + /* + * Handle "![^~=]", "!~", and "!=": + */ + case '!': + switch (c = input()) { + case '~': + return(REGNEQ); + case '=': + return(NEQ); + default: + unput(c); + return('!'); + } + + /* + * Handle identifiers and keywords: + * + * Note that the below set of characters is hard coded from + * is_identifier_char from parser.h. + */ + case 'a': case 'b': case 'c': case 'd': case 'e': + case 'f': case 'g': case 'h': case 'i': case 'j': + case 'k': case 'l': case 'm': case 'n': case 'o': + case 'p': case 'q': case 'r': case 's': case 't': + case 'u': case 'v': case 'w': case 'x': case 'y': + case 'z': + case 'A': case 'B': case 'C': case 'D': case 'E': + case 'F': case 'G': case 'H': case 'I': case 'J': + case 'K': case 'L': case 'M': case 'N': case 'O': + case 'P': case 'Q': case 'R': case 'S': case 'T': + case 'U': case 'V': case 'W': case 'X': case 'Y': + case 'Z': + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '_': + /* + * Read in the first MAX_IDENTIFIER_LENGTH characters of the + * identifier into varname null terminated. Eat + * the rest of the characters of the identifier: + */ + for (ptr = varname;;) { + if (ptrvalue == SHOW) + return(handle_show()); + else + return(binding->value); + + /* + * Handle "${identifier}". Note that $ followed by a + * non-identifier character is not the start of any valid token. + */ + case '$': + c = input(); + if (!is_identifier_char(c)) + return(ERROR); + + /* + * Read in the first MAX_IDENTIFIER_LENGTH characters of the + * identifier into varname null terminated. Eat + * the rest of the characters of the identifier: + */ + for (ptr = varname;;) { + if (ptr + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef lexer_MODULE +#define lexer_MODULE + +#include + +/* + * is_identifier_char(c) - is c a character that could be part of + * an identifier? + * + * NOTE: this information is hardwired into yylex() in lexer.c! + */ + +#define is_identifier_char(c) (isalnum(c) || (c)=='_') + +/* + * The maximum # of significant letters in an identifier: + * + * Note: in order for all keywords to be recognized, this must be at least 20. + */ + +#define MAX_IDENTIFIER_LENGTH 128 + +/* + * yylineno - this holds the current line # we are on. Updated automatically + * by yylex. + */ + +extern int yylineno; + +/* + * lex_open - this routine [re]initializes the lexer & prepares it to lex + * a file. Resets current line # to 1. + */ + +extern void lex_open(FILE *); + +/* + * yylex - performs as per. the yacc manual's requirements + */ + +extern int yylex(void); + +#endif diff --git a/zwgc/main.c b/zwgc/main.c new file mode 100644 index 0000000..7986242 --- /dev/null +++ b/zwgc/main.c @@ -0,0 +1,730 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#ifdef HAVE_ARES +#include +#endif + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_main_c[] = "$Id$"; +#endif + +#include +#include +#ifdef HAVE_ARPA_NAMESER_COMPAT_H +#include +#endif +#include +#include +#include +#include +#include + +#include "new_memory.h" +#include "zwgc.h" +#include "parser.h" +#include "node.h" +#include "exec.h" +#include "zephyr.h" +#include "notice.h" +#include "subscriptions.h" +#include "file.h" +#include "mux.h" +#include "port.h" +#include "variables.h" +#include "main.h" +#ifdef CMU_ZCTL_PUNT +#include "int_dictionary.h" +#endif +#ifdef CMU_ZWGCPLUS +#include "plus.h" +int zwgcplus = 1; +#endif + +void notice_handler(ZNotice_t *); +static void process_notice(ZNotice_t *, char *); +static void setup_signals(int); +static void detach(void); +static void signal_exit(int); +#ifdef HAVE_ARES +static void notice_callback(void *, int, int, char *, char *); +#endif + +/* + * Global zwgc-wide variables: + */ + +#ifdef DEBUG +int zwgc_debug = 0; +#endif + +static char *zwgc_version_string = "1.0"; + +/* + * description_filename_override - <<<>>> + */ + +static char *description_filename_override = NULL; + +/* + * progname - <<<>>> export! + */ + +char *progname = NULL; + +/* + * subscriptions_filename_override - <<<>>> export! + */ + +char *subscriptions_filename_override = NULL; + +/* + * location_override - <<<>>> export! + */ + +char *location_override = NULL; + +#ifdef HAVE_ARES +/* + * achannel - <<<>>> export! + */ + +ares_channel achannel; +#endif + +/****************************************************************************/ +/* */ +/* Code to deal with reading in the description file: */ +/* */ +/****************************************************************************/ + +/* + * program - this holds a pointer to the node representation of the + * description file once it has been read in. + */ + +static struct _Node *program = NULL; + +/* + * <<<>>> + */ + +static void +fake_startup_packet(void) +{ + ZNotice_t *notice = (ZNotice_t *)malloc(sizeof(ZNotice_t)); + struct timezone tz; + char msgbuf[BUFSIZ]; + extern void Z_gettimeofday(struct _ZTimeval *, struct timezone *); + + var_set_variable("version", zwgc_version_string); + + (void) memset(notice, 0, sizeof(ZNotice_t)); + + notice->z_version = ""; + notice->z_class = "WG_CTL_CLASS"; + notice->z_class_inst = "WG_CTL_USER<<<>>>"; + notice->z_opcode = "WG_STARTUP"; + notice->z_default_format = "Zwgc mark II version $version now running...\n"; + notice->z_recipient = ""; + notice->z_sender = "ZWGC"; + Z_gettimeofday(¬ice->z_time, &tz); + notice->z_port = 0; + notice->z_kind = ACKED; + notice->z_auth = ZAUTH_YES; + notice->z_charset = ZCHARSET_UNKNOWN; + sprintf(msgbuf,"Zwgc mark II version %s now running...", + zwgc_version_string); + notice->z_message = msgbuf; + notice->z_message_len = strlen(notice->z_message)+1; + +#ifdef CMU_ZWGCPLUS + list_add_notice(notice); + set_notice_fake(notice, 1); +#endif + process_notice(notice, NULL); +#ifdef CMU_ZWGCPLUS + list_del_notice(notice); +#else + free(notice); +#endif +} + +static void +read_in_description_file(void) +{ + FILE *input_file; + char defdesc[128]; + +/* var_clear_all_variables(); <<<>>> */ + + sprintf(defdesc, "%s/zephyr/%s", DATADIR, DEFDESC); + input_file = locate_file(description_filename_override, USRDESC, defdesc); + if (input_file) + program = parse_file(input_file); + else + program = NULL; + + fake_startup_packet(); +} + +/****************************************************************************/ +/* */ +/* Code to deal with argument parsing & overall control: */ +/* */ +/****************************************************************************/ + +/* + * void usage() + * Effects: Prints out an usage message on stderr then exits the + * program with error code 1. + */ + +void +usage(void) +{ +#ifdef DEBUG + fprintf(stderr, "\ +zwgc: usage: zwgc [-debug] [-f ] [-subfile ]\n\ + [-ttymode] [-nofork] [-reenter] [-loc text]\n\ + [-default ] {-disable }*\n\ + [output driver options]\n"); +#else + fprintf(stderr, "\ +zwgc: usage: zwgc [-f ] [-subfile ]\n\ + [-ttymode] [-nofork] [-reenter] [-loc text]\n\ + [-default ] {-disable }*\n\ + [output driver options]\n"); +#endif + exit(1); +} + +/* + * <<<>>> + */ + +static void +run_initprogs(void) +{ + /* + * This code stolen from old zwgc: yuck. Clean up & fix. <<<>>> + * Should this fork instead of just systeming? + */ + + int status; + char *iprogname = ZGetVariable("initprogs"); + + if (!iprogname) + return; + + status = system(iprogname); + if (status == 127) { + perror("zwgc initprog exec"); + fprintf(stderr,"zwgc initprog of <%s> failed: no shell.\n", + iprogname); + } else if (status!=-1 && status>>8) { + perror("zwgc initprog exec"); + fprintf(stderr,"zwgc initprog of <%s> failed with status [%d].\n", + iprogname, status>>8); + } +} + +/* + * main -- the program entry point. Does parsing & top level control. + */ + +int +main(int argc, char **argv) +{ + char **new; + register char **current; + int dofork = 1; +#ifdef HAVE_ARES + int status; +#endif + + setlocale(LC_ALL, ""); + progname = argv[0]; + + /* + * Process "-f ", "-subfile ", "-nofork", + * "-reenter" (which is ignored) and (if DEBUG) "-debug" + * arguments, removing then from argc, argv: + */ + for (new=current=argv+1; *current; current++) { + if (string_Eq(*current, "-debug")) { + argc--; +#ifdef DEBUG + zwgc_debug = 1; +#endif + } else if (string_Eq(*current, "-f")) { + argc -= 2; current++; + if (!*current) + usage(); + description_filename_override = *current; + } else if (string_Eq(*current, "-subfile")) { + argc -= 2; current++; + if (!*current) + usage(); + subscriptions_filename_override = *current; + } else if (string_Eq(*current, "-nofork")) { + argc--; + dofork = 0; + } else if (string_Eq(*current, "-reenter")) { + argc--; /* just throw it away */ + } else if (string_Eq(*current, "-loc")) { + argc -= 2; current++; + if (!*current) + usage(); + location_override = *current; + } else + *(new)++ = *current; + } + *new = *current; + +#ifdef HAVE_ARES + /* + * Initialize resolver library + */ + status = ares_init(&achannel); + if (status != ARES_SUCCESS) { + fprintf(stderr, "Couldn't initialize resolver: %s\n", + ares_strerror(status)); + return(1); + } +#endif + + /* + * Initialize various subsystems in proper order: + */ + dprintf("Initializing subsystems...\n"); /*<<<>>>*/ +#ifdef CMU_ZWGCPLUS + init_noticelist(); +#endif + mux_init(); + var_clear_all_variables(); /* <<<>>> */ + init_ports(); /* <<<>>> */ + dprintf("Initializing standard ports...\n"); + init_standard_ports(&argc, argv); + if (argc>1) + usage(); + dprintf("Initializing zephyr...\n"); + setup_signals(dofork); + zephyr_init(notice_handler); + + if (dofork) + detach(); + /* + * Run the initprogs program(s) now that we are all set to deal: + */ + dprintf("Running initprogs program...\n"); + run_initprogs(); + + dprintf("Test Zwgc parser.\n\n"); + read_in_description_file(); + + dprintf("Entering main loop\n"); + mux_loop(); + + dprintf("Returning from main loop\n"); + finalize_zephyr(); + + return(0); +} + +/****************************************************************************/ +/* */ +/* : */ +/* */ +/****************************************************************************/ + +#define USER_SUPPRESS "SUPPRESS" +#define USER_UNSUPPRESS "UNSUPPRESS" + +#ifdef CMU_ZCTL_PUNT +#define USER_LIST_SUPPRESSED "LIST-SUPPRESSED" + +#define PUNT_INC 1024 +extern int_dictionary puntable_addresses_dict; +ZNotice_t punt_reply; + +static void +create_punt_reply(int_dictionary_binding *punt_ent) +{ + int key_len = strlen(punt_ent->key); + char *tmp; + + if (!punt_reply.z_message) { + punt_reply.z_message = (char *)malloc(PUNT_INC); + punt_reply.z_message[0] = 0; + } + + if ((punt_reply.z_message_len + key_len + 1) / PUNT_INC > + (punt_reply.z_message_len + PUNT_INC - 1) / PUNT_INC) { + char *new_message = (char *)malloc((punt_reply.z_message_len + / PUNT_INC + 1) * PUNT_INC); + + strcpy(new_message, punt_reply.z_message); + + free(punt_reply.z_message); + punt_reply.z_message = new_message; + } + tmp = punt_reply.z_message + strlen(punt_reply.z_message); + strcat (punt_reply.z_message, punt_ent->key); + strcat (punt_reply.z_message, "\n"); + punt_reply.z_message_len += key_len + 1; + + while (*tmp != '\001') tmp++; + *tmp = ','; + while (*tmp != '\001') tmp++; + *tmp = ','; +} +#endif /* CMU_ZCTL_PUNT */ + +void +notice_handler(ZNotice_t *notice) +{ +#ifndef HAVE_ARES + int ret; + char node[NS_MAXDNAME]; +#endif + +#if defined(CMU_ZWGCPLUS) + list_add_notice(notice); +#endif + +#ifdef HAVE_ARES + ares_getnameinfo(achannel, + (const struct sockaddr *)&(notice->z_sender_sockaddr), + notice->z_sender_sockaddr.sa.sa_family == AF_INET ? + sizeof(struct sockaddr_in) : + notice->z_sender_sockaddr.sa.sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(notice->z_sender_sockaddr), ARES_NI_LOOKUPHOST, + notice_callback, notice); +#else + ret = getnameinfo((const struct sockaddr *)&(notice->z_sender_sockaddr), + notice->z_sender_sockaddr.sa.sa_family == AF_INET ? + sizeof(struct sockaddr_in) : + notice->z_sender_sockaddr.sa.sa_family == AF_INET6 ? + sizeof(struct sockaddr_in6) : + sizeof(notice->z_sender_sockaddr), + node, sizeof(node), NULL, 0, 0); + if (ret != 0) + strcpy(node, "?"); + + process_notice(notice, node); +#ifdef CMU_ZWGCPLUS + /* Let list_del_notice clean up for us. */ +#else + ZFreeNotice(notice); + free(notice); +#endif +#endif +} + +#ifdef HAVE_ARES +/* +static void +notice_callback(void *arg, + int status, + int timeouts, + struct hostent *fromhost) +*/ +static void +notice_callback(void *arg, + int status, + int timeouts, + char *node, + char *service) +{ + ZNotice_t *notice = (ZNotice_t *) arg; + +#ifdef CMU_ZWGCPLUS + plus_set_hname(notice, node); +#endif + + process_notice(notice, node); +#ifdef CMU_ZWGCPLUS + list_del_notice(notice); +#else + ZFreeNotice(notice); + free(notice); +#endif +} +#endif + +static void +process_notice(ZNotice_t *notice, + char *hostname) +{ + char *control_opcode; + + dprintf("Got a message\n"); + + control_opcode = decode_notice(notice, hostname); + if (control_opcode) { +#ifdef DEBUG + printf("got control opcode <%s>.\n", control_opcode); +#endif + if (!strcasecmp(control_opcode, USER_REREAD)) { + read_in_description_file(); + } else if (!strcasecmp(control_opcode, USER_SHUTDOWN)) + zwgc_shutdown(); + else if (!strcasecmp(control_opcode, USER_STARTUP)) { +#ifdef DEBUG_MEMORY + report_memory_usage(); /* <<<>>> */ +#endif + zwgc_startup(); + } else if (!strcasecmp(control_opcode, USER_SUPPRESS)) { + string class = get_field(notice->z_message, + notice->z_message_len, 1); + string instance = get_field(notice->z_message, + notice->z_message_len, 2); + string recipient = get_field(notice->z_message, + notice->z_message_len, 3); + punt(class, instance, recipient); + free(class); + free(instance); + free(recipient); + } else if (!strcasecmp(control_opcode, USER_UNSUPPRESS)) { + string class = get_field(notice->z_message, + notice->z_message_len, 1); + string instance = get_field(notice->z_message, + notice->z_message_len, 2); + string recipient = get_field(notice->z_message, + notice->z_message_len, 3); + unpunt(class, instance, recipient); + free(class); + free(instance); + free(recipient); +#ifdef CMU_ZCTL_PUNT + } else if (!strcasecmp(control_opcode, USER_LIST_SUPPRESSED)) { + struct sockaddr_in old, to; + int retval; + + if (!notice->z_port) { + printf("zwgc: can't reply to LIST-SUPPRESSED request\n"); + return; + } + memset((char *) &punt_reply, 0, sizeof(ZNotice_t)); + punt_reply.z_kind = CLIENTACK; + punt_reply.z_class = WG_CTL_CLASS; + punt_reply.z_class_inst = "WG_REPLY"; + punt_reply.z_recipient = "zctl?"; + punt_reply.z_sender = "Zwgc"; + punt_reply.z_default_format = ""; + punt_reply.z_opcode = USER_LIST_SUPPRESSED; + punt_reply.z_port = notice->z_port; + punt_reply.z_message = NULL; + punt_reply.z_message_len = 0; + + if (puntable_addresses_dict) { + int_dictionary_Enumerate(puntable_addresses_dict, + create_punt_reply); + } + + old = ZGetDestAddr(); + to = old; + + to.sin_port = notice->z_port; + if ((retval = ZSetDestAddr(&to)) != ZERR_NONE) { + com_err("zwgc",retval,"while setting destination address"); + exit(1); + } + + ZSendNotice(&punt_reply, ZNOAUTH); + + if ((retval = ZSetDestAddr(&old)) != ZERR_NONE) { + com_err("zwgc",retval,"while resetting destination address"); + exit(1); + } + + if (punt_reply.z_message) { + free(punt_reply.z_message); + punt_reply.z_message = NULL; + } +#endif + } else if (!strcasecmp(control_opcode, USER_EXIT)) { + signal_exit(0); + } else + printf("zwgc: unknown control opcode %s.\n", control_opcode); + + goto cleanup; + } + + if (!zwgc_active) { +#ifdef DEBUG + if (zwgc_debug) + printf("NON-ACTIVE: PUNTED <%s>!!!!\n", notice->z_class_inst); +#endif + goto cleanup; + } + + if (puntable_address_p(notice->z_class, + notice->z_class_inst, + notice->z_recipient)) { +#ifdef DEBUG + if (zwgc_debug) + printf("PUNTED <%s>!!!!\n", notice->z_class_inst); +#endif + goto cleanup; + } + + exec_process_packet(program, notice); + cleanup: + return; +} + +#ifdef CMU_ZWGCPLUS +void +reprocess_notice(ZNotice_t *notice, char *hostname) +{ + list_add_notice(notice); + process_notice(notice, hostname); + list_del_notice(notice); +} +#endif + +/***************************************************************************/ + +/* + * + */ + +static void +signal_exit(int ignored) +{ + mux_end_loop_p = 1; +} + +/* clean up ALL the waiting children, in case we get hit with + multiple SIGCHLD's at once, and don't process in time. */ +static RETSIGTYPE +signal_child(int ignored) +{ +#ifdef HAVE_WAITPID + int status; +#else + union wait status; +#endif + int pid, old_errno = errno; + + do { +#ifdef HAVE_WAITPID + pid = waitpid(-1, &status, WNOHANG); +#else + pid = wait3(&status, WNOHANG, (struct rusage *)0); +#endif + } while (pid != 0 && pid != -1); + errno = old_errno; +} + +/* rewrite the wgfile in case it has gone away */ +static RETSIGTYPE +signal_usr1(int ignored) +{ + write_wgfile(); +} + +static void +setup_signals(int dofork) +{ +#ifdef _POSIX_VERSION + struct sigaction sa; + + sigemptyset(&sa.sa_mask); + sa.sa_flags = 0; + + if (dofork) { + sa.sa_handler = SIG_IGN; + sigaction(SIGINT, &sa, (struct sigaction *)0); + sigaction(SIGTSTP, &sa, (struct sigaction *)0); + sigaction(SIGQUIT, &sa, (struct sigaction *)0); + sigaction(SIGTTOU, &sa, (struct sigaction *)0); + } else { + /* clean up on SIGINT; exiting on logout is the user's problem, now. */ + sa.sa_handler = signal_exit; + sigaction(SIGINT, &sa, (struct sigaction *)0); + } + + /* behavior never changes */ + sa.sa_handler = signal_exit; + sigaction(SIGTERM, &sa, (struct sigaction *)0); + sigaction(SIGHUP, &sa, (struct sigaction *)0); + + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, (struct sigaction *)0); + + sa.sa_handler = signal_child; + sigaction(SIGCHLD, &sa, (struct sigaction *)0); + + sa.sa_handler = signal_usr1; + sigaction(SIGUSR1, &sa, (struct sigaction *)0); + +#else /* !POSIX */ + if (dofork) { + /* Ignore keyboard signals if forking. Bad things will happen. */ + signal(SIGINT, SIG_IGN); + signal(SIGTSTP, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + signal(SIGQUIT, SIG_IGN); + } else { + /* clean up on SIGINT; exiting on logout is the user's problem, now. */ + signal(SIGINT, signal_exit); + } + + /* behavior never changes */ + signal(SIGTERM, signal_exit); + signal(SIGHUP, signal_exit); + signal(SIGCHLD, signal_child); + signal(SIGPIPE, SIG_IGN); /* so that Xlib gets an error */ + signal(SIGUSR1, signal_usr1); +#endif +} + +/* detach() taken from old zwgc, with lots of stuff ripped out */ + +static void +detach(void) +{ + /* detach from terminal and fork. */ + register int i; + + /* Attempt to join the process group of the session leader. This + * will get us a HUP if the session leader is in the foreground at + * logout time (which is often the case) or if the shell is running + * under telnetd or xterm (both of which HUP the process group of + * their child process). If we have getsid(), that's the best way + * of finding the session leader; otherwise use the process group of + * the parent process, which is a good guess. */ +#if defined(HAVE_GETSID) + + setpgid(0, getsid(0)); +#elif defined(HAVE_GETPGID) + setpgid(0, getpgid(getppid())); +#elif !defined(GETPGRP_VOID) + setpgid(0, getpgrp(getppid())); +#endif + + /* fork off and let parent exit... */ + i = fork(); + if (i) { + if (i < 0) { + perror("zwgc: cannot fork, aborting:"); + exit(1); + } + exit(0); + } +} diff --git a/zwgc/main.h b/zwgc/main.h new file mode 100644 index 0000000..9257ac6 --- /dev/null +++ b/zwgc/main.h @@ -0,0 +1,54 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef main_MODULE +#define main_MODULE + +#ifdef HAVE_ARES +#include + +extern ares_channel achannel; +#endif + +extern char *progname; +extern char *subscriptions_filename_override; +extern char *location_override; + +/* + * void usage() + * Effects: Prints out a usage message on stderr then exits the + * program with error code 1. + */ + +extern void usage(void); + +#ifdef CMU_ZWGCPLUS +extern void reprocess_notice(ZNotice_t *notice, char *hostname); +#endif + +/* USRDESC points to a file (relative to user's homedir) which has a user's + description file */ + +#define USRDESC ".zwgc.desc" + +/* DEFDESC points to a file (relative to the data directory) which has the + * system default description file */ + +#ifndef DEFDESC +#define DEFDESC "zwgc.desc" +#endif + +#endif diff --git a/zwgc/mux.c b/zwgc/mux.c new file mode 100644 index 0000000..a7b2210 --- /dev/null +++ b/zwgc/mux.c @@ -0,0 +1,239 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_mux_c[] = "$Id$"; +#endif + +/****************************************************************************/ +/* */ +/* Module containing code to wait on multiple file descriptors: */ +/* */ +/****************************************************************************/ + +#include +#include "main.h" +#include "mux.h" +#include "error.h" +#include "zwgc.h" +#include "pointer.h" +#ifdef CMU_ZWGCPLUS +#include "plus.h" +#endif + +#ifdef _AIX +#include +#endif + +/* + * mux_end_loop_p - Setting this to true during a mux_loop causes the mux_loop + * to be exited. + */ + +int mux_end_loop_p; + +/* + * have_tty - is defined to be true if there is a controlling tty for this + * process. When we can no longer access the controlling tty, + * the process will die. + */ + +static int have_tty = 0; + +/* + * max_source - the maximum file descriptor that a handler was ever + * registered for: + */ + +static int max_source = -1; + +/* + * Which file descriptors we're waiting on for input & the accompanying + * input handlers & their arguments: + */ + +static fd_set input_sources; +static void (*input_handler[MAX_SOURCES])(void *); +static pointer input_handler_arg[MAX_SOURCES]; + +static int check_tty(void); + +/* + * void mux_init() + * Requires: mux_init has never been called before + * Effects: Initializes the mux module. Must be called before + * any other mux call. + */ + +void +mux_init(void) +{ + int i; + + FD_ZERO(&input_sources); + + for (i=0; i= MAX_SOURCES) + abort(); /* <<<>>> */ +#endif + + input_handler[descriptor] = handler; + input_handler_arg[descriptor] = arg; + FD_SET(descriptor, &input_sources); + if(descriptor > max_source) + max_source = descriptor; +} + +/* + * void mux_loop() + * Requires: mux_init has been called. + * Effects: Loops until mux_end_loop_p becomes true. (Sets + * mux_end_loop_p false to start). Whenever input is + * available on an input source which has a registered + * handler (see mux_add_input_source), that handler is + * called with its argument. It is guaranteed that if + * input is available on a source, its respective input + * handler, if any, will eventually be called. No other + * ordering guarantees are made. When some signal handler + * or input handler eventually sets mux_end_loop_p to + * true, we return. + */ + +void +mux_loop(void) +{ + int i, nfds; + fd_set inputs, outputs; + struct timeval tv, *tvp; + + mux_end_loop_p = 0; + + for (;;) { + /* + * Exit if mux_end_loop_p has been set to true by a handler: + */ + if (mux_end_loop_p) + break; + tvp = NULL; + tv.tv_sec = 0; + if (have_tty) { +#ifdef CMU_ZWGCPLUS + tv.tv_sec = plus_timequeue_events(); + if (tv.tv_sec > 10) tv.tv_sec = 10; +#else + tv.tv_sec = 10; +#endif + tv.tv_usec = 0; +#ifdef CMU_ZWGCPLUS + } else { + tv.tv_sec = plus_timequeue_events(); + tv.tv_usec = 0; +#endif + } + if (tv.tv_sec) + tvp = &tv; + + /* + * Do a select on all the file descriptors we care about to + * wait until at least one of them has input available: + */ + inputs = input_sources; + FD_ZERO(&outputs); + +#ifdef HAVE_ARES + nfds = ares_fds(achannel, &inputs, &outputs); + if (nfds < max_source + 1) + nfds = max_source + 1; + tvp = ares_timeout(achannel, tvp, &tv); +#else + nfds = max_source + 1; +#endif + + i = select(nfds, &inputs, &outputs, NULL, tvp); + + if (i == -1) { + if (errno == EINTR) + continue; /* on a signal restart checking mux_loop_end_p */ + else + FATAL_TRAP( errno, "while selecting" ); + } + else if (i == 0) { + if (have_tty && !check_tty()) { + mux_end_loop_p = 1; + continue; + } + } + +#ifdef HAVE_ARES + ares_process(achannel, &inputs, &outputs); +#endif + + /* + * Call all input handlers whose corresponding file descriptors have + * input: + */ + for(i=0; i<=max_source; i++) + if (FD_ISSET(i, &inputs) && input_handler[i]) { +#ifdef DEBUG + if (zwgc_debug) + fprintf(stderr, + "mux_loop...activity on fd %d, calling %lx(%lx)\n", + i, (unsigned long)input_handler[i], + (unsigned long)input_handler_arg[i]); +#endif + input_handler[i](input_handler_arg[i]); + } + } +} + +static int +check_tty(void) +{ + register int result; + int pgrp; + int tty = open("/dev/tty", O_RDONLY|O_NDELAY); + + if (tty < 0) return 0; + +#if defined(_POSIX_VERSION) + result = ( ((pgrp = tcgetpgrp(tty)) < 0) ? 0 : 1 ); +#else + result = ( (ioctl(tty, TIOCGPGRP, &pgrp) < 0) ? 0 : 1 ); +#endif + + close(tty); + return(result); +} diff --git a/zwgc/mux.h b/zwgc/mux.h new file mode 100644 index 0000000..230f9df --- /dev/null +++ b/zwgc/mux.h @@ -0,0 +1,72 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef mux_MODULE +#define mux_MODULE + +/* + * MAX_SOURCES - the greatest file descriptor # that can be waited on minus one + * This can not exceed FD_SETSIZE from . + */ + +#define MAX_SOURCES 32 + +/* + * mux_end_loop_p - Setting this to true during a mux_loop causes the mux_loop + * to be exited. + */ + +extern int mux_end_loop_p; + +/* + * void mux_init() + * Requires: mux_init has never been called before + * Effects: Initializes the mux module. Must be called before + * any other mux call. + */ + +extern void mux_init(void); + +/* + * void mux_add_input_source(int descriptior; void (*handler)(); void *arg) + * Requires: 0<=descriptor + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_new_memory_c[] = "$Id$"; +#endif + +#if !defined(SABER) && (defined(DEBUG) || defined(MEMORY_DEBUG)) + +/* + * memory - module wrapping debugging code around normal malloc/free/etc. + * routines. + * + * Overview: + * + * ... + */ + +#define memory__PROVIDER +#include "new_memory.h" + +/* + * + */ +#ifdef DEBUG +#define assert(x) if (!(x)) abort() +#else +#define assert(x) +#endif + +/* + * + */ +#ifdef DEBUG_MEMORY + +extern void record_request(); +char *current_module = 0; +int current_line = -1; + +#endif + +/* + * string string_CreateFromData(char *data, int length): + * Requires: data[0], data[1], ..., data[length-1] != 0 + * Effects: Takes the first length characters at data and + * creates a string containing them. The returned string + * is on the heap & must be freed eventually. + * I.e., if passed "foobar" and 3, it would return + * string_Copy("foo"). + */ + +void *memory__malloc(size) + unsigned size; +{ + char *result; + + result = malloc(size + memory__size_of_header); + if (!result) + abort(); /* <<<>>> */ + +#ifdef DEBUG_MEMORY + ((memory_block_header *)result)->size = size; + ((memory_block_header *)result)->creating_module = current_module; + ((memory_block_header *)result)->line_number_in_creating_module = + current_line; + ((memory_block_header *)result)->check_field = CHECK_FIELD_VALUE; + result += memory__size_of_header; + + record_request(current_module, current_line, 1, size); +#endif + + return(result); +} + +void *memory__realloc(aptr, size) + void *aptr; + unsigned size; +{ + char *result, *ptr = aptr; + + assert(ptr); + +#ifdef DEBUG_MEMORY + if (!memory__on_heap_p(ptr)) { + printf("realloced non-memory block in %s on line %d!\n", + current_module, current_line); + fflush(stdout); + return(realloc(ptr, size)); + } +#endif + + result = realloc(ptr-memory__size_of_header, size+memory__size_of_header); + if (!result) + abort(); /* <<<>>> */ + + return(result+memory__size_of_header); +} + +void *memory__calloc(nelem, elsize) + unsigned nelem; + unsigned elsize; +{ + char *result; + +#ifdef DEBUG_MEMORY + printf("in calloc\n"); fflush(stdout); +#endif + + abort(); + +#ifdef FRED + result = calloc(nelem, elsize); + if (!result) + abort(); + + record_request(1); +#endif + + return(result); +} + +void memory__free(aptr) + void *aptr; +{ + char *ptr = aptr; + assert(ptr); + +#ifdef DEBUG_MEMORY + if (!memory__on_heap_p(ptr)) { + printf("freed non-memory block in %s on line %d!\n", current_module, + current_line); + fflush(stdout); + (void)free(ptr); + return; + } + + record_request(memory__get_header(ptr)->creating_module, + memory__get_header(ptr)->line_number_in_creating_module, + -1, + memory__get_header(ptr)->size); +#endif + + (void)free(ptr-memory__size_of_header); +} + +#ifdef DEBUG_MEMORY + +#include "int_dictionary.h" + +static int request_off = 0; +static int_dictionary requests = 0; +static int outstanding_requests = 0; +static int outstanding_memory = 0; + +void record_request(module, line_number, dir, size) + char *module; + int line_number; + int dir; + unsigned int size; +{ + int_dictionary_binding *binding; + int already_exists; +#ifdef LINE + char buffer[20]; +#endif + + if (request_off) + return; + request_off = 1; + + if (!requests) + requests = int_dictionary_Create(101); + +#ifdef LINE + module = string_Concat(module, ":"); + sprintf(buffer, "%d", line_number); + module = string_Concat2(module, buffer); +#endif + + binding = int_dictionary_Define(requests, module, &already_exists); + if (!already_exists) + binding->value = 0; + +#ifdef LINE + free(module); +#endif + + binding->value += dir; + outstanding_requests += dir; + outstanding_memory += size*dir; + + request_off = 0; +} + +void proc(binding) + int_dictionary_binding *binding; +{ + if (binding->value) + printf(" %-30s %6d blocks allocated\n", binding->key, binding->value); +} + +void report_memory_usage() +{ + printf("\n# of blocks on the heap = %d\n", outstanding_requests); + printf("Total heap space in use: %d bytes\n", outstanding_memory); + + printf("\nHeap Allocations by module:\n"); + int_dictionary_Enumerate(requests, proc); + printf("\n"); + + fflush(stdout); +} + +void set_module(file, line) + char *file; + int line; +{ + if (request_off) + return; + + if (!strcmp(file, "new_string.c")) + return; + if (!strcmp(file, "string_dictionary_aux.c")) + return; + + current_line = line; + current_module = file; +} + +#endif + +#endif /* SABER */ diff --git a/zwgc/new_memory.h b/zwgc/new_memory.h new file mode 100644 index 0000000..31235fb --- /dev/null +++ b/zwgc/new_memory.h @@ -0,0 +1,84 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +/* This entire module goes out the window in saber */ +#if !defined(SABER) && (defined(DEBUG) || defined(DEBUG_MEMORY)) + +#ifndef memory_MODULE +#define memory_MODULE + +extern void *memory__malloc(unsigned); /* PRIVATE */ +extern void *memory__realloc(void *, unsigned); /* PRIVATE */ +extern void *memory__calloc(unsigned, unsigned); /* PRIVATE */ +extern void memory__free(void *); /* PRIVATE */ + +#ifdef DEBUG_MEMORY + +#define CHECK_FIELD_VALUE 0xe5e7e3e9 + +typedef struct _memory_block_header { + unsigned size; + char *creating_module; + int line_number_in_creating_module; + unsigned int check_field; +} memory_block_header; + +#define memory__size_of_header (sizeof(struct _memory_block_header)) + +#define memory__get_header(block) \ + ((struct _memory_block_header *)((block)-memory__size_of_header)) + +#define memory__on_heap_p(block) \ + (memory__get_header(block)->check_field==CHECK_FIELD_VALUE) + +#else + +#define memory__size_of_header 0 + +#define memory__on_heap_p(block) 1 + +#endif + +/* + * int string_Length(string s): + * Effects: Returns the number of non-null characters in s. + */ + +#ifndef memory__PROVIDER +#ifdef DEBUG_MEMORY + +extern char *current_module; +extern void set_module(); + +#define malloc(size) (set_module(__FILE__,__LINE__),\ + memory__malloc(size)) +#define realloc(ptr, size) (set_module(__FILE__,__LINE__),\ + memory__realloc((char *) ptr, size)) +#define calloc(nelem, elsize) (set_module(__FILE__,__LINE__),\ + memory__calloc(nelem, elsize)) +#define free(ptr) (set_module(__FILE__,__LINE__),\ + memory__free((char *) ptr)) +#else + +#define malloc(size) memory__malloc(size) +#define realloc(ptr, size) memory__realloc((char *) ptr, size) +#define calloc(nelem, elsize) memory__calloc(nelem, elsize) +#define free(ptr) memory__free((char *) ptr) + +#endif /* DEBUG_MEMORY */ + +#endif /* memory__PROVIDER */ + +#endif /* memory_MODULE */ + +#endif /* SABER */ diff --git a/zwgc/new_string.c b/zwgc/new_string.c new file mode 100644 index 0000000..4d95244 --- /dev/null +++ b/zwgc/new_string.c @@ -0,0 +1,193 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include "new_string.h" + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_new_string_c[] = "$Id$"; +#endif + +/* + * string - a module providing operations on C strings. (i.e., char *'s) + * + * Overview: + * + * A string is a standard C string. I.e., a char pointer to a + * null-terminated sequence of characters. 0 is NOT considered a valid + * string! Various operations are available. See the string_spec file + * for details. + * + * Note: This module assumes that malloc NEVER returns 0 for reasonable + * requests. It is the users responsibility to either ensure that + * this happens or supply a version of malloc with error + * handling. + * + * Some strings are mutable. + */ + +#ifdef DEBUG +#define assert(x) if (!(x)) abort() +#else +#define assert(x) +#endif + +#include "new_memory.h" + +/* + * string string_CreateFromData(char *data, int length): + * Requires: data[0], data[1], ..., data[length-1] != 0 + * Effects: Takes the first length characters at data and + * creates a string containing them. The returned string + * is on the heap & must be freed eventually. + * I.e., if passed "foobar" and 3, it would return + * string_Copy("foo"). + */ + +string string__CreateFromData(char *data, int length) +{ + string result; + + assert(length>=0); + + result = (string)malloc(length+1); + assert(result); + + (void) memcpy(result, data, length); + result[length] = 0; + + return(result); +} + +/* + * string string_Copy(string s): + * Effects: Returns a copy of s on the heap. The copy must be + * freed eventually. + */ + +string +string__Copy(string s) +{ + int length; + string result; + + assert(s); + + length = string_Length(s)+1; + result = (string)malloc(length); + assert(result); + + (void) memcpy(result, s, length); + return(result); +} + +/* + * string string_Concat(string a, b): + * Effects: Returns a string equal to a concatenated to b. + * The returned string is on the heap and must be + * freed eventually. I.e., given "abc" and "def", + * returns string_Copy("abcdef"). + */ + +string +string__Concat(string a, + string b) +{ + string result; + int a_length, b_size, result_size; + + a_length = string_Length(a); + b_size = string_Length(b)+1; + result_size = a_length+b_size; + result = (string)malloc(result_size); + assert(result); + + (void) memcpy(result, a, a_length); + (void) memcpy(result+a_length, b, b_size); + + return(result); +} + +/* + * string string_Concat2(string a, b): + * Modifies: a + * Requires: a is on the heap, b does not point into a. + * Effects: Equivalent to: + * string temp; + * temp = string_Concat(a,b); + * free(a); + * return(temp); + * only faster. I.e., uses realloc instead of malloc+memcpy. + */ + +string +string__Concat2(string a, + string b) +{ + int a_length = string_Length(a); + int b_size = string_Length(b)+1; + +#ifdef DEBUG_MEMORY + assert(memory__on_heap_p(a)); +#endif + + a = (string)realloc(a, a_length+b_size); + assert(a); + (void) memcpy(a+a_length, b, b_size); + + return(a); +} + +/* + * string string_Downcase(string s): + * Modifies: s + * Effects: Modifies s by changing every uppercase character in s + * to the corresponding lowercase character. Nothing else + * is changed. I.e., "FoObAr19." is changed to "foobar19.". + * S is returned as a convenience. + */ + +string +string_Downcase(string s) +{ + char *ptr; + + for (ptr=s; *ptr; ptr++) { + if (isupper(*ptr)) + *ptr = tolower(*ptr); + } + + return(s); +} + +/* + * string string_Upcase(string s): + * Modifies: s + * Effects: Modifies s by changing every lowercase character in s + * to the corresponding uppercase character. Nothing else + * is changed. I.e., "FoObAr19." is changed to "FOOBAR19.". + * S is returned as a convenience. + */ + +string +string_Upcase(string s) +{ + char *ptr; + + for (ptr=s; *ptr; ptr++) { + if (islower(*ptr)) + *ptr = toupper(*ptr); + } + + return(s); +} diff --git a/zwgc/new_string.h b/zwgc/new_string.h new file mode 100644 index 0000000..ea10105 --- /dev/null +++ b/zwgc/new_string.h @@ -0,0 +1,134 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef string_TYPE +#define string_TYPE + +#include +#include "new_memory.h" + +typedef char *string; + +/* + * int string_Length(string s): + * Effects: Returns the number of non-null characters in s. + */ + +#define string_Length(s) strlen(s) + +/* + * int string_Eq(string a, b): + * Effects: Returns true iff strings a & b are equal. I.e., have the + * same character contents. + */ + +#define string_Eq(a,b) (!strcmp(a,b)) + +/* + * int string_Neq(string a, b): + * Effects: Returns true iff strings a & b are not equal. + */ + +#define string_Neq(a,b) (strcmp(a,b)) + +/* + * string string_CreateFromData(char *data, int length): + * Requires: data[0], data[1], ..., data[length-1] != 0 + * Effects: Takes the first length characters at data and + * creates a string containing them. The returned string + * is on the heap & must be freed eventually. + * I.e., if passed "foobar" and 3, it would return + * string_Copy("foo"). + */ + +extern string string__CreateFromData(char *, int); +#ifdef DEBUG_MEMORY +#define string_CreateFromData(data,length) (set_module(__FILE__,__LINE__),\ + string__CreateFromData(data,length)) +#else +#define string_CreateFromData(data,length) string__CreateFromData(data,length) +#endif + +/* + * string string_Copy(string s): + * Effects: Returns a copy of s on the heap. The copy must be + * freed eventually. + */ + +extern string string__Copy(string); +#ifdef DEBUG_MEMORY +#define string_Copy(data) (set_module(__FILE__,__LINE__),\ + string__Copy(data)) +#else +#define string_Copy(data) string__Copy(data) +#endif + +/* + * string string_Concat(string a, b): + * Effects: Returns a string equal to a concatenated to b. + * The returned string is on the heap and must be + * freed eventually. I.e., given "abc" and "def", + * returns string_Copy("abcdef"). + */ + +extern string string__Concat(string, string); +#ifdef DEBUG_MEMORY +#define string_Concat(a,b) (set_module(__FILE__,__LINE__),\ + string__Concat(a,b)) +#else +#define string_Concat(a,b) string__Concat(a,b) +#endif + +/* + * string string_Concat2(string a, b): + * Modifies: a + * Requires: a is on the heap, b does not point into a. + * Effects: Equivalent to: + * string temp; + * temp = string_Concat(a,b); + * free(a); + * return(temp); + * only faster. I.e., uses realloc instead of malloc+bcopy. + */ + +extern string string__Concat2(string, string); +#ifdef DEBUG_MEMORY +#define string_Concat2(a,b) (set_module(__FILE__,__LINE__),\ + string__Concat2(a,b)) +#else +#define string_Concat2(a,b) string__Concat2(a,b) +#endif + +/* + * string string_Downcase(string s): + * Modifies: s + * Effects: Modifies s by changing every uppercase character in s + * to the corresponding lowercase character. Nothing else + * is changed. I.e., "FoObAr19." is changed to "foobar19.". + * S is returned as a convenience. + */ + +extern string string_Downcase(string); + +/* + * string string_Upcase(string s): + * Modifies: s + * Effects: Modifies s by changing every lowercase character in s + * to the corresponding uppercase character. Nothing else + * is changed. I.e., "FoObAr19." is changed to "FOOBAR19.". + * S is returned as a convenience. + */ + +extern string string_Upcase(string); + +#endif diff --git a/zwgc/node.c b/zwgc/node.c new file mode 100644 index 0000000..f04225e --- /dev/null +++ b/zwgc/node.c @@ -0,0 +1,331 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_node_c[] = "$Id$"; +#endif + +#include + +#include "new_memory.h" +#include "node.h" + +/****************************************************************************/ +/* */ +/* Internal node construction & destruction functions: */ +/* */ +/****************************************************************************/ + +/* + * NODE_BATCH_SIZE - the number of nodes to malloc at once to save overhead: + */ + +#define NODE_BATCH_SIZE 100 + +/* + * The nodes we have malloced are kept in a linked list of bunches of + * NODE_BATCH_SIZE nodes. Nodes points to the first bunch on the list + * and current_bunch to the last. All nodes from the first one in the first + * bunch to the last_node_in_current_bunch_used'th one in the last bunch + * are in use. The others have not been used yet. + */ + +static struct _bunch_of_nodes { + struct _bunch_of_nodes *next_bunch; + Node nodes[NODE_BATCH_SIZE]; +} *nodes = NULL; +static struct _bunch_of_nodes *current_bunch = NULL; +static int last_node_in_current_bunch_used = -1; + +/* + * Internal Routine: + * + * Node *node_create(int opcode) + * Effects: Creates a node with opcode opcode and returns a pointer + * to it. The next pointer of the returned node is NULL. + * If the opcode is STRING_CONSTANT_OPCODE the caller must + * ensure that the string_constant field points to a valid + * string on the heap when node_DestroyAllNodes is called. + */ + +static Node * +node_create(int opcode) +{ + Node *result; + + if (!nodes) { + /* + * Handle special case where no nodes allocated yet: + */ + current_bunch = nodes = (struct _bunch_of_nodes *) + malloc(sizeof(struct _bunch_of_nodes)); + nodes->next_bunch = NULL; + last_node_in_current_bunch_used = -1; + } + + /* + * If all nodes allocated so far in use, allocate another + * bunch of NODE_BATCH_SIZE nodes: + */ + if (last_node_in_current_bunch_used == NODE_BATCH_SIZE-1) { + current_bunch->next_bunch = (struct _bunch_of_nodes *) + malloc(sizeof(struct _bunch_of_nodes)); + current_bunch = current_bunch->next_bunch; + current_bunch->next_bunch = NULL; + last_node_in_current_bunch_used = -1; + } + + /* + * Get next not already used node & ready it for use: + */ + last_node_in_current_bunch_used++; + result = &(current_bunch->nodes[last_node_in_current_bunch_used]); + result->opcode = opcode; + result->next = NULL; + + return(result); +} + +/* + * + */ + +void +node_DestroyAllNodes(void) +{ + struct _bunch_of_nodes *next_bunch; + int i, last_node_used_in_this_bunch; + + while (nodes) { + next_bunch = nodes->next_bunch; + last_node_used_in_this_bunch = next_bunch ? + NODE_BATCH_SIZE-1 : last_node_in_current_bunch_used; + for (i=0; i<=last_node_used_in_this_bunch; i++) { + if (nodes->nodes[i].opcode==STRING_CONSTANT_OPCODE) + free(nodes->nodes[i].d.string_constant); + else if (nodes->nodes[i].opcode==VARREF_OPCODE) + free(nodes->nodes[i].d.string_constant); + else if (nodes->nodes[i].opcode==VARNAME_OPCODE) + free(nodes->nodes[i].d.string_constant); + } + free(nodes); + nodes = next_bunch; + } + + current_bunch = nodes; +} + +/****************************************************************************/ +/* */ +/* Node construction functions: */ +/* */ +/****************************************************************************/ + +Node * +node_create_string_constant(int opcode, + string text) +{ + Node *n; + + n = node_create(opcode); + n->d.string_constant = text; + return(n); +} + +Node * +node_create_noary(int opcode) +{ + Node *n; + + n = node_create(opcode); + return(n); +} + +Node * +node_create_unary(int opcode, + Node *arg) +{ + Node *n; + + n = node_create(opcode); + n->d.nodes.first = arg; + return(n); +} + +Node * +node_create_binary(int opcode, + Node *first_arg, + Node *second_arg) +{ + Node *n; + + n = node_create(opcode); + n->d.nodes.first = first_arg; + n->d.nodes.second = second_arg; + return(n); +} + +/****************************************************************************/ +/* */ +/* Node utility functions: */ +/* */ +/****************************************************************************/ + +/* + * Node *reverse_list_of_nodes(Node *list) + * Modifies: the nodes on the linked list list + * Effects: Reverses the linked list list and returns it. + * This is done by modifing the next pointers of the + * list elements to point to the previous node & returning + * the address of the (previously) last node. + */ + +Node * +reverse_list_of_nodes(Node *list) +{ + Node *next_node; + Node *head = NULL; + + while (list) { + next_node = list->next; + + /* + * Add the node list to the beginning of linked list head: + */ + list->next = head; + head = list; + + list = next_node; + } + + return(head); +} + +/****************************************************************************/ +/* */ +/* Node display functions: */ +/* */ +/****************************************************************************/ + +#ifdef DEBUG + +static void +print_stuff(Node *node, + string format_string) +{ + char c; + + for (c=(*(format_string++)); c; c=(*(format_string++))) { + if (c!='%') { + putchar(c); + continue; + } + c=(*(format_string++)); + if (!c) { + format_string--; + continue; + } + if (c=='s') + printf("%s", node->d.string_constant); + else if (c=='1') + node_display(node->d.nodes.first); + else if (c=='2') + node_display(node->d.nodes.second); + else + putchar(c); + } +} + +static string how_to_print[] = { + "\"%s\"", /* constant string */ + "$%s", /* varref */ + "%s", /* varname */ + + "!%1", + + "( %1 + %2 )", + "( %1 and %2 )", + "( %1 or %2 )", + "( %1 == %2 )", + "( %1 != %2 )", + "( %1 =~ %2 )", + "( %1 !~ %2 )", + + "buffer()", + + "substitute(%1)", + "protect(%1)", + "verbatim(%1)", + "stylestrip(%1)", + "getenv(%1)", + "upcase(%1)", + "downcase(%1)", + "zvar(%1)", + "get(%1)", + + "lany(%1, %2)", + "rany(%1, %2)", + "lbreak(%1, %2)", + "rbreak(%1, %2)", + "lspan(%1, %2)", + "rspan(%1, %2)", + + "noop\n", + "set %1 = %2\n", + "fields %1\n", + + "print %1\n", + "clearbuf\n", + + "appendport %1 %2\n", + "execport %1 %2\n", + "inputport %1 %2\n", + "outputport %1 %2\n", + "put %1 %2\n", + "closeinput %1\n", + "closeoutput %1\n", + "closeport %1\n", + + "exec %1 %2\n", + + "%1endif\n", + "case %1\n%2endcase\n", + "while %1 do\n%2endwhile\n", + "break\n", + "exit\n", + + "if %1 then\n%2", + "elseif %1 then\n%2", + "else\n%2", + "match %1\n%2", + "default\n%2" }; + +void node_display(Node *node) +{ + int opcode = LAST_EXPR_OPCODE + 1; + + for (; node; node=node->next) { + if (opcode<=LAST_EXPR_OPCODE) + printf(" "); + + opcode = node->opcode; + if (opcode>=0 && opcode + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef node_MODULE +#define node_MODULE + +#include "new_string.h" + +#define STRING_CONSTANT_OPCODE 0 +#define VARREF_OPCODE 1 +#define VARNAME_OPCODE 2 + +#define NOT_OPCODE 3 + +#define PLUS_OPCODE 4 +#define AND_OPCODE 5 +#define OR_OPCODE 6 +#define EQ_OPCODE 7 +#define NEQ_OPCODE 8 +#define REGEQ_OPCODE 9 +#define REGNEQ_OPCODE 10 + +#define BUFFER_OPCODE 11 + +#define SUBSTITUTE_OPCODE 12 +#define PROTECT_OPCODE 13 +#define VERBATIM_OPCODE 14 +#define STYLESTRIP_OPCODE 15 +#define GETENV_OPCODE 16 +#define UPCASE_OPCODE 17 +#define DOWNCASE_OPCODE 18 +#define ZVAR_OPCODE 19 +#define GET_OPCODE 20 + +#define LANY_OPCODE 21 +#define RANY_OPCODE 22 +#define LBREAK_OPCODE 23 +#define RBREAK_OPCODE 24 +#define LSPAN_OPCODE 25 +#define RSPAN_OPCODE 26 + +#define LAST_EXPR_OPCODE 26 + +#define NOOP_OPCODE 27 +#define SET_OPCODE 28 +#define FIELDS_OPCODE 29 + +#define PRINT_OPCODE 30 +#define CLEARBUF_OPCODE 31 + +#define APPENDPORT_OPCODE 32 +#define EXECPORT_OPCODE 33 +#define INPUTPORT_OPCODE 34 +#define OUTPUTPORT_OPCODE 35 +#define PUT_OPCODE 36 +#define CLOSEINPUT_OPCODE 37 +#define CLOSEOUTPUT_OPCODE 38 +#define CLOSEPORT_OPCODE 39 + +#define EXEC_OPCODE 40 + +#define IF_STMT_OPCODE 41 +#define CASE_OPCODE 42 +#define WHILE_OPCODE 43 +#define BREAK_OPCODE 44 +#define EXIT_OPCODE 45 + +#define IF_OPCODE 46 +#define ELSEIF_OPCODE 47 +#define ELSE_OPCODE 48 +#define MATCHLIST_OPCODE 49 +#define DEFAULT_OPCODE 50 + +#define NUMBER_OF_OPCODES 51 + +typedef struct _Node { + int opcode; /* Read-only */ + struct _Node *next; + union { + string string_constant; + struct { + struct _Node *first; + struct _Node *second; + } nodes; + } d; +} Node; + +/* Function externs */ + +extern void node_DestroyAllNodes(void); + +extern Node *node_create_string_constant(int, string); + +extern Node *node_create_noary(int); +extern Node *node_create_unary(int, Node *); +extern Node *node_create_binary(int, Node *, Node *); + +/* + * Node *reverse_list_of_nodes(Node *list) + * Modifies: the nodes on the linked list list + * Effects: Reverses the linked list list and returns it. + * This is done by modifing the next pointers of the + * list elements to point to the previous node & returning + * the address of the (previously) last node. + */ + +extern Node *reverse_list_of_nodes(Node *); + +#ifdef DEBUG +extern void node_display(Node *); +#endif + +#endif diff --git a/zwgc/notice.c b/zwgc/notice.c new file mode 100644 index 0000000..21d0676 --- /dev/null +++ b/zwgc/notice.c @@ -0,0 +1,351 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_notice_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Module containing code to extract a notice's fields: */ +/* */ +/****************************************************************************/ + +#include +#include +#include "new_memory.h" +#include "error.h" +#include "variables.h" +#include "notice.h" +#ifdef CMU_ZWGCPLUS +#include +#include "plus.h" +#endif + +/* + * int count_nulls(char *data, int length) + * Requires: length>=0 + * Effects: Returns the # of nulls in data[0]..data[length-1] + */ + +int +count_nulls(char *data, + int length) +{ + int count = 0; + + for (; length; data++, length--) + if (!*data) + count++; + + return(count); +} + +/* + * string get_next_field(char **data_p, int *length_p) + * Requires: *length_p >= 0 + * Modifies: *data_p, *length_p + * Effects: Treats (*data_p)[0], (*data_p)[1], ... (*data_p)[length-1] + * as a series of null-seperated fields. This function + * returns a copy of the first field on the heap. This + * string must eventually be freed. Also, *data_p is + * advanced and *length_p decreased so that another + * call to this procedure with the same arguments will + * return the second field. The next call will return + * the third field, etc. "" is returned if 0 fields + * remain. (this is the case when *length_p == 0) + */ + +string +get_next_field(char **data_p, + int *length_p) +{ + char *data = *data_p; + int length = *length_p; + char *ptr; + + for (ptr=data; length; ptr++, length--) + if (!*ptr) { + *data_p = ptr+1; + *length_p = length-1; + return(string_Copy(data)); + } + + length = *length_p; + *data_p = ptr; + *length_p = 0; + return(string_CreateFromData(data, length)); +} + +/* + * string get_field(char *data, int length, int num) + * Requires: length>=0, num>0 + * Effects: Treats data[0]..data[length-1] as a series of + * null-seperated fields. This function returns a copy of + * the num'th field (numbered from 1 in this case) on the + * heap. This string must eventually be freed. If there + * is no num'th field (because num<1 or num># of fields), + * "" is returned. + */ + +string get_field(char *data, + int length, + int num) +{ + /* + * While num>1 and there are fields left, skip a field & decrement num: + */ + while (length && num>1) { + if (!*data) + num--; + length--; + data++; + } + + /* + * If any more fields left, the first field is the one we want. + * Otherwise, there is no such field as num -- return "". + */ + if (length) + return(get_next_field(&data, &length)); + else + return(string_Copy("")); +} + +/* + * string convert_nulls_to_newlines(data, length) + * Requires: length>=0, malloc never returns NULL + * Effects: Takes data[0]..data[length-1], converts all nulls to + * newlines ('\n') and returns the result as a null-terminated + * string on the heap. The returned string must eventually + * be freed. + */ + +string +convert_nulls_to_newlines(char *data, + int length) +{ + char *result, *ptr; + char c; + + result = (char *) malloc(length+1); + result[length] = '\0'; + + for (ptr=result; length; data++, ptr++, length--) + *ptr = (c = *data) ? c : '\n'; + + return(result); +} + + +/* + * Internal Routine: + * + * string z_kind_to_ascii(ZNotice_Kind_t z_kind) + * Effects: Returns an ascii representation for z_kind. + * The string returned is on the heap and must be freed + * eventually. + */ + +static string +z_kind_to_ascii(ZNotice_Kind_t z_kind) +{ + string result; + + switch (z_kind) { + case UNSAFE: + result = "unsafe"; + break; + + case UNACKED: + result = "unacked"; + break; + + case ACKED: + result = "acked"; + break; + + case HMACK: + result = "hmack"; + break; + + case HMCTL: + result = "hmctl"; + break; + + case SERVACK: + result = "servack"; + break; + + case SERVNAK: + result = "servnak"; + break; + + case CLIENTACK: + result = "clientack"; + break; + + case STAT: + result = "stat"; + break; + + default: + result = ""; + break; + } + + return(string_Copy(result)); +} + +/* + * Internal Routine: + * + * string z_auth_to_ascii(int z_auth) + * Effects: Returns an ascii representation for z_auth. + * The string returned is on the heap and must be freed + * eventually. + */ + +static string +z_auth_to_ascii(int z_auth) +{ + string result; + + switch (z_auth) { + case ZAUTH_FAILED: + result = "forged"; + break; + + case ZAUTH_NO: + result = "no"; + break; + + case ZAUTH_YES: + result = "yes"; + break; + + default: + result = "unknown"; + break; + } + + return(string_Copy(result)); +} + +/* + * char *decode_notice(ZNotice_t *notice) + * Modifies: various description language variables + * Effects: + */ + +char * +decode_notice(ZNotice_t *notice, + char *hostname) +{ + char *temp; + string when, notyear, year, date_string, time_string; + + /* + * Convert useful notice fields to ascii and store away in + * description language variables for later use by the + * the user's program: + */ + var_set_variable("zephyr_version", notice->z_version); + var_set_variable("class", notice->z_class); + var_set_variable("instance", notice->z_class_inst); + var_set_variable("opcode", notice->z_opcode); + var_set_variable("default", notice->z_default_format); + var_set_variable("notice_charset", (char *)ZCharsetToString(notice->z_charset)); /*XXX const*/ + var_set_variable("recipient", + (notice->z_recipient[0] ? notice->z_recipient : "*")); + var_set_variable("fullsender", notice->z_sender); + var_set_variable_to_number("port", (int)ntohs(notice->z_port)); + var_set_variable_then_free_value("kind", z_kind_to_ascii(notice->z_kind)); + var_set_variable_then_free_value("auth", z_auth_to_ascii(notice->z_auth)); + +#ifdef CMU_ZWGCPLUS + if ((temp=getSelectedText()) != 0) + var_set_variable("selection", temp); + + var_set_variable("delete_window", "none"); + var_set_variable("event_time", "none"); + var_set_variable("event_name", "event"); +#endif + /* + * Set $sender to the name of the notice sender except first strip off the + * realm name if it is the local realm: + */ + if ( (temp=strchr(notice->z_sender,'@')) && string_Eq(temp+1, ZGetRealm()) ) + var_set_variable_then_free_value("sender", + string_CreateFromData(notice->z_sender, + temp-notice->z_sender)); + else + var_set_variable("sender", notice->z_sender); +#ifdef CMU_ZWGCPLUS + if (get_full_names) { + struct passwd *pwnam = getpwnam(var_get_variable("sender")); + if (pwnam) { + temp = string_Copy(pwnam->pw_gecos); + var_set_variable_then_free_value("sendername", temp); + } else { + var_set_variable("sendername", "unknown"); + } + } +#endif + + /* + * Convert time & date notice was sent to ascii. The $time + * has the format "01:03:52" while $date has the format + * "Sun Sep 16 1973". + */ + { + /* the fields of struct timeval might not be the right type to pass + to ctime, so use a temporary */ + time_t sec = notice->z_time.tv_sec; + when = ctime(&sec); + } + time_string = string_CreateFromData(when+11,8); + var_set_variable_then_free_value("time", time_string); + date_string = string_Concat(notyear=string_CreateFromData(when,11), + year=string_CreateFromData(when+20,4)); + var_set_variable_then_free_value("date", date_string); + free(notyear); + free(year); + + /* + * Convert host notice sent from to ascii: + */ + var_set_variable("fromhost", hostname ? hostname : + inet_ntoa(notice->z_sender_addr)); + + /* + * Set $message to the message field of the notice with nulls changed + * to newlines: + */ + var_set_variable_then_free_value("message", + convert_nulls_to_newlines(notice->z_message, + notice->z_message_len)); + + /* + * Decide if its a control notice. If so, return the notice's + * opcode. Otherwise, return NULL: + */ + if ((strcasecmp(notice->z_class, WG_CTL_CLASS)==0) && /* <<<>>> */ + (strcasecmp(notice->z_class_inst, WG_CTL_USER)==0)) + return(notice->z_opcode); + return(0); +} diff --git a/zwgc/notice.h b/zwgc/notice.h new file mode 100644 index 0000000..ad6635d --- /dev/null +++ b/zwgc/notice.h @@ -0,0 +1,75 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef notice_MODULE +#define notice_MODULE + +#include +#include "new_string.h" + +/* + * int count_nulls(char *data, int length) + * Requires: length>=0 + * Effects: Returns the # of nulls in data[0]..data[length-1] + */ + +extern int count_nulls(char *, int); + +/* + * string get_next_field(char **data_p, int *length_p) + * Requires: *length_p >= 0 + * Modifies: *data_p, *length_p + * Effects: Treats (*data_p)[0], (*data_p)[1], ... (*data_p)[length-1] + * as a series of null-seperated fields. This function + * returns a copy of the first field on the heap. This + * string must eventually be freed. Also, *data_p is + * advanced and *length_p decreased so that another + * call to this procedure with the same arguments will + * return the second field. The next call will return + * the third field, etc. "" is returned if 0 fields + * remain. (this is the case when *length_p == 0) + */ + +extern string get_next_field(char **, int *); + +/* + * string get_field(char *data, int length, int num) + * Requires: length>=0, num>0 + * Effects: Treats data[0]..data[length-1] as a series of + * null-seperated fields. This function returns a copy of + * the num'th field (numbered from 1 in this case) on the + * heap. This string must eventually be freed. If there + * is no num'th field (because num<1 or num># of fields), + * "" is returned. + */ + +extern string get_field(char *, int, int); + +/* + * string convert_nulls_to_newlines(data, length) + * Requires: length>=0, malloc never returns NULL + * Effects: Takes data[0]..data[length-1], converts all nulls to + * newlines ('\n') and returns the result as a null-terminated + * string on the heap. The returned string must eventually + * be freed. + */ + +extern string convert_nulls_to_newlines(char *, int); + + +extern char *decode_notice(ZNotice_t *, char *); + +#endif diff --git a/zwgc/parser.h b/zwgc/parser.h new file mode 100644 index 0000000..92724dd --- /dev/null +++ b/zwgc/parser.h @@ -0,0 +1,54 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef parser_MODULE +#define parser_MODULE + +/* + * Parser-Lexer Internal Routine: + * + * void report_parse_error(char *error_message, int line_number) + * Modifies: error_occured, stderr + * Effects: This routine is called to report a parser or lexer + * error. Error_message is the error message and line_number + * the line number it occured on. The reported error message + * is of the form ".... on line .\n". + * This routine sets error_occured (local to parser.y) to + * true. If it was previously false, the error message + * is reported to the user via stderr. + */ + +extern void report_parse_error(char *, int); + +/* + * struct _Node *parse_file(FILE *input_file) + * Requires: input_file is opened for reading, no pointers to + * existing nodes will ever be dereferened. + * Modifies: *input_file, stderr, all existing nodes + * Effects: First this routine destroys all nodes. Then it parses + * input_file as a zwgc description langauge file. If + * an error is encountered, an error message is printed + * on stderr and NULL is returned. If no error is + * encountered, a pointer to the node representation of + * the parsed program is returned, suitable for passing to + * exec.c. Note that NULL will also be returned for a + * empty file & is a valid program. Either way, input_file + * is closed before this routine returns. + */ + +extern struct _Node *parse_file(FILE *); + +#endif diff --git a/zwgc/parser.y b/zwgc/parser.y new file mode 100644 index 0000000..30f4088 --- /dev/null +++ b/zwgc/parser.y @@ -0,0 +1,387 @@ +%{ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_parser_y[] = "$Id$"; +#endif + +#include + +/* Saber-C suppressions because yacc loses */ + +/*SUPPRESS 288*/ +/*SUPPRESS 287*/ + +#include +#include "lexer.h" +#include "parser.h" +#include "node.h" +#include "zwgc.h" + +static void yyerror(char *); + +/* + * the_program - local variable used to communicate the program's node + * representation from the program action to the parse_file + * function. + */ + +static Node *the_program; +%} + +%union{ + char *text; + struct _Node *node; +} + +%start program + +%token ERROR +%token VARNAME VARREF STRING SHOW + +%token APPENDPORT BUFFER BREAK CLOSEINPUT CLOSEOUTPUT +%token CLOSEPORT CASE CLEARBUF DEFAULT DISPLAY DO DOWNCASE +%token ELSE ELSEIF ENDCASE ENDIF ENDWHILE EXEC EXECPORT EXIT +%token FIELDS GET GETENV IF INPUTPORT LANY LBREAK LSPAN +%token MATCH NOOP NOT OUTPUTPORT PRINT PROTECT VERBATIM PUT RANY RBREAK +%token RSPAN SET SUBSTITUTE THEN UPCASE WHILE ZVAR STYLESTRIP + +%type expr varname string +%type exprlist comma_exprlist varnamelist +%type statement statements program elseparts elseifparts +%type match matchlist + +%left '|' +%left '&' +%left EQ NEQ REGEQ REGNEQ +%left '+' +%left '!' + +%% + +/* + * A program is simply a list of statements: (may be NULL if no statements...) + */ +program : statements + { the_program = reverse_list_of_nodes($1); + $$ = the_program; } + ; + +varname : VARNAME + { $$ = node_create_string_constant(VARNAME_OPCODE, $1); } + ; + +string : STRING + { $$ = node_create_string_constant(STRING_CONSTANT_OPCODE, $1); } + ; + +expr : '(' expr ')' + { $$ = $2; } + + | string + { $$ = $1; } + | VARREF + { $$ = node_create_string_constant(VARREF_OPCODE, $1); } + + | '!' expr + { $$ = node_create_unary(NOT_OPCODE, $2); } + + | expr '+' expr + { $$ = node_create_binary(PLUS_OPCODE, $1, $3); } + | expr '|' expr /* note "or" == '|' */ + { $$ = node_create_binary(OR_OPCODE, $1, $3); } + | expr '&' expr /* note "and" == '&' */ + { $$ = node_create_binary(AND_OPCODE, $1, $3); } + | expr EQ expr + { $$ = node_create_binary(EQ_OPCODE, $1, $3); } + | expr NEQ expr + { $$ = node_create_binary(NEQ_OPCODE, $1, $3); } + | expr REGEQ expr + { $$ = node_create_binary(REGEQ_OPCODE, $1, $3); } + | expr REGNEQ expr + { $$ = node_create_binary(REGNEQ_OPCODE, $1, $3); } + + | BUFFER '(' ')' + { $$ = node_create_noary(BUFFER_OPCODE); } + + | SUBSTITUTE '(' expr ')' + { $$ = node_create_unary(SUBSTITUTE_OPCODE, $3); } + | PROTECT '(' expr ')' + { $$ = node_create_unary(PROTECT_OPCODE, $3); } + | VERBATIM '(' expr ')' + { $$ = node_create_unary(VERBATIM_OPCODE, $3); } + | GETENV '(' expr ')' + { $$ = node_create_unary(GETENV_OPCODE, $3); } + | UPCASE '(' expr ')' + { $$ = node_create_unary(UPCASE_OPCODE, $3); } + | DOWNCASE '(' expr ')' + { $$ = node_create_unary(DOWNCASE_OPCODE, $3); } + | ZVAR '(' expr ')' + { $$ = node_create_unary(ZVAR_OPCODE, $3); } + | GET '(' expr ')' + { $$ = node_create_unary(GET_OPCODE, $3); } + | STYLESTRIP '(' expr ')' + { $$ = node_create_unary(STYLESTRIP_OPCODE, $3); } + + | LANY '(' expr ',' expr ')' + { $$ = node_create_binary(LANY_OPCODE, $3, $5 ); } + | RANY '(' expr ',' expr ')' + { $$ = node_create_binary(RANY_OPCODE, $3, $5 ); } + | LBREAK '(' expr ',' expr ')' + { $$ = node_create_binary(LBREAK_OPCODE, $3, $5 ); } + | RBREAK '(' expr ',' expr ')' + { $$ = node_create_binary(RBREAK_OPCODE, $3, $5 ); } + | LSPAN '(' expr ',' expr ')' + { $$ = node_create_binary(LSPAN_OPCODE, $3, $5 ); } + | RSPAN '(' expr ',' expr ')' + { $$ = node_create_binary(RSPAN_OPCODE, $3, $5 ); } + ; + +statement : NOOP + { $$ = node_create_noary(NOOP_OPCODE); } + | SET varname '=' expr + { $$ = node_create_binary(SET_OPCODE, $2, $4); } + | FIELDS varnamelist + { $$ = node_create_unary(FIELDS_OPCODE, + reverse_list_of_nodes($2)); } + + /* + * Output to & control of output buffer statements: + */ + | PRINT exprlist + { $$ = node_create_unary(PRINT_OPCODE, + reverse_list_of_nodes($2)); } + | SHOW + { $$ = node_create_unary(PRINT_OPCODE, + node_create_unary(SUBSTITUTE_OPCODE, + node_create_string_constant(STRING_CONSTANT_OPCODE, + $1))); } + | CLEARBUF + { $$ = node_create_noary(CLEARBUF_OPCODE); } + + /* + * Statements to manage ports: + */ + | APPENDPORT expr expr + { $$ = node_create_binary(APPENDPORT_OPCODE, $2, $3); } + | EXECPORT expr expr exprlist + { $3->next = reverse_list_of_nodes($4); + $$ = node_create_binary(EXECPORT_OPCODE, $2, $3); } + | INPUTPORT expr expr + { $$ = node_create_binary(INPUTPORT_OPCODE, $2, $3); } + | OUTPUTPORT expr expr + { $$ = node_create_binary(OUTPUTPORT_OPCODE, $2, $3); } + | PUT expr exprlist + { $$ = node_create_binary(PUT_OPCODE, $2, + reverse_list_of_nodes($3)); } + | PUT + { $$ = node_create_binary(PUT_OPCODE, 0, 0); } + | CLOSEINPUT expr + { $$ = node_create_unary(CLOSEINPUT_OPCODE, $2); } + | CLOSEOUTPUT expr + { $$ = node_create_unary(CLOSEOUTPUT_OPCODE, $2); } + | CLOSEPORT expr + { $$ = node_create_unary(CLOSEPORT_OPCODE, $2); } + + /* + * Statements to run subprocesses without I/O to them: + */ + | EXEC expr exprlist + { $2->next = reverse_list_of_nodes($3); + $$ = node_create_unary(EXEC_OPCODE, $2); } + + /* + * Control statements: + */ + | IF expr THEN statements elseparts ENDIF + { Node *n = node_create_binary(IF_OPCODE, $2, + reverse_list_of_nodes($4)); + n->next = $5; + $$ = node_create_unary(IF_STMT_OPCODE, n); } + | CASE expr matchlist ENDCASE + { $$ = node_create_binary(CASE_OPCODE, $2, + reverse_list_of_nodes($3)); } + | WHILE expr DO statements ENDWHILE + { $$ = node_create_binary(WHILE_OPCODE, $2, + reverse_list_of_nodes($4)); } + | BREAK + { $$ = node_create_noary(BREAK_OPCODE); } + | EXIT + { $$ = node_create_noary(EXIT_OPCODE); } + ; + +elseparts : elseifparts + { $$ = reverse_list_of_nodes($1); } + | elseifparts ELSE statements + { $$ = node_create_binary(ELSE_OPCODE, 0, + reverse_list_of_nodes($3)); + $$->next = $1; + $$ = reverse_list_of_nodes($$); } + ; + +/* elseifparts needs to be reversed before using... */ +elseifparts : /* empty */ + { $$ = 0; } + | elseifparts ELSEIF expr THEN statements + { $$ = node_create_binary(ELSEIF_OPCODE, $3, + reverse_list_of_nodes($5)); + $$->next = $1; } + ; + +match : MATCH comma_exprlist statements + { $$ = node_create_binary(MATCHLIST_OPCODE, + reverse_list_of_nodes($2), + reverse_list_of_nodes($3)); } + | DEFAULT statements + { $$ = node_create_binary(DEFAULT_OPCODE, 0, + reverse_list_of_nodes($2)); } + ; + +/* + * Various lists of non-terminals like expr's and varname's. Each is + * built up as a linked list using the nodes' next fields. To prevent + * Yacc stack overflow on long lists, these are put on the linked list + * BACKWARDS. The user of these must first call reverse_list_of_nodes + * on one of these before using it. All except comma_exprlist + * allow 0 elements on the list in which case their value is NULL. + * (comma_exprlist requires at least one element) + */ + +exprlist : /* empty */ + { $$ = 0; } + | exprlist expr + { $$ = $2; + $$->next = $1; } + ; + +comma_exprlist : expr + { $$ = $1; } + | comma_exprlist ',' expr + { $$ = $3; + $$->next = $1; } + ; + +varnamelist : /* empty */ + { $$ = 0; } + | varnamelist varname + { $$ = $2; + $$->next = $1; } + ; + +matchlist : /* empty */ + { $$ = 0; } + | matchlist match + { $$ = $2; + $$->next = $1; } + ; + +statements : /* empty */ + { $$ = 0; } + | statements statement + { $$ = $2; + $$->next = $1; } + ; + +%% + +/* + * error_occured - Set to true when a parse error is reported. If it is false + * at the time a parse error is reported, a message is + * printed on stderr. See report_parse_error for more + * details. + */ + +static int error_occured = 0; + +/* + * Parser-Lexer Internal Routine: + * + * void report_parse_error(char *error_message, int line_number) + * Modifies: error_occured, stderr + * Effects: This routine is called to report a parser or lexer + * error. Error_message is the error message and line_number + * the line number it occured on. The reported error message + * is of the form ".... on line .\n". + * This routine sets error_occured (local to parser.y) to + * true. If it was previously false, the error message + * is reported to the user via stderr. + */ + +void +report_parse_error(char *error_message, + int line_number) +{ + if (error_occured) + return; + error_occured = 1; + + fprintf(stderr, "zwgc: error in description file: %s on line %d.\n", + error_message, line_number); + fflush(stderr); +} + +/* + * yyerror - internal routine - used by yacc to report syntax errors and + * stack overflow errors. + */ + +static void yyerror(char *message) +{ + report_parse_error(message, yylineno); +} + +/* + * struct _Node *parse_file(FILE *input_file) + * Requires: input_file is opened for reading, no pointers to + * existing nodes will ever be dereferened. + * Modifies: *input_file, stderr, all existing nodes + * Effects: First this routine destroys all nodes. Then it parses + * input_file as a zwgc description langauge file. If + * an error is encountered, an error message is printed + * on stderr and NULL is returned. If no error is + * encountered, a pointer to the node representation of + * the parsed program is returned, suitable for passing to + * exec.c. Note that NULL will also be returned for a + * empty file & is a valid program. Either way, input_file + * is closed before this routine returns. + */ + +struct _Node * +parse_file(FILE *input_file) +{ + the_program = NULL; + error_occured = 0; + node_DestroyAllNodes(); + + lex_open(input_file); + yyparse(); + fclose(input_file); + + if (error_occured) { + node_DestroyAllNodes(); + the_program = NULL; + } + +#ifdef DEBUG + if (zwgc_debug) { + printf("****************************************************************************\n"); + node_display(the_program); + printf("****************************************************************************\n"); + } +#endif + + return(the_program); +} diff --git a/zwgc/plus.c b/zwgc/plus.c new file mode 100644 index 0000000..761109c --- /dev/null +++ b/zwgc/plus.c @@ -0,0 +1,499 @@ +/* + This file contains code related to the zwgcplus extension to zwgc. + zwgc is copyrighted by the Massachusetts Institute of Technology. + This file is public domain. + Written by Andrew Plotkin, ap1i+@andrew.cmu.edu + Timequeue code added by Ryan Ingram, ryani+@andrew.cmu.edu + Rewritten for incorporation into MIT zwgc from 2.0.2 by Derrick Brashear + */ + +#include +#ifdef CMU_ZWGCPLUS +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_plus_c[] = "$Id$"; +#endif + +#include +#include + +#include "new_memory.h" +#include "node.h" +#include "exec.h" +#include "eval.h" +#include "node.h" +#include "buffer.h" +#include "port.h" +#include "variables.h" +#include "notice.h" +#include "X_gram.h" +#include "xrevstack.h" +#include "main.h" +#include "plus.h" + +int get_full_names = 0; + +#define HASHSIZE (251) + +typedef struct timenode_s { + ZNotice_t *notice; + struct timenode_s *next; + time_t when; + char *event_name; +} TimeNode; + +typedef struct _notnode { + ZNotice_t *notice; + int fake_notice; /* if TRUE, do not call ZFreeNotice() */ + int refcount; + struct _notnode *next; + char *opcode; + char *hname; +} notnode; + +static ZNotice_t *stored_notice; +static notnode *notlist[HASHSIZE]; +TimeNode *timeq_head = NULL; + +int list_hash_fun(ZNotice_t *notice); + +static TimeNode * +addtimenode(TimeNode *head, TimeNode *node) +{ + if(head == NULL) { +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "adding new timenode; creating queue\n"); +#endif + node->next = NULL; + return node; + } + + if(head->when > node->when) { +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "adding new timenode at start of queue\n"); +#endif + node->next = head; + return node; + } + + head->next = addtimenode(head->next, node); + return head; +} + +static void +handle_timeq_event(TimeNode *event) +{ + char buf[128]; + notnode *pt; + int bx = list_hash_fun(event->notice); + + for (pt=notlist[bx]; pt && pt->notice!=event->notice; pt=pt->next); + + /* "time-" + event_name + '\0' */ +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "handle_timeq_event()\n"); +#endif + + if (strlen(event->event_name)<123) + sprintf(buf, "time-%s", event->event_name); + else + sprintf(buf, "time-bogus"); + +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "opcode: %s\n", buf); +#endif + + event->notice->z_version = "zwgcplus-repeat"; + event->notice->z_opcode = buf; + + reprocess_notice(event->notice, pt->hname); + +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "end handle_timeq_event()\n"); +#endif +} + +static void +schedule_event(long secs, char *name, ZNotice_t *notice) +{ + time_t eventtime = (time(NULL)) + secs; + TimeNode *newnode; + char *buf; + +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "schedule_event(%ld, %ld, %s)\n", eventtime, secs, name); +#endif + + if(!notice || !name) return; + + list_add_notice(notice); + + newnode = (TimeNode *)malloc(sizeof(TimeNode)); + buf = (char *)malloc(strlen(name) + 1); + + strcpy(buf, name); + +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "name: %s\n", buf); +#endif + + newnode->when = eventtime; + newnode->event_name = buf; + newnode->notice = notice; + + timeq_head = addtimenode(timeq_head, newnode); +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "end schedule_event()\n"); +#endif +} + +static void +free_timenode(TimeNode *node) +{ +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "free_timenode(%s)\n", node->event_name); +#endif + + free(node->event_name); + free(node); +} + +/* returns the number of notices destroyed */ +static int +destroy_timeq_notice(ZNotice_t *notice, char *name) +{ + TimeNode *curr = timeq_head; + TimeNode *prev = NULL; + TimeNode *tmp; + + int ct = 0; + +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "destroy_timeq_notice(%s)\n", name); +#endif + + while(curr != NULL) { + if(curr->notice == notice && + (!name || !strcmp(curr->event_name, name))) + { + ct++; + if(!prev) { + timeq_head = curr->next; + } else { + prev->next = curr->next; + } + tmp = curr; + curr = curr->next; + free_timenode(tmp); + } else { + prev = curr; + curr = curr->next; + } + } + + return ct; +} + +long +plus_timequeue_events(void) +{ + /* returns number of seconds to the next event or 0L */ + /* if there are no events remaining to be processed */ + + time_t timenow = time(NULL); + TimeNode *curr; + + while(timeq_head != NULL && timeq_head->when <= timenow) { +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "handling event\n"); +#endif + handle_timeq_event(timeq_head); + curr = timeq_head; + timeq_head = timeq_head->next; + free_timenode(curr); + } + +#ifdef DEBUG_TIMEQUEUE + if(timeq_head != NULL) + fprintf(stderr, "next event in %ld seconds.\n", + (timeq_head->when) - timenow); +#endif + + return ((timeq_head == NULL) ? 0L : ((timeq_head->when) - timenow)); +} + +void +plus_set_hname(ZNotice_t *notice, char *hname) +{ + notnode *pt; + int bx; + + if (hname) { + bx = list_hash_fun(notice); + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + pt->hname=(char *)malloc(strlen(hname)+1); + strcpy(pt->hname, hname); + } + return; +} + +void +plus_queue_notice(ZNotice_t *notice) +{ + char *val; + int howlong = 0; + +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "plus_queue_notice()\n"); +#endif + + val = var_get_variable("event_time"); + if(val) { + if(strcmp(val, "kill")) { + howlong = atoi(val); +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "$event_time %d\n", howlong); +#endif + } else { + val = var_get_variable("event_name"); + if(!val || strcmp(val, "all")) + destroy_timeq_notice(notice, (val && val[0]) ? val : "event"); + else + destroy_timeq_notice(notice, (char *)NULL); + } + } + + if(howlong > 0) { + val = var_get_variable("event_name"); +#ifdef DEBUG_TIMEQUEUE + fprintf(stderr, "$event_name = %s\n", val); +#endif + schedule_event(howlong, (val && val[0]) ? val : "event", notice); + } +} + +int +list_hash_fun(ZNotice_t *notice) +{ + unsigned int ix; + int res = 0, val = 1, ptval; + char *pt = (char *)(notice); + + for (ix=0; ixnext) { + fprintf(stderr, "Not %p: %d [%d]\n", (void *)pt->notice, + pt->refcount, bx); + } + } +} + +/* add notice to table. Either generate a new entry, or increment ref count. */ +void +list_add_notice(ZNotice_t *notice) +{ + notnode *pt; + int bx = list_hash_fun(notice); + + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + + if (pt) { + /* found entry */ + pt->refcount++; + } + else { + /* no entry */ + pt = (notnode *)malloc(sizeof(notnode)); + pt->notice = notice; + pt->refcount = 1; + pt->fake_notice = 0; + pt->next = notlist[bx]; + pt->opcode = notice->z_opcode; + pt->hname = NULL; + notlist[bx] = pt; + } + + /*fprintf(stderr, "list_add_notice(%p)\n", notice); + dump_noticelist();*/ +} + +/* remove notice from table. If refcount reaches 0, return 1; if refcount is + still positive, return 0; if notice not there, return -1. */ +int +list_del_notice(ZNotice_t *notice) +{ + notnode *pt, **ppt; + int bx = list_hash_fun(notice); + + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + + if (!pt) { + /* no entry */ + /*fprintf(stderr, "list_del_notice(%p): ERROR\n", notice); + dump_noticelist();*/ + return (-1); + } + + pt->refcount--; + if (pt->refcount > 0) { + /*fprintf(stderr, "list_del_notice(%p): count %d\n", notice, pt->refcount); + dump_noticelist();*/ + return 0; + } + + for (ppt = &(notlist[bx]); (*ppt)!=pt; ppt = &((*ppt)->next)); + + *ppt = (*ppt)->next; + + if (!pt->fake_notice) + ZFreeNotice(pt->notice); + if (pt->hname) + free(pt->hname); + free(pt->notice); + free(pt); + + /*fprintf(stderr, "list_del_notice(%p): count 0, gone\n", notice);*/ + /*dump_noticelist();*/ + return 1; +} + +void +set_notice_fake(ZNotice_t *notice, int val) +{ + notnode *pt; + int bx = list_hash_fun(notice); + + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + + if (pt) { + pt->fake_notice = val; + } +} + +int +get_notice_fake(ZNotice_t *notice) +{ + notnode *pt; + int bx = list_hash_fun(notice); + + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + + if (pt) { + return pt->fake_notice; + } + else + return 0; +} + +int +get_list_refcount(ZNotice_t *notice) +{ + notnode *pt; + int bx = list_hash_fun(notice); + + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + + if (pt) { + /*fprintf(stderr, "get_list_refcount(%p): count %d\n", notice, pt->refcount);*/ + return pt->refcount; + } + else { + /*fprintf(stderr, "get_list_refcount(%p): count 0\n", notice);*/ + return 0; + } +} + +/* export a reference to the current notice. */ +ZNotice_t * +get_stored_notice(void) +{ + if (!stored_notice) + return NULL; + + list_add_notice(stored_notice); + + return stored_notice; +} + +void +set_stored_notice(ZNotice_t *notice) +{ + stored_notice = notice; +} + +void +plus_retry_notice(ZNotice_t *notice, char ch, int metaflag) +{ + char buf[128]; + char *tmp; + notnode *pt; + int bx; + + if (!notice) + return; + + bx = list_hash_fun(notice); + for (pt=notlist[bx]; pt && pt->notice!=notice; pt=pt->next); + + if (metaflag) tmp = "-meta"; + else tmp = ""; + + if (ch==' ') + sprintf(buf, "key%s-space", tmp); + else if (ch==127) + sprintf(buf, "key%s-delete", tmp); + else if (ch==0) + sprintf(buf, "key%s-ctrl-@", tmp); + else if (ch==27) + sprintf(buf, "key%s-esc", tmp); + else if (isprint(ch)) + sprintf(buf, "key%s-%c", tmp, ch); + else if (ch>=1 && ch<=26) + sprintf(buf, "key%s-ctrl-%c", tmp, ch+'a'-1); + else if (iscntrl(ch)) + sprintf(buf, "key%s-ctrl-%c", tmp, ch+'A'-1); + else + sprintf(buf, "key%s-unknown", tmp); + + /* concat the old opcode if they're running in "new" mode */ + if (zwgcplus == 2 && pt && pt->opcode[0] && + strcmp(pt->opcode, "") != 0) + { + strcat(buf, " "); + strncat(buf, pt->opcode, sizeof(buf)-strlen(buf)); + } + + notice->z_version = "zwgcplus-repeat"; + notice->z_opcode = buf; + + reprocess_notice(notice, NULL); +} +#endif /* CMU_ZWGCPLUS */ diff --git a/zwgc/plus.h b/zwgc/plus.h new file mode 100644 index 0000000..e6e5183 --- /dev/null +++ b/zwgc/plus.h @@ -0,0 +1,29 @@ +/* + This file contains code related to the zwgcplus extension to zwgc. + zwgc is copyrighted by the Massachusetts Institute of Technology. + This file is public domain. + Written by Andrew Plotkin, ap1i+@andrew.cmu.edu + */ + +#define NAMESIZE (256) + +extern int get_full_names; +extern int zwgcplus; + +extern void init_noticelist(void); +extern void dump_noticelist(void); +extern void list_add_notice(ZNotice_t *notice); +extern int list_del_notice(ZNotice_t *notice); +extern int get_list_refcount(ZNotice_t *notice); +extern void set_notice_fake(ZNotice_t *notice, int val); +extern int get_notice_fake(ZNotice_t *notice); +extern ZNotice_t *get_stored_notice(void); +extern void plus_retry_notice(ZNotice_t *notice, char ch, int metaflag); +extern void set_stored_notice(ZNotice_t *notice); +extern void plus_window_deletions(ZNotice_t *notice); /* actually in xshow.c */ + +extern void plus_queue_notice(ZNotice_t *notice); +extern long plus_timequeue_events(void); +void plus_set_hname(ZNotice_t *notice, char *hname); + +extern char *getSelectedText(void); /* actually in xcut.c */ diff --git a/zwgc/pointer.h b/zwgc/pointer.h new file mode 100644 index 0000000..7d8332d --- /dev/null +++ b/zwgc/pointer.h @@ -0,0 +1,26 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef pointer_MODULE +#define pointer_MODULE + +#ifdef __STDC__ +typedef void *pointer; +#else +typedef char *pointer; +#endif + +#endif diff --git a/zwgc/port.c b/zwgc/port.c new file mode 100644 index 0000000..3d73a69 --- /dev/null +++ b/zwgc/port.c @@ -0,0 +1,656 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_port_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* The Implementation of the port type: */ +/* */ +/****************************************************************************/ + +#include "new_string.h" +#include "port_dictionary.h" +#include "port.h" +#include "notice.h" +#include "variables.h" + +/****************************************************************************/ +/* */ +/* Port methods (internal): */ +/* */ +/****************************************************************************/ + +static string +port_get(port *p) +{ + char *(*get_proc)(port *, char **); + char *error = NULL; + char *result; + + if (p->status & INPUT_CLOSED) { + var_set_variable("error", + "Attempt to read from a port whose input has been closed"); + return(string_Copy("")); + } + + get_proc = p->get; + if (!get_proc) { + var_set_variable("error", + "Attempt to read from a port which does not support reading"); + return(string_Copy("")); + } + + result = get_proc(p, &error); + if (!result) { + var_set_variable("error", error); + return(string_Copy("")); + } else + return(result); +} + +static void +port_put(port *p, + char *data, + int length) +{ + char *(*put_proc)(port *, char *, int); + char *error; + + if (p->status & OUTPUT_CLOSED) { + var_set_variable("error", + "Attempt to write to a port whose output has been closed"); + return; + } + + put_proc = p->put; + if (!put_proc) { + var_set_variable("error", + "Attempt to write to a port which does not support writing"); + return; + } + + error = put_proc(p, data, length); + if (error) + var_set_variable("error", error); +} + +static void +port_close_input(port *p) +{ + char *(*close_input_proc)(port *); + char *error; + + if (p->status & INPUT_CLOSED) + return; + p->status |= INPUT_CLOSED; + + close_input_proc = p->close_input; + if (!close_input_proc) + return; + + error = close_input_proc(p); + if (error) + var_set_variable("error", error); +} + +static void +port_close_output(port *p) +{ + char *(*close_output_proc)(port *); + char *error; + + if (p->status & OUTPUT_CLOSED) + return; + p->status |= OUTPUT_CLOSED; + + close_output_proc = p->close_output; + if (!close_output_proc) + return; + + error = close_output_proc(p); + if (error) + var_set_variable("error", error); +} + +/****************************************************************************/ +/* */ +/* Code to implement a namespace of ports: */ +/* */ +/****************************************************************************/ + +/* + * port_dict - the dictionary mapping portnames to ports + */ + +static port_dictionary port_dict = NULL; + +/* + * void init_ports() + * Modifies: all ports + * Effects: Closes all existing ports. Must be called before + * any other port call is made. + */ + +static void +close_port_from_binding(port_dictionary_binding *b) +{ + port_close_input(&(b->value)); + port_close_output(&(b->value)); +} + +void +init_ports(void) +{ + if (port_dict) { + port_dictionary_Enumerate(port_dict, close_port_from_binding); + port_dictionary_Destroy(port_dict); + } + + port_dict = port_dictionary_Create(31); +} + +/* + * Internal Routine: + * + * port *create_named_port(string name) + * Modifies: the port named name + * Requires: init_ports has been called + * Effects: If a port with name name already exists, it is first + * closed (& destroyed). A new unfilled in port is then + * created and assigned the name name. Its address is + * then returned. It is up to the caller to fill in its + * various fields correctly. + */ + +static port * +create_named_port(string name) +{ + int already_exists; + port_dictionary_binding *binding; + + binding = port_dictionary_Define(port_dict, name, &already_exists); + if (already_exists) { + port_close_input(&(binding->value)); + port_close_output(&(binding->value)); + } + + return(&(binding->value)); +} + +/* + * Internal Routine: + * + * port *get_named_port(string name) + * Requires: init_ports has been called + * Effects: If there is a port by name name, returns a pointer to + * it. Otherwise returns NULL. + */ + +static port * +get_named_port(string name) +{ + port_dictionary_binding *binding; + + binding = port_dictionary_Lookup(port_dict, name); + if (!binding) + return(NULL); + + return(&(binding->value)); +} + +/****************************************************************************/ +/* */ +/* External interface to named ports: */ +/* */ +/****************************************************************************/ + +/* + * string read_from_port(string name) + * Requires: init_ports has been called + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns "". Otherwise, attempts to + * read from that port. If an error occurs, $error is + * set to the error message and "" returned. Otherwise + * the read string is returned. The returned string is + * on the heap & must be eventually freed. + */ + +string +read_from_port(string name) +{ + port *p; + + if (!(p = get_named_port(name))) { + var_set_variable("error", "No such port"); + return(string_Copy("")); + } + + return(port_get(p)); +} + +/* + * void write_on_port(string name, char *text, int length) + * Requires: init_ports has been called, length>=0 + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns. Otherwise, attempts to + * write text[0..length-1] on that port. If an error + * occurs, $error is set to the error message. + */ + +void +write_on_port(string name, + char *text, + int length) +{ + port *p; + + if (!(p = get_named_port(name))) { + var_set_variable("error", "No such port"); + return; + } + + port_put(p, text, length); +} + +/* + * void close_port_input(string name) + * Requires: init_ports has been called + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns. Otherwise, closes the + * input part of the port by name name. When both a + * port's input & output parts have been closed, the + * port is deleted to save space. If an error + * occurs, $error is set to the error message. + */ + +void +close_port_input(string name) +{ + port_dictionary_binding *binding; + + binding = port_dictionary_Lookup(port_dict, name); + if (!binding) + return; + + port_close_input(&(binding->value)); + if (binding->value.status == PORT_CLOSED) + port_dictionary_Delete(port_dict, binding); +} + +/* + * void close_port_output(string name) + * Requires: init_ports has been called + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns. Otherwise, closes the + * output part of the port by name name. When both a + * port's input & output parts have been closed, the + * port is deleted to save space. If an error + * occurs, $error is set to the error message. + */ + +void +close_port_output(string name) +{ + port_dictionary_binding *binding; + + binding = port_dictionary_Lookup(port_dict, name); + if (!binding) + return; + + port_close_output(&(binding->value)); + if (binding->value.status == PORT_CLOSED) + port_dictionary_Delete(port_dict, binding); +} + +/****************************************************************************/ +/* */ +/* Code to implement a port given some FILE *'s: */ +/* */ +/****************************************************************************/ + +static string +get_file(port *p, + char **error_p) +{ + char buffer[10000]; /* <<<>>> */ + + if (!p->data.file.input_connector) { + *error_p = "Attempt to read past end of file"; + return(NULL); + } + + buffer[0] = 0; + errno = 0; + if (!fgets(buffer, 9999, p->data.file.input_connector)) { + if (errno) + *error_p = strerror(errno); + else + *error_p = "Attempt to read past end of file"; + + return(NULL); + } + + buffer[9999] = 0; + return(string_Copy(buffer)); +} + +static char * +put_file(port *p, + string text, + int length) +{ + if (!p->data.file.output_connector) + return(NULL); + + errno = 0; + fwrite(text, 1, length, p->data.file.output_connector); + fflush(p->data.file.output_connector); + + if (errno) + return(strerror(errno)); + + return(NULL); +} + +static char * +close_file_input(port *p) +{ + errno = 0; + if (p->data.file.input_connector) { + fclose(p->data.file.input_connector); + p->data.file.input_connector = 0; + } + + if (errno) + return(strerror(errno)); + + return(NULL); +} + +static char * +close_file_output(port *p) +{ + errno = 0; + if (p->data.file.output_connector) { + fclose(p->data.file.output_connector); + p->data.file.output_connector = 0; + } + + if (errno) + return(strerror(errno)); + + return(NULL); +} + +void create_port_from_files(string name, + FILE *input, + FILE *output) +{ + port *p = create_named_port(name); + +#if !defined(__HIGHC__) + p->get = input ? get_file : NULL; + p->put = output ? put_file : NULL; +#else + /* RT compiler (hc2.1y) bug workaround */ + if (input) + p->get = get_file; + else + p->get = NULL; + if (output) + p->put = put_file; + else + p->put = NULL; +#endif + p->close_input = close_file_input; + p->close_output = close_file_output; + p->status = 0; + p->data.file.input_connector = input; + p->data.file.output_connector = output; +} + +/****************************************************************************/ +/* */ +/* Code for creating various types of FILE * ports: */ +/* */ +/****************************************************************************/ + +void +create_subprocess_port(string name, + char **argv) +{ + int pid; + int to_child_descriptors[2]; + int to_parent_descriptors[2]; + FILE *in = 0; + FILE *out = 0; + + /* <<<>>> (file leak) */ + if (pipe(to_child_descriptors)!=0 || pipe(to_parent_descriptors)!=0) + return; + + pid = fork(); + if (pid == -1) { + fprintf(stderr, "zwgc: error while attempting to fork: "); + perror(""); + return; /* <<<>>> */ + } else if (pid == 0) { /* in child */ + close(0); + close(1); + dup2(to_child_descriptors[0], 0); + dup2(to_parent_descriptors[1], 1); + close(to_child_descriptors[1]); + close(to_parent_descriptors[0]); + + execvp(argv[0], argv); + fprintf(stderr,"zwgc: unable to exec %s: ", argv[0]); + perror(""); + _exit(errno); + } + + fcntl(to_parent_descriptors[0], F_SETFD, 1); + fcntl(to_child_descriptors[1], F_SETFD, 1); + in = fdopen(to_parent_descriptors[0],"r"); + out = fdopen(to_child_descriptors[1],"w"); + close(to_child_descriptors[0]); + close(to_parent_descriptors[1]); + + create_port_from_files(name, in, out); +} + +void +create_file_append_port(string name, + string filename) +{ + FILE *out; + int oumask; + + errno = 0; + + oumask = umask(077); /* allow read/write for us only */ + out = fopen(filename, "a"); + (void) umask(oumask); + if (out == NULL) { + var_set_variable("error", strerror(errno)); + return; + } + + create_port_from_files(name, 0, out); +} + +void +create_file_input_port(string name, + string filename) +{ + FILE *in; + + errno = 0; + in = fopen(filename, "r"); + if (in == NULL) { + var_set_variable("error", strerror(errno)); + return; + } + + create_port_from_files(name, in, 0); +} + +void +create_file_output_port(string name, + string filename) +{ + FILE *out; + int oumask; + + errno = 0; + + oumask = umask(077); /* allow read/write for us only */ + out = fopen(filename, "w"); + (void) umask(oumask); + if (out == NULL) { + var_set_variable("error", strerror(errno)); + return; + } + + create_port_from_files(name, 0, out); +} + +/****************************************************************************/ +/* */ +/* Code to implement a port given a filter function: */ +/* */ +/****************************************************************************/ + +static string +get_filter(port *p, + char **error_p) +{ + string result; + + if (string_stack_empty(p->data.filter.waiting_packets)) { + *error_p = "Attempt to read from port when no data available"; + return(NULL); + } + + result = string_stack_top(p->data.filter.waiting_packets); + string_stack_pop(p->data.filter.waiting_packets); + return(result); +} + +static char * +put_filter(port *p, + string text, + int length) +{ + string input; + string output; + + if (p->status & INPUT_CLOSED) + return(NULL); + + input = convert_nulls_to_newlines(text, length); + output = (*(p->data.filter.filter))(input); + free(input); + string_stack_push(p->data.filter.waiting_packets, output); + return(NULL); +} + +static char * +close_filter_input(port *p) +{ + while (!string_stack_empty(p->data.filter.waiting_packets)) + string_stack_pop(p->data.filter.waiting_packets); + + return(NULL); +} + +/*ARGSUSED*/ +static char * +close_filter_output(port *p) +{ + return(NULL); +} + +void +create_port_from_filter(string name, + string (*filter)(string)) +{ + port *p = create_named_port(name); + + p->get = get_filter; + p->put = put_filter; + p->close_input = close_filter_input; + p->close_output = close_filter_output; + p->status = 0; + p->data.filter.waiting_packets = string_stack_create(); + p->data.filter.filter = filter; +} + +/****************************************************************************/ +/* */ +/* Code to implement a port given an output function: */ +/* */ +/****************************************************************************/ + +static char * +put_output(port *p, + string text, + int length) +{ + string input; + char *error; + + input = convert_nulls_to_newlines(text, length); + error = p->data.output.output(input); + free(input); + return(error); +} + +/*ARGSUSED*/ +static char * +close_output(port *p) +{ + return(NULL); +} + +void +create_port_from_output_proc(string name, + char *(*output)(string)) +{ +#ifdef SABER /* Yes, it's another ANSI incompatiblity */ + port *p; +#else + port *p = create_named_port(name); +#endif + +#ifdef SABER + p = create_named_port(name); +#endif + + p->get = NULL; + p->put = put_output; + p->close_input = close_output; + p->close_output = close_output; + p->status = 0; + p->data.output.output = output; +} diff --git a/zwgc/port.h b/zwgc/port.h new file mode 100644 index 0000000..d7da9d3 --- /dev/null +++ b/zwgc/port.h @@ -0,0 +1,124 @@ +#ifndef port_TYPE +#define port_TYPE + +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#include +#include "new_string.h" +#include "string_stack.h" + +union port__data { + struct { + FILE *input_connector; + FILE *output_connector; + } file; + struct { + string_stack waiting_packets; + string (*filter)(string); + } filter; + struct { + char *(*output)(string); + } output; +}; + +typedef struct port__struct { /* PRIVATE */ + char *(*get)(struct port__struct *, char **); + char *(*put)(struct port__struct *, char *, int); + char *(*close_input)(struct port__struct *); + char *(*close_output)(struct port__struct *); +#define INPUT_CLOSED 0x1 +#define OUTPUT_CLOSED 0x2 +#define PORT_CLOSED 0x3 + int status; + union port__data data; +} port; + +/* + * void init_ports() + * Modifies: all ports + * Effects: Closes all existing ports. Must be called before + * any other port call is made. + */ + +extern void init_ports(void); + +/* + * string read_from_port(string name) + * Requires: init_ports has been called + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns "". Otherwise, attempts to + * read from that port. If an error occurs, $error is + * set to the error message and "" returned. Otherwise + * the read string is returned. The returned string is + * on the heap & must be eventually freed. + */ + +extern string read_from_port(string); + +/* + * void write_on_port(string name, char *text, int length) + * Requires: init_ports has been called, length>=0 + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns. Otherwise, attempts to + * write text[0..length-1] on that port. If an error + * occurs, $error is set to the error message. + */ + +extern void write_on_port(string, char *, int); + +/* + * void close_port_input(string name) + * Requires: init_ports has been called + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns. Otherwise, closes the + * input part of the port by name name. When both a + * port's input & output parts have been closed, the + * port is deleted to save space. If an error + * occurs, $error is set to the error message. + */ + +extern void close_port_input(string); + +/* + * void close_port_output(string name) + * Requires: init_ports has been called + * Modifies: the port named name if any, $error + * Effects: If a port by name name does not exist, sets $error to + * "No such port" & returns. Otherwise, closes the + * output part of the port by name name. When both a + * port's input & output parts have been closed, the + * port is deleted to save space. If an error + * occurs, $error is set to the error message. + */ + +extern void close_port_output(string); + + +extern void create_subprocess_port(string, char **); +extern void create_file_append_port(string, string); +extern void create_file_input_port(string, string); +extern void create_file_output_port(string, string); +extern void create_port_from_filter(string, string (*)(string)); +extern void create_port_from_output_proc(string, char *(*)(string)); + +extern void init_standard_ports(int *, char **); +extern void create_port_from_files(string, FILE *, FILE *); + +#endif diff --git a/zwgc/regexp.c b/zwgc/regexp.c new file mode 100644 index 0000000..a9314ab --- /dev/null +++ b/zwgc/regexp.c @@ -0,0 +1,46 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_regexp_c[] = "$Id$"; +#endif + +#include "regexp.h" + +int +ed_regexp_match_p(string test_string, + string pattern) +{ + regex_t RE; + int retval; + char errbuf[512]; + + retval = regcomp(&RE, pattern, REG_NOSUB); + if (retval != 0) { + regerror(retval, &RE, errbuf, sizeof(errbuf)); + fprintf(stderr,"%s in regcomp %s\n",errbuf,pattern); + return(0); + } + retval = regexec(&RE, test_string, 0, NULL, 0); + if (retval != 0 && retval != REG_NOMATCH) { + regerror(retval, &RE, errbuf, sizeof(errbuf)); + fprintf(stderr,"%s in regexec %s\n",errbuf,pattern); + regfree(&RE); + return(0); + } + regfree(&RE); + return(retval == 0 ? 1 : 0); +} diff --git a/zwgc/regexp.h b/zwgc/regexp.h new file mode 100644 index 0000000..d5efcc2 --- /dev/null +++ b/zwgc/regexp.h @@ -0,0 +1,24 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef regexp_MODULE +#define regexp_MODULE + +#include "new_string.h" + +extern int ed_regexp_match_p(string, string); + +#endif diff --git a/zwgc/stack.h b/zwgc/stack.h new file mode 100644 index 0000000..ec722c8 --- /dev/null +++ b/zwgc/stack.h @@ -0,0 +1,65 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +/****************************************************************************/ +/* */ +/* A generic stack type based on linked lists: */ +/* */ +/****************************************************************************/ + +#ifndef TYPE_T_stack_TYPE +#define TYPE_T_stack_TYPE + +#ifndef NULL +#define NULL 0 +#endif + +typedef struct _TYPE_T_stack { + struct _TYPE_T_stack *next; + TYPE_T data; +} *TYPE_T_stack; + +#define TYPE_T_stack_create() ((struct _TYPE_T_stack *) NULL) + +#define TYPE_T_stack_empty(stack) (!(stack)) + +#ifdef DEBUG +#define TYPE_T_stack_top(stack) ((stack) ? (stack)->data :\ + (abort(),(stack)->data)) +#else +#define TYPE_T_stack_top(stack) ((stack)->data) +#endif + +#ifdef DEBUG +#define TYPE_T_stack_pop(stack) { TYPE_T_stack old = (stack);\ + if (!old)\ + abort(); /*<<<>>>*/\ + (stack) = old->next;\ + free(old); } +#else +#define TYPE_T_stack_pop(stack) { TYPE_T_stack old = (stack);\ + (stack) = old->next;\ + free(old); } +#endif + +#define TYPE_T_stack_push(stack,object) \ + { TYPE_T_stack new = (struct _TYPE_T_stack *)\ + malloc(sizeof (struct _TYPE_T_stack));\ + new->next = (stack);\ + new->data = object;\ + (stack) = new; } + +#endif diff --git a/zwgc/standard_ports.c b/zwgc/standard_ports.c new file mode 100644 index 0000000..2d6d685 --- /dev/null +++ b/zwgc/standard_ports.c @@ -0,0 +1,305 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_standard_ports_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Code to setup standard ports: */ +/* */ +/****************************************************************************/ + +#include +#include "new_memory.h" +#include "port.h" +#include "variables.h" +#include "error.h" +#include "main.h" +#include "tty_filter.h" +#ifndef X_DISPLAY_MISSING +#include "X_driver.h" +#endif + + +extern char *tty_filter(string, int); +extern int tty_filter_init(char *, char, int *, char **); + +extern void usage(void); + +/* + * + */ + +static char * +plain_driver(string input) +{ + string processed_input = tty_filter(input, 0); + + fputs(processed_input, stdout); + fflush(stdout); + free(processed_input); + return(NULL); +} + +/* + * + */ + +static char * +tty_driver(string input) +{ + string processed_input = tty_filter(input, 1); + + fputs(processed_input, stdout); + fflush(stdout); + free(processed_input); + return(NULL); +} + +/* + * + */ + +static string +noop_filter(string input) +{ + return(input); +} + +/* + * + */ + +static string +plain_filter(string input) +{ + return(tty_filter(input, 0)); +} + +/* + * + */ + +static string +fancy_filter(string input) +{ + return(tty_filter(input, 1)); +} + +/* + * + */ + +static struct standard_port_info { + char *port_name; +/* + * 0 = ok to use as the default output port + * 1 = not ok to use as the default output port + * 2 = disabled + */ +#define DEFAULT_OK 0 +#define DEFAULT_NOTOK 1 +#define DISABLED 2 + + int port_setup_status; + int (*port_init)(char *, char, int *, char **); +#define INPUT_DESC 0 +#define OUTPUT_DESC 1 +#define FILTER 2 +#define OUTPUT_PROC 3 + int type; + char *(*function)(string); + int setup_arg; +} standard_port_info_table[] = { +#ifndef X_DISPLAY_MISSING +{ "X", DEFAULT_OK, X_driver_init, OUTPUT_PROC, X_driver, 0}, +{ "tty", DEFAULT_NOTOK, tty_filter_init, OUTPUT_PROC, tty_driver, 0}, +#else +{ "tty", DEFAULT_OK, tty_filter_init, OUTPUT_PROC, tty_driver, 0}, +#endif +{ "plain", DEFAULT_NOTOK, tty_filter_init, OUTPUT_PROC, plain_driver, 0}, +{ "stdout", DEFAULT_NOTOK, NULL, OUTPUT_DESC, NULL, 1}, +{ "stderr", DEFAULT_NOTOK, NULL, OUTPUT_DESC, NULL, 2}, + +{ "stdin", DEFAULT_NOTOK, NULL, INPUT_DESC, NULL, 0}, +{ "loopback", DEFAULT_NOTOK, NULL, FILTER, noop_filter, 0}, +{ "plain_filter", DEFAULT_NOTOK, tty_filter_init, FILTER, plain_filter, 0}, +{ "tty_filter", DEFAULT_NOTOK, tty_filter_init, FILTER, fancy_filter, 0}, + +{ NULL, DISABLED, NULL, FILTER, NULL, 0} }; + +/* + * <<<>>> + */ + +static struct standard_port_info * +get_standard_port_info(string port_name) +{ + struct standard_port_info *p; + + for (p=standard_port_info_table; p->port_name; p++) + if (string_Eq(p->port_name, port_name) && p->port_setup_status!=DISABLED) + return(p); + + return(NULL); +} + +/* + * Internal Routine: + * + * int boolean_value_of(string text) + * Effects: If text represents yes/true/on, return 1. If text + * representes no/false/off, return 0. Otherwise, + * returns -1. + */ + +static int +boolean_value_of(string text) +{ + if (!text) + return(-1); /* not set */ + if (!strcasecmp("yes", text) || !strcasecmp("y", text) || + !strcasecmp("true", text) || !strcasecmp("t", text) || + !strcasecmp("on", text)) + return(1); + else if (!strcasecmp("no", text) || !strcasecmp("n", text) || + !strcasecmp("false", text) || !strcasecmp("f", text) || + !strcasecmp("off", text)) + return(0); + else + return(-1); +} + +/* + * + */ + +void init_standard_ports(int *pargc, + char **argv) +{ + struct standard_port_info *p; + string first_working_port = ""; + string default_port = ""; + char **new, **current; + int fallback; + char *charset = NULL; + + /* + * Process argument list handling "-disable " and + * "-default " arguments, as well as "-ttymode" + * and -charset, because tty_filter_init gets run twice + */ + for (new=current=argv+1; *current; current++) { + if (string_Eq((string) *current, "-disable")) { + current++; *pargc -= 2; + if (!*current) + usage(); + p = get_standard_port_info((string) *current); + if (p) + p->port_setup_status = DISABLED; + } else if (string_Eq((string) *current, "-default")) { + current++; *pargc -= 2; + if (!*current) + usage(); + default_port = (string) *current; + p = get_standard_port_info((string) *current); + if (p) + p->port_setup_status = DEFAULT_OK; + } else if (string_Eq((string) *current, "-charset")) { + current++; *pargc -= 2; + if (!*current) + usage(); + charset = *current; + } else if (string_Eq((string) *current, "-ttymode")) { + default_port = (string) "tty"; + (*pargc)--; + p = get_standard_port_info(default_port); + if (p) { + p->port_setup_status = DEFAULT_OK; + p = get_standard_port_info ((string) "X"); + if (p) + p->port_setup_status = DISABLED; + } + } else + *(new++) = *current; + } + *new = *current; + + var_set_variable_then_free_value("tty_charset", (string)ZGetCharsetString(charset)); + + fallback = boolean_value_of(ZGetVariable("fallback")); + /* + * Initialize all non-disabled ports. If a port reports an error, + * disable that port. Set default_port if not already set + * by the -default argument to the first non-disabled port. + */ + for (p = standard_port_info_table; p->port_name; p++) { + if (p->port_setup_status == DISABLED) + continue; + + if (p->port_init && (*(p->port_init))(p->port_name, + *first_working_port, + pargc, argv)) { + p->port_setup_status = DISABLED; + continue; + } + + if (fallback == 1) { + /* we are doing fallback, make DEFAULT_NOTOK ports OK */ + p->port_setup_status = DEFAULT_OK; + } + if (!*first_working_port) + first_working_port = p->port_name; + switch (p->type) { + case INPUT_DESC: + create_port_from_files(p->port_name, fdopen(p->setup_arg, "r"),0); + break; + + case OUTPUT_DESC: + create_port_from_files(p->port_name, 0, fdopen(p->setup_arg, "w")); + break; + + case FILTER: + create_port_from_filter(p->port_name, p->function); + break; + + case OUTPUT_PROC: + create_port_from_output_proc(p->port_name, p->function); + break; + } + } + + if (!default_port[0]) { + /* no default port has been set */ + for (p = get_standard_port_info(first_working_port); p->port_name; p++) + if ((p->port_setup_status == DEFAULT_OK)) + break; + if (p->port_name) + var_set_variable("output_driver", p->port_name); + else { /* no suitable default has been found */ + if (fallback == -1) /* complain, since indeterminate */ + ERROR2( +"To receive Zephyrgrams, (type `%s -ttymode').\n", + progname); + exit(1); + } + } else + var_set_variable("output_driver", default_port); + +} diff --git a/zwgc/string_dictionary_aux.c b/zwgc/string_dictionary_aux.c new file mode 100644 index 0000000..0c2b306 --- /dev/null +++ b/zwgc/string_dictionary_aux.c @@ -0,0 +1,102 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_string_dictionary_aux_c[] = "$Id$"; +#endif + +/* + * string_dictionary_aux - a module implementing convenience routines for use + * with string_dictionarys + * + * Overview: + * + * This module implements Fetch and Set operations on + * string_dictionaries which take the place of Define and Lookup for + * most uses. The importance difference between them and Define and + * Lookup is that they maintain the invariant that all the value strings + * in a string_dictionary are on the heap. In particular, they do + * free's and string_Copy's whenever needed. Also implemented is + * SafeDestroy which does a Destroy after freeing all the value strings + * in a string_dictionary. + */ + +#include +#include "new_memory.h" +#include "string_dictionary.h" +#include "string_dictionary_aux.h" + +/* + * void string_dictionary_Set(string_dictionary d, string key,string value): + * Modifies: d + * Effects: Binds key to value in d. Automatically free's the + * previous value of key, if any. Value is copied on the + * heap. + */ + +void +string__dictionary_Set(string_dictionary d, + string key, + string value) +{ + string_dictionary_binding *binding; + int already_exists; + + binding = string_dictionary_Define(d, key, &already_exists); + if (already_exists) + free(binding->value); + + binding->value = string_Copy(value); +} + +/* + * char *string_dictionary_Fetch(string_dictionary d, string key) + * Effects: If key is not bound in d, returns 0. Otherwise, + * returns the value that key is bound to. + * Note that the returned string if any should not be + * freed or modified in any way. Note also that it may + * disappear later if key is rebound. + */ + +char * +string_dictionary_Fetch(string_dictionary d, + string key) +{ + string_dictionary_binding *binding; + + binding = string_dictionary_Lookup(d, key); + if (!binding) + return(0); + + return(binding->value); +} + +/* + * void string_dictionary_SafeDestroy(string_dictionary d) + * Modifies: d + * Effects: Like string_dictionary_Destroy except first frees + * all value's in the dictionary. + */ + +static void +free_value_of_binding(string_dictionary_binding *b) +{ + free(b->value); +} + +void +string_dictionary_SafeDestroy(string_dictionary d) +{ + string_dictionary_Enumerate(d, free_value_of_binding); + string_dictionary_Destroy(d); +} diff --git a/zwgc/string_dictionary_aux.h b/zwgc/string_dictionary_aux.h new file mode 100644 index 0000000..e058721 --- /dev/null +++ b/zwgc/string_dictionary_aux.h @@ -0,0 +1,57 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef string_dictionary_aux_MODULE +#define string_dictionary_aux_MODULE + +#include "new_memory.h" +#include "string_dictionary.h" + +/* + * void string_dictionary_Set(string_dictionary d, string key,string value): + * Modifies: d + * Effects: Binds key to value in d. Automatically free's the + * previous value of key, if any. Value is copied on the + * heap. + */ + +extern void string__dictionary_Set(string_dictionary, string, string); +#ifdef DEBUG_MEMORY +#define string_dictionary_Set(a,b,c) (set_module(__FILE__,__LINE__),\ + string__dictionary_Set(a,b,c)) +#else +#define string_dictionary_Set(a,b,c) string__dictionary_Set(a,b,c) +#endif + +/* + * char *string_dictionary_Fetch(string_dictionary d, string key) + * Effects: If key is not bound in d, returns 0. Otherwise, + * returns the value that key is bound to. + * Note that the returned string if any should not be + * freed or modified in any way. Note also that it may + * disappear later if key is rebound. + */ + +extern char *string_dictionary_Fetch(string_dictionary, + string); + +/* + * void string_dictionary_SafeDestroy(string_dictionary d) + * Modifies: d + * Effects: Like string_dictionary_Destroy except first frees + * all value's in the dictionary. + */ + +extern void string_dictionary_SafeDestroy(string_dictionary); + +#endif diff --git a/zwgc/subscriptions.c b/zwgc/subscriptions.c new file mode 100644 index 0000000..23b1c3d --- /dev/null +++ b/zwgc/subscriptions.c @@ -0,0 +1,402 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_subscriptions_c[] = "$Id$"; +#endif + +/****************************************************************************/ +/* */ +/* Subscriptions.c: code to deal with subscriptions & punting: */ +/* */ +/****************************************************************************/ + +#include +#include +#include +#include +#include "new_memory.h" +#include "new_string.h" +#include "int_dictionary.h" +#include "zwgc.h" +#include "subscriptions.h" +#include "error.h" +#include "file.h" +#include "main.h" + +/****************************************************************************/ +/* */ +/* Code to implement punting of notices: */ +/* */ +/****************************************************************************/ + +/* + * + */ +#ifndef CMU_ZCTL_PUNT +static +#endif +int_dictionary puntable_addresses_dict = 0; + +static void +init_puntable_dict(void) +{ + puntable_addresses_dict = int_dictionary_Create(33); +} + +static string +address_to_string(string class, + string instance, + string recipient) +{ + string result; + + /* + * Treat a recipient of "" as "*": + */ + if (string_Eq(recipient,"")) + recipient = "*"; + else if (recipient[0] == '@') { + recipient = string_Concat("*", recipient); + } + + /* + * The following is a hack for now only. It should be replaced with + * several calls to escape_code... <<<>>> + */ + result = string_Concat(class, "\001"); + result = string_Concat2(result, instance); + result = string_Concat2(result, "\001"); + result = string_Concat2(result, recipient); + string_Downcase(result); + + return(result); +} + +int puntable_address_p(string class, + string instance, + string recipient) +{ + string temp; + + if (!puntable_addresses_dict) + init_puntable_dict(); + + temp = address_to_string(class, instance, recipient); + if (int_dictionary_Lookup(puntable_addresses_dict, temp)) { + free(temp); + return 1; + } + free(temp); + + /* This kludge is to allow punts of wildcard instance to work */ + temp = address_to_string(class, "*", recipient); + if (int_dictionary_Lookup(puntable_addresses_dict, temp)) { + free(temp); + return(1); + } + + free(temp); + return(0); +} + +void punt(string class, + string instance, + string recipient) +{ + string temp; + + if (!puntable_addresses_dict) + init_puntable_dict(); + + temp = address_to_string(class, instance, recipient); + (void)int_dictionary_Define(puntable_addresses_dict, temp, 0); + free(temp); +} + +void unpunt(string class, + string instance, + string recipient) +{ + string temp; + int_dictionary_binding *binding; + + if (!puntable_addresses_dict) + init_puntable_dict(); + + temp = address_to_string(class, instance, recipient); + binding = int_dictionary_Define(puntable_addresses_dict, temp, 0); + free(temp); + if (binding) + int_dictionary_Delete(puntable_addresses_dict, binding); +} + +/****************************************************************************/ +/* */ +/* Code to implement batching [un]subscription requests: */ +/* */ +/****************************************************************************/ + +/* + * <<<>>> these routines require zwgc_active to be false (0) + */ + +#define BATCH_SIZE 20 + +static int subscription_list_size = 0; +static ZSubscription_t subscription_list[BATCH_SIZE]; + +static int unsubscription_list_size = 0; +static ZSubscription_t unsubscription_list[BATCH_SIZE]; + +static void +free_subscription_list(ZSubscription_t *list, + int number_of_elements) +{ + int i; + + for (i=0; ih_name, sizeof(ourhostcanon)-1); + return; +} + +static void +macro_sub(char *str) +{ + static int initedhosts = 0; + + if (!initedhosts) { + inithosts(); + initedhosts = 1; + } + if (string_Eq(str, TOKEN_ME)) + strcpy(str, ZGetSender()); + else if (string_Eq(str, TOKEN_HOSTNAME)) + strcpy(str, ourhost); + else if (string_Eq(str, TOKEN_CANONNAME)) + strcpy(str, ourhostcanon); +} + +#define UNSUBSCRIBE_CHARACTER '!' +#define PUNT_CHARACTER '-' + +static void +load_subscriptions_from_file(FILE *file) +{ + char line[BUFSIZ]; + char class_buffer[BUFSIZ], instance[BUFSIZ], recipient[BUFSIZ]; + char *class, *temp; + char c; + + while ((!feof(file)) && (!ferror(file))) { + if (fgets(line, BUFSIZ, file)) { + class = class_buffer; + /* Parse line */ + /* <<<>>> + * The below does NOT work is the recipient field is "": + */ + temp = strchr(line, '#'); + if (temp) + *temp = '\0'; + for (temp=line; *temp && *temp==' '; temp++) ; + if (!*temp || *temp=='\n') + continue; + + sscanf(temp,"%[^,],%[^,],%s", class, instance, recipient); + + /* skip type indicator if any: */ + c = class[0]; + if (c==UNSUBSCRIBE_CHARACTER || c==PUNT_CHARACTER) + class++; + + /* perform macro substitutions */ + macro_sub(class); + macro_sub(instance); + macro_sub(recipient); + + /* do the right thing with it */ + switch (c) { + case UNSUBSCRIBE_CHARACTER: + unsubscribe(class, instance, recipient); + break; + case PUNT_CHARACTER: + punt(class, instance, recipient); + break; + default: + subscribe(class, instance, recipient); + break; + } + } else { + break; + } + } + + if (ferror(file)) { + com_err("zwgc", errno, "while reading from subscription file"); + exit(1); + } + + flush_subscriptions(); + flush_unsubscriptions(); + + fclose(file); +} + +#define DEFSUBS "/dev/null" + +static void +load_subscriptions(void) +{ + FILE *subscriptions_file; + + /* no system default sub file on client--they live on the server */ + /* BUT...we need to use something to call load_subscriptions_from_file, + so we use /dev/null */ + subscriptions_file = locate_file(subscriptions_filename_override, + USRSUBS, DEFSUBS); + if (subscriptions_file) + load_subscriptions_from_file(subscriptions_file); +} + +/****************************************************************************/ +/* */ +/* Code to implement shutdown and startup: */ +/* */ +/****************************************************************************/ + +int zwgc_active = 0; + +static ZSubscription_t *saved_subscriptions = NULL; +static int number_of_saved_subscriptions; + +void zwgc_shutdown(void) +{ + if (!zwgc_active) + return; + + TRAP(ZRetrieveSubscriptions(0, &number_of_saved_subscriptions), + "while retrieving zephyr subscription list"); + if (error_code) + return; + saved_subscriptions = (ZSubscription_t *) + malloc(number_of_saved_subscriptions*sizeof(ZSubscription_t)); + if (number_of_saved_subscriptions) + TRAP(ZGetSubscriptions(saved_subscriptions, + &number_of_saved_subscriptions), + "while getting subscriptions"); + if (error_code) { + free(saved_subscriptions); + saved_subscriptions = NULL; + } + TRAP(ZCancelSubscriptions(0), "while canceling subscriptions") ; + + zwgc_active = 0; +} + +void zwgc_startup(void) +{ + if (zwgc_active) + return; + + if (saved_subscriptions) { + TRAP(ZSubscribeToSansDefaults(saved_subscriptions,number_of_saved_subscriptions,0), + "while resubscribing to zephyr messages"); + free(saved_subscriptions); + saved_subscriptions = NULL; + } else + load_subscriptions(); + + zwgc_active = 1; +} diff --git a/zwgc/subscriptions.h b/zwgc/subscriptions.h new file mode 100644 index 0000000..91cb360 --- /dev/null +++ b/zwgc/subscriptions.h @@ -0,0 +1,30 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef subscriptions_MODULE +#define subscriptions_MODULE + +extern int zwgc_active; + +extern int puntable_address_p(string, string, string); +extern void punt(string, string, string); +extern void unpunt(string, string, string); +extern void zwgc_shutdown(void); +extern void zwgc_startup(void); + +#define USRSUBS ".zephyr.subs" + +#endif diff --git a/zwgc/substitute.c b/zwgc/substitute.c new file mode 100644 index 0000000..26accc1 --- /dev/null +++ b/zwgc/substitute.c @@ -0,0 +1,169 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_substitute_c[] = "$Id$"; +#endif + +#include + +#include +#include "new_memory.h" +#include "lexer.h" +#include "substitute.h" + +/* + * Internal Routine: + * + * string eat_dollar_sign_stuff(string (*lookup)(string); string *text_ptr) + * Modifies: *text_ptr + * Effects: This routine deals with handling the stuff after a '$' + * for substitute. If *text_ptr starts with a valid + * variable reference (minus the leading '$'), we look up + * the variable using lookup and return its value. + * *text_ptr is also advanced past the variable reference. + * If a '$' starts *text_ptr, *text_ptr is advanced past it & + * "$" returned. (This handles "$$" -> "$") Otherwise, + * "$" is returned and *text_ptr is not advanced. + * The returned string must not be freed. + */ + +static string +eat_dollar_sign_stuff(string (*lookup)(string), + string *text_ptr) /* Input/Output parameter */ +{ + char c; + char closing_brace = 0; + char *p = *text_ptr; + char *variable_name_start; + int variable_name_length; + + /* + * Handle "$$" -> "$" translation: + */ + c = *p; + if (c=='$') { + *text_ptr = p+1; + return("$"); + } + + /* + * If opening brace present (i.e., '(' or '{'), skip it and save away + * what closing brace we must see at the end of the variable reference: + */ + if (c=='{') { + closing_brace = '}'; + c = *++p; + } else if (c=='(') { + closing_brace = ')'; + c = *++p; + } + + /* + * Eat {identifier_char}* keeping track of what we ate: + */ + variable_name_start = p; + variable_name_length = 0; + while (c = *p, is_identifier_char(c)) { + p++; + variable_name_length++; + } + + /* + * If there was an opening brace, there had better be a comparable + * closing brace. If so, skip it. If not, we have an invalid variable + * reference so return '$' without advancing *text_ptr. + */ + if (closing_brace) { + if (c==closing_brace) + c = *++p; + else + return("$"); + } + + /* + * Zero length variable names are not valid: + */ + if (!variable_name_length) + return("$"); + + /* + * We have a valid variable reference. Advance past it then lookup + * its value and return it: + */ + *text_ptr = p; + if (variable_name_length > MAX_IDENTIFIER_LENGTH) + variable_name_length = MAX_IDENTIFIER_LENGTH; + variable_name_start = string_CreateFromData(variable_name_start, + variable_name_length); + p = lookup(variable_name_start); + free(variable_name_start); + return(p); +} + +/* + * string substitute(string (*lookup)(string); string text) + * Effects: returns the result of expanding all variable + * references in text using lookup. Example: + * "test $foo.$bar baz" would be translated to + * "text . baz" where "" is the value of + * lookup("foo") and "" is the value of lookup("bar"). + * Variables are case sensitive and have the form + * {identifier_char}+ where identifier_char is defined + * in lexer.h by is_identifier_char. $(foo) and + * ${foo} are alternate forms for $foo. In particular, + * ${foo}bar is a reference to foo followed by "bar" while + * $foobar is a reference to foobar. Incomplete variable + * references like $(foo bar are displayed as if they + * were not variable references. To allow quoting, "$$" + * is translated to "$". Only the first + * MAX_IDENTIFIER_LENGTH characters of an identifier are + * significant. The strings returned by lookup are not + * modified in any way or freed. + */ + +string +substitute(string (*lookup)(string), + string text) +{ + string result_so_far = string_Copy(""); + char *p, *temp; + + for (;;) { + /* + * Move [^$]* from start of text to end of result_so_far: + */ + for (p=text; *p && (*p)!='$'; p++) ; + if (text != p) { + temp = string_CreateFromData(text, p-text); + text = p; + result_so_far = string_Concat2(result_so_far, temp); + free(temp); + } + + /* + * If text now empty, exit -- the result is in result_so_far: + */ + if (!*text) + return(result_so_far); + + /* + * Otherwise, text begins with a '$'. Eat it then call + * eat_dollar_sign_stuff to process stuff after it. + * Append result to result_so_far, update text, & continue. + */ + text++; + p = eat_dollar_sign_stuff(lookup, &text); + result_so_far = string_Concat2(result_so_far, p); + } +} diff --git a/zwgc/substitute.h b/zwgc/substitute.h new file mode 100644 index 0000000..925454a --- /dev/null +++ b/zwgc/substitute.h @@ -0,0 +1,45 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef substitute_MODULE +#define substitute_MODULE + +#include "new_string.h" + +/* + * string substitute(string (*lookup)(string); string text) + * Effects: returns the result of expanding all variable + * references in text using lookup. Example: + * "test $foo.$bar baz" would be translated to + * "text . baz" where "" is the value of + * lookup("foo") and "" is the value of lookup("bar"). + * Variables are case sensitive and have the form + * {identifier_char}+ where identifier_char is defined + * in lexer.h by is_identifier_char. $(foo) and + * ${foo} are alternate forms for $foo. In particular, + * ${foo}bar is a reference to foo followed by "bar" while + * $foobar is a reference to foobar. Incomplete variable + * references like $(foo bar are displayed as if they + * were not variable references. To allow quoting, "$$" + * is translated to "$". Only the first + * MAX_IDENTIFIER_LENGTH characters of an identifier are + * significant. The strings returned by lookup are not + * modified in any way or freed. + */ + +extern string substitute(string (*)(string), string); + +#endif diff --git a/zwgc/text_operations.c b/zwgc/text_operations.c new file mode 100644 index 0000000..16d9047 --- /dev/null +++ b/zwgc/text_operations.c @@ -0,0 +1,129 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_text_operations_c[] = "$Id$"; +#endif + +#include + +#include "new_memory.h" +#include "text_operations.h" +#include "char_stack.h" + +string +lany(string *text_ptr, + string str) +{ + string result, whats_left; + char *p = *text_ptr; + + while (*p && *str) p++, str++; + + result = string_CreateFromData(*text_ptr, p - *text_ptr); + whats_left = string_Copy(p); + free(*text_ptr); + *text_ptr = whats_left; + + return(result); +} + +string +lbreak(string *text_ptr, + const character_class set) +{ + string result, whats_left; + char *p = *text_ptr; + + while (*p && !set[(int)*p]) p++; + + result = string_CreateFromData(*text_ptr, p - *text_ptr); + whats_left = string_Copy(p); + free(*text_ptr); + *text_ptr = whats_left; + + return(result); +} + +string +lspan(string *text_ptr, + character_class set) +{ + string result, whats_left; + char *p = *text_ptr; + + while (*p && set[(int)*p]) p++; + + result = string_CreateFromData(*text_ptr, p - *text_ptr); + whats_left = string_Copy(p); + free(*text_ptr); + *text_ptr = whats_left; + + return(result); +} + +string +rany(string *text_ptr, + string str) +{ + string result, whats_left; + string text = *text_ptr; + char *p = text + strlen(text); + + while (text

+ * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef text_operations_MODULE +#define text_operations_MODULE + +#include "character_class.h" + +extern string lany(string *, string); +extern string lbreak(string *, const character_class); +extern string lspan(string *, character_class); +extern string rany(string *, string); +extern string rbreak(string *, character_class); +extern string rspan(string *, character_class); + +#endif diff --git a/zwgc/tty_filter.c b/zwgc/tty_filter.c new file mode 100644 index 0000000..7e4924a --- /dev/null +++ b/zwgc/tty_filter.c @@ -0,0 +1,597 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_tty_filter_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* The tty & plain filters: */ +/* */ +/****************************************************************************/ +#ifdef HAVE_TERMCAP_H +#include +#else +#ifdef HAVE_TERM_H +#ifdef HAVE_TERMIO_H +/* I blame Solaris. Solaris to blame. */ +#include +#endif +#ifdef HAVE_CURSES_H +#include +#endif +#include +#endif +#endif + +#include + +#include "new_memory.h" +#include "new_string.h" +#include "variables.h" +#include "string_dictionary_aux.h" +#include "formatter.h" +#include "zwgc.h" +#include "error.h" +#include "tty_filter.h" + +/***************************************************************************/ +#ifndef HAVE_TERMCAP_H +extern int tgetent(); +extern char *tgetstr(),*getenv(); +#ifdef linux +extern speed_t ospeed; +#else +extern short ospeed; +#endif +char PC; +#endif + +/* Dictionary naming convention: + + B.xxx is the termcap sequence to begin environment xxx. + E.xxx is the termcap sequence to end environment xxx. + + */ + +static string_dictionary termcap_dict; +static char code_buf[10240], *code_buf_pos = code_buf, *code; + +/* Define the following commands: + + (Hopefully) shared with all devices: + + @center Guess. + + @em Emphasis. User underline if available, else reverse video. + @bold Bold letters. If not available, reverse video, else underline. + @beep "bl" termcap entry, else "^G" + + Other: + + @blink "mb"/"me" termcap entry, else nothing. + @rv "so"/"se" termcap entry. + @u "us"/"ue" termcap entry. + */ + +#define TD_SET(k,v) (string_dictionary_Define(termcap_dict, (k), &ex)->value \ + = (v)) +#define EXPAND(k) (code = code_buf_pos, tputs(tmp, 1, tty_outc), \ + *code_buf_pos++ = 0, TD_SET(k, code)) + +static int +tty_outc(int c) +{ + *code_buf_pos++ = c; + return 0; +} + +/* ARGSUSED */ +int +tty_filter_init(char *drivername, + char notfirst, + int *pargc, + char **argv) +{ + static char st_buf[128]; + char tc_buf[1024], *p = st_buf, *tmp, *term; + int ex; + string_dictionary_binding *b; + int isrealtty = string_Eq(drivername, "tty"); + struct termios tbuf; + + ospeed = (tcgetattr(STDIN_FILENO, &tbuf) == 0) ? cfgetospeed(&tbuf) : 2400; + + if (termcap_dict == (string_dictionary) NULL) + termcap_dict = string_dictionary_Create(7); + + if (!(term = getenv("TERM"))) { /* Only use termcap if $TERM. */ + if (isrealtty && !notfirst) + /* only complain if initializing tty mode, and would be first + available port */ + ERROR("$TERM not set. tty mode will be plain.\n"); + } +#ifdef _AIX + /* + * This is a temporary KLUDGE to get around the problem where some people + * might start zwgc in their ~/.startup.X and it hangs on the RISC/6000. + * Apparently, the call to tgetent() with the Athena console window causes + * the process to get stopped on tty access. Since the terminal type is + * "dumb" (set by tcsh), we can pretty much assume there isn't anything + * to setup from the termcap information. + */ + else if (!strcmp(term, "dumb")) { } +#endif + else { + tgetent(tc_buf, term); + + /* Step 1: get all of {rv,bold,u,bell,blink} that are available. */ + + /* We cheat here, and ignore the padding (if any) specified for + the mode-change strings (it's a real pain to do "right") */ + + tmp = tgetstr("pc", &p); + PC = (tmp) ? *tmp : 0; + tmp = tgetstr("md", &p); + if (tmp) { /* bold ? */ + EXPAND("B.bold"); + tmp = tgetstr("me",&p); + EXPAND("E.bold"); + } + tmp = tgetstr("mr", &p); + if (tmp) { /* reverse video? */ + EXPAND("B.rw"); + tmp = tgetstr("me", &p); + EXPAND("E.rw"); + } + tmp = tgetstr("bl", &p); + if (tmp) { /* Bell ? */ + EXPAND("B.bell"); + TD_SET("E.bell", NULL); + } + tmp = tgetstr("mb", &p); + if (tmp) { /* Blink ? */ + EXPAND("B.blink"); + tmp = tgetstr("me", &p); + EXPAND("E.blink"); + } + tmp = tgetstr("us", &p); + if (tmp) { /* Underline ? */ + EXPAND("B.u"); + tmp = tgetstr("ue", &p); + EXPAND("E.u"); + } + tmp = tgetstr("so", &p); + if (tmp) { /* Standout ? */ + EXPAND("B.so"); + tmp = tgetstr("se", &p); + EXPAND("E.so"); + } + } + /* Step 2: alias others to the nearest substitute */ + + /* Bold = so, else rv, else ul */ + if (NULL == string_dictionary_Lookup(termcap_dict, "B.bold")) { + if((b = string_dictionary_Lookup(termcap_dict, "B.so"))) { + TD_SET("B.bold", b->value); + TD_SET("E.bold", + string_dictionary_Lookup(termcap_dict, "E.so")->value); + } else if ((b = string_dictionary_Lookup(termcap_dict, "B.rv"))) { + TD_SET("B.bold", b->value); + TD_SET("E.bold", + string_dictionary_Lookup(termcap_dict, "E.rv")->value); + } else if ((b = string_dictionary_Lookup(termcap_dict,"B.u"))) { + TD_SET("B.bold", b->value); + TD_SET("E.bold", + string_dictionary_Lookup(termcap_dict, "E.u")->value); + } + } + + /* Bell = ^G */ + if (NULL == string_dictionary_Lookup(termcap_dict, "B.bell")) { + TD_SET("B.bell", "\007"); + TD_SET("E.bell", NULL); + } + + /* Underline -> nothing */ + /* Blink -> nothing */ + + return(0); +} + +/***************************************************************************/ + + + + +static int +fixed_string_eq(string pattern, + char *text, + int text_length) +{ + while (*pattern && text_length>0 && *pattern == *text) { + pattern++; + text++; + text_length--; + } + + return(!*pattern && !text_length); +} + +typedef struct _tty_str_info { + struct _tty_str_info *next; + + char *str; + int len; + + char alignment; /* 'l', 'c', 'r', or ' ' to indicate newline */ + unsigned int bold_p : 1; + unsigned int italic_p : 1; + unsigned int bell_p : 1; + unsigned int ignore: 1; +} tty_str_info; + +const char *info_default_string = ""; + +static void +free_info(tty_str_info *info) +{ + tty_str_info *next_info; + + while (info) { + next_info = info->next; + if (info->str != info_default_string) + free(info->str); + free(info); + info = next_info; + } +} + +static int +do_mode_change(tty_str_info *current_mode_p, + char *text, + int text_length) +{ + /* alignment commands: */ + if (fixed_string_eq("left", text, text_length) || + fixed_string_eq("l", text, text_length)) + current_mode_p->alignment = 'l'; + else if (fixed_string_eq("center", text, text_length) || + fixed_string_eq("c", text, text_length)) + current_mode_p->alignment = 'c'; + else if (fixed_string_eq("right", text, text_length) || + fixed_string_eq("r", text, text_length)) + current_mode_p->alignment = 'r'; + + /* font commands: */ + else if (fixed_string_eq("bold", text, text_length) || + fixed_string_eq("b", text, text_length)) + current_mode_p->bold_p = 1; + else if (fixed_string_eq("italic", text, text_length) || + fixed_string_eq("i", text, text_length)) + current_mode_p->italic_p = 1; + else if (fixed_string_eq("roman", text, text_length)) { + current_mode_p->bold_p = 0; + current_mode_p->italic_p = 0; + } else if (fixed_string_eq("beep", text, text_length)) { + current_mode_p->bell_p = 1; + return 1; + } + + /* commands ignored in tty mode: */ + else if (fixed_string_eq("color", text, text_length) || + fixed_string_eq("font", text, text_length)) { + current_mode_p->ignore = 1; + } + return 0; +} + +static void +zwgc_transliterate(char *in, int inlen, char **out, int *outlen){ + int retval = 0; + string notice_charset = var_get_variable("notice_charset"); + string tty_charset = var_get_variable("tty_charset"); + + if (string_Eq(notice_charset, "UNKNOWN") || + string_Eq(notice_charset, tty_charset) || + (retval = ZTransliterate(in, inlen, + notice_charset, tty_charset, + out, outlen)) != 0) { + *out = string_CreateFromData(in, inlen); + *outlen = inlen; + } + if (retval != 0) + var_set_variable("error", strerror(retval)); +} + +static tty_str_info * +convert_desc_to_tty_str_info(desctype *desc) +{ + tty_str_info *temp; + tty_str_info *result = NULL; + tty_str_info *last_result_block = NULL; + int isbeep, did_beep = 0; + +#if !defined(SABER) && defined(__STDC__) + tty_str_info current_mode = { NULL, "", 0, 'l', 0 , 0, 0, 0}; +#else + /* This is needed due to a bug in saber, and lack of pre-ANSI support. */ + tty_str_info current_mode; + + current_mode.next = NULL; + current_mode.str = info_default_string; /* "" */ + current_mode.len = 0; + current_mode.alignment = 'l'; + current_mode.bold_p = 0; + current_mode.italic_p = 0; + current_mode.bell_p = 0; + current_mode.ignore = 0; +#endif + + for (; desc->code!=DT_EOF; desc=desc->next) { + isbeep = 0; + /* Handle environments: */ + if (desc->code == DT_ENV) { + /* PUSH! */ + temp = (tty_str_info *)malloc(sizeof(struct _tty_str_info)); + *temp = current_mode; + current_mode.next = temp; + + isbeep = do_mode_change(¤t_mode, desc->str, desc->len); + if (!isbeep || did_beep) + continue; /* process one beep, ignore other envs */ + } else if (desc->code == DT_END) { + /* POP! */ + temp = current_mode.next; + current_mode = *temp; + free(temp); + continue; + } + + /* Add new block (call it temp) to result: */ + temp = (tty_str_info *)malloc(sizeof(struct _tty_str_info)); + *temp = current_mode; + if (last_result_block) { + last_result_block->next = temp; + last_result_block = temp; + } else { + result = temp; + last_result_block = temp; + } + + if (isbeep) { + /* special processing: need to insert a bell */ + string_dictionary_binding *b; + b = string_dictionary_Lookup(termcap_dict,"B.bell"); + if (b) { + temp->str = strdup(b->value); + temp->len = string_Length(temp->str); + } else + /* shouldn't get here! */ + abort(); + did_beep++; + continue; + } + if (desc->code == DT_STR) { + /* just combine string info with current mode: */ + zwgc_transliterate(desc->str, desc->len, &temp->str, &temp->len); + } else if (desc->code == DT_NL) { + /* make the new block a ' ' alignment block with an empty string */ + temp->alignment = ' '; + temp->len = 0; + temp->ignore = 0; + } + } + + if (last_result_block) + last_result_block->next = NULL; + + return(result); +} + +#define max(a,b) ((a)>(b)?(a):(b)) + +static int +line_width(int left_width, + int center_width, + int right_width) +{ + if (center_width>0) { + if (left_width==0 && right_width==0) + return(center_width); + return(center_width+2+max(left_width,right_width)*2); + } else { + if (left_width && right_width) + return(1+left_width+right_width); + else + return(left_width+right_width); + } +} + +static int +calc_max_line_width(tty_str_info *info) +{ + int max_line_width = 0; + int left = 0; + int center = 0; + int right = 0; + + for (; info; info=info->next) { + if (info->ignore) + continue; + switch (info->alignment) { + case 'l': + left += info->len; + break; + + case 'c': + center += info->len; + break; + + case 'r': + right += info->len; + break; + + case ' ': +#ifdef DEBUG + if (zwgc_debug) + printf("width: %d %d %d = %d\n", left, center, right, + line_width(left, center, right)); +#endif + max_line_width = max(max_line_width, + line_width(left, center, right)); + left = center = right = 0; + break; + } + } + +#ifdef DEBUG + if (zwgc_debug) + printf("width: %d %d %d = %d\n", left, center, right, + line_width(left, center, right)); +#endif + max_line_width = max(max_line_width, + line_width(left, center, right)); + + return(max_line_width); +} + +string +tty_filter(string text, + int use_fonts) +{ + string text_copy = string_Copy(text); + string result_so_far = string_Copy(""); + desctype *desc; + int number_of_strs; + int number_of_lines; + tty_str_info *info, *info_head; + int max_line_width; + + desc = disp_get_cmds(text_copy, &number_of_strs, &number_of_lines); + info_head = info = convert_desc_to_tty_str_info(desc); + free_desc(desc); + +#ifdef DEBUG + if (zwgc_debug) + { tty_str_info *ptr; + for (ptr=info; ptr; ptr=ptr->next) { + printf("%c: %s %s %s <%s>\n", ptr->alignment, + ptr->bold_p ? "(bold)" : "", + ptr->italic_p ? "(italic)" : "", + ptr->bell_p ? "(bell)" : "", + string_CreateFromData(ptr->str, ptr->len)); + } + } +#endif + + max_line_width = calc_max_line_width(info); + dprintf1("max width = %d\n", max_line_width); + + while (info) { + string left, center, right; + int left_width, center_width, right_width; + char *temp; + + left_width = center_width = right_width = 0; + left = string_Copy(""); + center = string_Copy(""); + right = string_Copy(""); + + for (; info && info->alignment!=' '; info=info->next) { + string item; + + if (info->ignore) + continue; + + item = string_Copy(""); + + if (info->bold_p && use_fonts) { + temp = string_dictionary_Fetch(termcap_dict, "B.bold"); + if (temp) + item = string_Concat2(item, temp); + } else if (info->italic_p && use_fonts) { + temp = string_dictionary_Fetch(termcap_dict, "B.u"); + if (temp) + item = string_Concat2(item, temp); + } + temp = string_CreateFromData(info->str, info->len); + item = string_Concat2(item, temp); + free(temp); + + if (info->bold_p && use_fonts) { + temp = string_dictionary_Fetch(termcap_dict, "E.bold"); + if (temp) + item = string_Concat2(item, temp); + } else if (info->italic_p && use_fonts) { + temp = string_dictionary_Fetch(termcap_dict, "E.u"); + if (temp) + item = string_Concat2(item, temp); + } + + switch (info->alignment) { + default: + case 'l': + left = string_Concat2(left, item); + left_width += info->len; + break; + + case 'c': + center = string_Concat2(center, item); + center_width += info->len; + break; + + case 'r': + right = string_Concat2(right, item); + right_width += info->len; + break; + } + free(item); + } + + result_so_far = string_Concat2(result_so_far, left); + if (center_width) + while (left_width < (max_line_width-center_width)/2 ) { + result_so_far = string_Concat2(result_so_far, " "); + left_width++; + } + result_so_far = string_Concat2(result_so_far, center); + left_width += center_width; + + if (right_width) + while (left_widthalignment == ' ') { + info = info->next; + result_so_far = string_Concat2(result_so_far, "\r\n"); + } + } + + free_info(info_head); + free(text_copy); + if (number_of_lines && + (result_so_far[string_Length(result_so_far)-1] != '\n')) + /* CRLF-terminate all results */ + result_so_far = string_Concat2(result_so_far, "\r\n"); + return(result_so_far); +} diff --git a/zwgc/tty_filter.h b/zwgc/tty_filter.h new file mode 100644 index 0000000..77f0e28 --- /dev/null +++ b/zwgc/tty_filter.h @@ -0,0 +1,2 @@ +extern int tty_filter_init(char *, char, int *, char **); +extern string tty_filter(string, int); diff --git a/zwgc/unsigned_long.h b/zwgc/unsigned_long.h new file mode 100644 index 0000000..92b1725 --- /dev/null +++ b/zwgc/unsigned_long.h @@ -0,0 +1,4 @@ +/* $Id$ + */ + +#define unsigned_long unsigned long diff --git a/zwgc/variables.c b/zwgc/variables.c new file mode 100644 index 0000000..3368c1f --- /dev/null +++ b/zwgc/variables.c @@ -0,0 +1,243 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_variables_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Module containing code to deal with description langauge variables: */ +/* */ +/****************************************************************************/ + +#include "new_memory.h" +#include "notice.h" +#include "string_dictionary_aux.h" +#include "variables.h" + +/* + * fields_data[_length] - these point to the field data that the number + * variables were last set to using + * var_set_number_variables_to_fields. + */ + +static char *fields_data; +static int fields_data_length = 0; + +/* + * [non_]number_variable_dict - contains the values of all the [non-]number + * variables that have been set since the last + * var_clear_all_variables call or (for numbers + * only) var_set_number_variables_to_fields call. + */ + +static string_dictionary non_number_variable_dict = NULL; +static string_dictionary number_variable_dict = NULL; + +/* + * Internal Routine: + * + * int is_digits(string text) + * Effects: Returns true iff text matches [0-9]*. ("" matches...) + */ + +static int +is_digits(string text) +{ + for (; *text; text++) + if (!isdigit(*text)) + return(0); + + return(1); +} + +/* + * Internal Routine: + * + * int is_number_variable(string text) + * Effects: Returns true iff text matches [0-9]+. + */ + +#define is_number_variable(x) (isdigit(*(x)) && is_digits((x))) + +/* + * void var_clear_all_variables() + * Requires: This routine must be called before any other + * var module routine is called. + * Modifies: All description language variables + * Effects: Sets all description langauge variables to "". + */ + +void +var_clear_all_variables(void) +{ + if (non_number_variable_dict) { + string_dictionary_SafeDestroy(non_number_variable_dict); + string_dictionary_SafeDestroy(number_variable_dict); + } + + non_number_variable_dict = string_dictionary_Create(101); + number_variable_dict = string_dictionary_Create(11); + fields_data_length = 0; +} + +/* + * string var_get_variable(string name) + * Requires: var_clear_all_variables has been called + * Effects: Returns the value of the description langauge variable + * named name. The returned string is read-only and is + * guarenteed to last only until the next var module + * call. DO NOT FREE THIS STRING. + */ + +string +var_get_variable(string name) +{ + char *result; + int field_to_get; + static string last_get_field_call_result = NULL; + + if (is_number_variable(name)) { + result = string_dictionary_Fetch(number_variable_dict, name); + if (result) + return(result); + + /* + * Convert name to an integer avoiding overflow: + */ + while (*name=='0') + name++; + if (strlen(name)>12) + field_to_get = 0; /* no way we'll have > 1 trillian fields... */ + else + field_to_get = atoi(name); + + if (!field_to_get) + return(""); + if (last_get_field_call_result) + free(last_get_field_call_result); + last_get_field_call_result = get_field(fields_data, + fields_data_length, + field_to_get); + return(last_get_field_call_result); + } + + if (!(result = string_dictionary_Fetch(non_number_variable_dict, name))) + result = ""; + + return(result); +} + +/* + * void var_set_variable(string name, value) + * Requires: var_clear_all_variables has been called + * Modifies: The value of description langauge variable + * named name. + * Effects: Sets the description langauge variable named name + * to have the value value. + */ + +void +var_set_variable(string name, + string value) +{ + string_dictionary_Set(is_number_variable(name) ? number_variable_dict + : non_number_variable_dict, name, value); +} + +/* + * void var_set_variable_to_number(string name; int number) + * Requires: var_clear_all_variables has been called + * Modifies: The value of description langauge variable + * named name. + * Effects: Sets the description langauge variable named name + * to have as its value number's ascii representation. + */ + +void +var_set_variable_to_number(string name, + int number) +{ + char buffer[20]; + + sprintf(buffer, "%d", number); + var_set_variable(name, buffer); +} + +/* + * void var_set_variable_then_free_value(string name, value) + * Requires: var_clear_all_variables has been called, value is + * on the heap. + * Modifies: The value of description langauge variable + * named name, value + * Effects: Sets the description langauge variable named name + * to have the value value then frees value. This + * routine is slightly faster than calling var_set_variable + * then freeing value. It is provided mainly for + * convenience reasons. + */ + +void +var_set_variable_then_free_value(string name, + string value) +{ + string_dictionary_binding *binding; + int exists; + +#ifdef DEBUG_MEMORY + if (!memory__on_heap_p(value)) + abort(); /* <<<>>> */ +#endif + + if (is_number_variable(name)) { + var_set_variable(name, value); + free(value); + return; + } + + binding = string_dictionary_Define(non_number_variable_dict, name, + &exists); + if (exists) + free(binding->value); + binding->value = value; +} + +/* + * void var_set_number_variables_to_fields(char *data, int length) + * Requires: var_clear_all_variables has been called + * Modifies: All numeric description language variables + * Effects: Treats data[0]..data[length-1] as a series of + * null-seperated fields. Sets $ ( + * here means [0-9]+ to field # in data. + * Field 0 is defined to be "" as are all field #'s + * greater than the number of fields in data. + * Data[0]..data[length-1] must not be changed (or freed) + * until either this call is made again with different + * data or var_clear_all_variables is called. + */ + +void +var_set_number_variables_to_fields(char *data, + int length) +{ + fields_data = data; + fields_data_length = length; + + string_dictionary_SafeDestroy(number_variable_dict); + number_variable_dict = string_dictionary_Create(11); +} diff --git a/zwgc/variables.h b/zwgc/variables.h new file mode 100644 index 0000000..b0be99b --- /dev/null +++ b/zwgc/variables.h @@ -0,0 +1,96 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef var_MODULE +#define var_MODULE + +#include "new_string.h" + +/* + * void var_clear_all_variables() + * Requires: This routine must be called before any other + * var module routine is called. + * Modifies: All description language variables + * Effects: Sets all description langauge variables to "". + */ + +extern void var_clear_all_variables(void); + +/* + * string var_get_variable(string name) + * Requires: var_clear_all_variables has been called + * Effects: Returns the value of the description langauge variable + * named name. The returned string is read-only and is + * guarenteed to last only until the next var module + * call. DO NOT FREE THIS STRING. + */ + +extern string var_get_variable(string); + +/* + * void var_set_variable(string name, value) + * Requires: var_clear_all_variables has been called + * Modifies: The value of description langauge variable + * named name. + * Effects: Sets the description langauge variable named name + * to have the value value. + */ + +extern void var_set_variable(string, string); + +/* + * void var_set_variable_to_number(string name; int number) + * Requires: var_clear_all_variables has been called + * Modifies: The value of description langauge variable + * named name. + * Effects: Sets the description langauge variable named name + * to have as its value number's ascii representation. + */ + +extern void var_set_variable_to_number(string, int); + +/* + * void var_set_variable_then_free_value(string name, value) + * Requires: var_clear_all_variables has been called, value is + * on the heap. + * Modifies: The value of description langauge variable + * named name, value + * Effects: Sets the description langauge variable named name + * to have the value value then frees value. This + * routine is slightly faster than calling var_set_variable + * then freeing value. It is provided mainly for + * convenience reasons. + */ + +extern void var_set_variable_then_free_value(string, string); + +/* + * void var_set_number_variables_to_fields(char *data, int length) + * Requires: var_clear_all_variables has been called + * Modifies: All numeric description language variables + * Effects: Treats data[0]..data[length-1] as a series of + * null-seperated fields. Sets $ ( + * here means [0-9]+ to field # in data. + * Field 0 is defined to be "" as are all field #'s + * greater than the number of fields in data. + * Data[0]..data[length-1] must not be changed (or freed) + * until either this call is made again with different + * data or var_clear_all_variables is called. + */ + +extern void var_set_number_variables_to_fields(char *, int); + +#endif diff --git a/zwgc/xcut.c b/zwgc/xcut.c new file mode 100644 index 0000000..a5d5b39 --- /dev/null +++ b/zwgc/xcut.c @@ -0,0 +1,437 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xcut_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Code to deal with handling X events: */ +/* */ +/****************************************************************************/ + +#ifndef X_DISPLAY_MISSING + +#include +#include +#include +#include "new_memory.h" +#include "new_string.h" +#include "X_gram.h" +#include "zwgc.h" +#include "xselect.h" +#include "xmark.h" +#include "error.h" +#include "xrevstack.h" +#include "X_driver.h" +#include "xcut.h" +#ifdef CMU_ZWGCPLUS +#include "plus.h" +#include "variables.h" +#endif + +/* + * + */ + +extern long ttl; + +static char *selected_text=NULL; +static Window selecting_in = 0; + +char * +getSelectedText(void) +{ + return(selected_text); +} + +#ifdef notdef +static string +x_gram_to_string(x_gram *gram) +{ + int i, index, len; + int last_y = -1; + string temp; + string text_so_far = string_Copy(""); + char *text; + + text = gram->text; + for (i=0; inumblocks; i++) { + if (last_y != -1 && last_y != gram->blocks[i].y) + text_so_far = string_Concat2(text_so_far, "\n"); + index = gram->blocks[i].strindex; + len = gram->blocks[i].strlen; + temp = string_CreateFromData(text+index, len); + text_so_far = string_Concat2(text_so_far, temp); + free(temp); + last_y = gram->blocks[i].y; + } + + text_so_far = string_Concat2(text_so_far, "\n"); + return(text_so_far); +} +#endif + +/* + * + */ + +#if 0 +/*ARGSUSED*/ +static Bool +isShiftButton1(Display *dpy, + XEvent *event, + char *arg) +{ + return(event->xbutton.state & (ShiftMask|Button1Mask)); +} + +/*ARGSUSED*/ +static Bool +isShiftButton3(Display *dpy, + XEvent *event, + char *arg) +{ + return(event->xbutton.state & (ShiftMask|Button3Mask)); +} + +static void +getLastEvent(Display *dpy, + unsigned int state, + XEvent *event) +{ + XEvent xev; + + if (state & Button1Mask) { + while(XCheckIfEvent(dpy,&xev,isShiftButton1,NULL)) + *event=xev; + } else if (state & Button3Mask) { + while(XCheckIfEvent(dpy,&xev,isShiftButton3,NULL)) + *event=xev; + } +} +#endif + +static void +xunmark(Display *dpy, + Window w, + x_gram *gram, + XContext desc_context) +{ + XPointer gramp; /* Avoid strict aliasing violation */ + + if (gram == NULL) { + if (XFindContext(dpy, w, desc_context, &gramp)) + return; + gram = (x_gram *)gramp; + } + + xmarkClear(); + xmarkRedraw(dpy,w,gram,XMARK_REDRAW_OLD); +} + +/* This is out here so xdestroygram can get at it */ + +#define PRESSOP_NONE 0 /* nothing */ +#define PRESSOP_KILL 1 /* normal click */ +#define PRESSOP_SEL 2 /* shift left */ +#define PRESSOP_EXT 3 /* shift right */ +#define PRESSOP_NUKE 4 /* ctrl */ +#define PRESSOP_STOP 5 /* pressop cancelled by moving out of window */ + +static int current_pressop = PRESSOP_NONE; + +void +xdestroygram(Display *dpy, + Window w, + XContext desc_context, + x_gram *gram) +{ + struct timeval now; + int i; + + gettimeofday(&now,NULL); + if ((gram->can_die.tv_sec == 0) || + (gram->can_die.tv_sec > now.tv_sec) || + ((gram->can_die.tv_sec == now.tv_sec) && + (gram->can_die.tv_usec > now.tv_usec))) + return; + + if (w == selecting_in) { + selecting_in = 0; + xmarkClear(); + } + current_pressop = PRESSOP_NONE; + XDeleteContext(dpy, w, desc_context); + XDestroyWindow(dpy, w); + delete_gram(gram); + free(gram->text); + for (i=0; i < gram->numblocks; i++) + free(gram->blocks[i].wstr); + free(gram->blocks); +#ifdef CMU_ZWGCPLUS + if (gram->notice) + list_del_notice(gram->notice); +#endif + free(gram); + +#ifdef CMU_ZWGCPLUS + XFlush(dpy); +#endif + + if (bottom_gram == NULL && unlinked == NULL) { + /* flush colormap here */ + } +} + +void +xcut(Display *dpy, + XEvent *event, + XContext desc_context) +{ + XPointer gramp; /* Avoid strict aliasing violation */ + x_gram *gram; + Window w = event->xany.window; + int changedbound; + + /* + * If event is for a window that's not ours anymore (say we're + * in the process of deleting it...), ignore it: + */ + if (XFindContext(dpy, w, desc_context, &gramp)) + return; + gram = (x_gram *)gramp; + + /* + * Dispatch on the event type: + */ + switch(event->type) { +#ifdef CMU_ZWGCPLUS + case KeyPress: + { + char c; + char *plusvar; + int res, metaflag; + res = XLookupString(&(event->xkey), &c, 1, NULL, NULL); + metaflag = event->xkey.state & Mod1Mask; + + /* Recheck if zwgcplus is turned on; + * Zephyr variables override zwgc variables + */ + + zwgcplus = 1; + plusvar = ZGetVariable("zwgcplus") + ? ZGetVariable("zwgcplus") : var_get_variable("zwgcplus"); + + if ((plusvar[0]=='\0') || (strcmp(plusvar,"no") == 0)) + zwgcplus = 0; + else { + if (strcmp(plusvar,"no") == 0) + zwgcplus = 0; + if (strcmp(plusvar,"new") == 0) + zwgcplus = 2; + } + + if (res != 0 && zwgcplus != 0) + plus_retry_notice(gram->notice, c, metaflag); + } + break; +#endif + case ClientMessage: + if ((event->xclient.message_type == XA_WM_PROTOCOLS) && + (event->xclient.format == 32) && + (event->xclient.data.l[0] == (long)XA_WM_DELETE_WINDOW)) + xdestroygram(dpy,w,desc_context,gram); + break; + + case MapNotify: + /* I don't like using the local time, but MapNotify events don't + * come with a timestamp, and there's no way to query the server + */ + + if (gram->can_die.tv_sec == 0) { + gettimeofday(&(gram->can_die),NULL); + gram->can_die.tv_sec += (int) (ttl/1000); + gram->can_die.tv_usec += (ttl%1000)*1000; + } + break; + + case UnmapNotify: + unlink_gram(gram); + break; + + case LeaveNotify: + if (current_pressop == PRESSOP_KILL || + current_pressop == PRESSOP_NUKE) + current_pressop = PRESSOP_STOP; + break; + + case MotionNotify: + if (current_pressop == PRESSOP_SEL) { + /* getLastEvent(dpy,Button1Mask,event); */ + changedbound=xmarkExtendFromFirst(gram,event->xmotion.x, + event->xmotion.y); + xmarkRedraw(dpy,w,gram,changedbound); + } else if (current_pressop == PRESSOP_EXT) { + /* getLastEvent(dpy,Button3Mask,event); */ + changedbound=xmarkExtendFromNearest(gram,event->xmotion.x, + event->xmotion.y); + xmarkRedraw(dpy,w,gram,changedbound); + } + break; + + case ButtonPress: + if (current_pressop != PRESSOP_NONE) { + current_pressop = PRESSOP_STOP; + } else if ((event->xbutton.button==Button4 || + event->xbutton.button==Button5) && + !get_bool_resource("scrollDelete","ScrollDelete",0)) { + /* Ignore scroll wheel movement. */ + break; + } else if ( (event->xbutton.state)&ShiftMask ) { + if (event->xbutton.button==Button1) { + if (selecting_in) + xunmark(dpy,selecting_in,NULL,desc_context); + if (selected_text) free(selected_text); + selected_text = NULL; + if (! xselGetOwnership(dpy,w,event->xbutton.time)) { + XBell(dpy,0); + ERROR("Unable to get ownership of PRIMARY selection.\n"); + selecting_in = 0; + current_pressop = PRESSOP_STOP; + } else { + selecting_in = w; + xmarkStart(gram,event->xbutton.x,event->xbutton.y); + current_pressop = PRESSOP_SEL; + } + } else if ((event->xbutton.button==Button3) && + (w == selecting_in)) { + if (selected_text) free(selected_text); + selected_text = NULL; + changedbound=xmarkExtendFromNearest(gram,event->xbutton.x, + event->xbutton.y); + xmarkRedraw(dpy,w,gram,changedbound); + selected_text = xmarkGetText(); + /* this is ok, since to get here, the selection must be owned */ + current_pressop = PRESSOP_EXT; +#ifdef CMU_ZWGCPLUS + if (selected_text) + XStoreBytes(dpy, selected_text, strlen(selected_text)+1); +#endif + } + } else if ( (event->xbutton.state)&ControlMask ) { + current_pressop = PRESSOP_NUKE; + } else { + current_pressop = PRESSOP_KILL; + } + break; + + case ButtonRelease: + if (current_pressop == PRESSOP_KILL) { + xdestroygram(dpy,w,desc_context,gram); + } else if (current_pressop == PRESSOP_SEL || + current_pressop == PRESSOP_EXT) { + if (selected_text) free(selected_text); + selected_text = xmarkGetText(); +#ifdef CMU_ZWGCPLUS + if (selected_text) + XStoreBytes(dpy, selected_text, strlen(selected_text)+1); +#endif + } else if (current_pressop == PRESSOP_NUKE) { + XWindowAttributes wa; + int gx,gy; + Window temp; + x_gram *next; + + for (gram = bottom_gram ; gram ; gram = next) { + XGetWindowAttributes(dpy,gram->w,&wa); + XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy, + &temp); + + next = gram->above; + + if ((wa.map_state == IsViewable) && + (gx <= event->xbutton.x_root) && + (event->xbutton.x_root < gx+wa.width) && + (gy <= event->xbutton.y_root) && + (event->xbutton.y_root < gy+wa.height)) { + xdestroygram(dpy,gram->w,desc_context,gram); + } + } + for (gram = unlinked ; gram ; gram = next) { + XGetWindowAttributes(dpy,gram->w,&wa); + XTranslateCoordinates(dpy,gram->w,wa.root,0,0,&gx,&gy, + &temp); + + next = gram->above; + + if ((wa.map_state == IsViewable) && + (gx <= event->xbutton.x_root) && + (event->xbutton.x_root < gx+wa.width) && + (gy <= event->xbutton.y_root) && + (event->xbutton.y_root < gy+wa.height)) { + xdestroygram(dpy,gram->w,desc_context,gram); + } + } + } + current_pressop = PRESSOP_NONE; + break; + + case SelectionRequest: + xselProcessSelection(dpy,w,event); + break; + + case SelectionClear: + xselOwnershipLost(event->xselectionclear.time); + if (w == selecting_in) { + selecting_in = 0; + xunmark(dpy,w,gram,desc_context); + if (selected_text) free(selected_text); + selected_text = NULL; + } + break; + +#ifdef notdef + case ConfigureNotify: +#ifdef DEBUG + if (zwgc_debug) + printf("ConfigureNotify received for wid %lx above wid %lx\n", + (long) w,(long) event->xconfigure.above); +#endif + if (gram->above==gram) { + /* a new zgram. Straight to the bottom! */ + add_to_bottom(gram); + } else if (event->xconfigure.above) { + /* some zgram was pulled to the top */ + pull_to_top(gram); + } else { + /* Some zgram was pushed to the bottom */ + push_to_bottom(gram); + } + /* Note that there is no option to configure a zgram to the middle */ + break; +#endif + default: + break; + } + + XFlush(dpy); +} + +#endif + diff --git a/zwgc/xcut.h b/zwgc/xcut.h new file mode 100644 index 0000000..f4e034a --- /dev/null +++ b/zwgc/xcut.h @@ -0,0 +1,5 @@ +/* $Id$ + * + */ + +void xdestroygram(Display *dpy, Window w, XContext desc_context, x_gram *gram); diff --git a/zwgc/xerror.c b/zwgc/xerror.c new file mode 100644 index 0000000..cb934b5 --- /dev/null +++ b/zwgc/xerror.c @@ -0,0 +1,55 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xerror_c[] = "$Id$"; +#endif + +#include + +#ifndef X_DISPLAY_MISSING + +#include +#include "mux.h" +#include "xerror.h" + +int xerror_happened; + +/*ARGSUSED*/ +static int +xerrortrap(Display *dpy, + XErrorEvent *xerrev) +{ + xerror_happened = 1; + return 0; +} + +/*ARGSUSED*/ +void +begin_xerror_trap(Display *dpy) +{ + xerror_happened = 0; + XSetErrorHandler(xerrortrap); +} + +void +end_xerror_trap(Display *dpy) +{ + XSync(dpy,False); + XSetErrorHandler(NULL); +} + +#endif + diff --git a/zwgc/xerror.h b/zwgc/xerror.h new file mode 100644 index 0000000..ea6702e --- /dev/null +++ b/zwgc/xerror.h @@ -0,0 +1,28 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef _XERROR_H_ +#define _XERROR_H_ + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xerror_h[] = "$Id$"; +#endif + +#include + +extern int xerror_happened; + +void begin_xerror_trap(Display *); +void end_xerror_trap(Display *); + +#endif diff --git a/zwgc/xmark.c b/zwgc/xmark.c new file mode 100644 index 0000000..d25796b --- /dev/null +++ b/zwgc/xmark.c @@ -0,0 +1,418 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xmark_c[] = "$Id$"; +#endif + +#include + +#include + +#ifndef X_DISPLAY_MISSING + +#include +#include +#include +#include "X_gram.h" +#include "X_fonts.h" +#include "xmark.h" +#include "new_string.h" + +int markblock[3] = { -1 , -1 , -1 }; +int markchar[3] = { -1 , -1 , -1 }; +int markpixel[3] = { -1 , -1 , -1 }; +x_gram *markgram = NULL; + +int oldblock[2] = { -1 , -1 }; +int oldpixel[2] = { -1 , -1 }; +x_gram *oldgram = NULL; + +#define xmarkValid() \ + ((markgram) && \ + (STARTBLOCK != -1) && (ENDBLOCK != -1) && \ + (STARTCHAR != -1) && (ENDCHAR != -1) && \ + (STARTPIXEL != -1) && (ENDPIXEL != -1)) + +void +xmarkSetBound(x_gram *gram, + int x, + int y, + int which) +{ + int i, xofs, yofs; + XFontSet font; + xblock *xb; + int num_chars; + XRectangle *ink, *logical; + +#ifdef MARK_DEBUG +#define RETURN \ + if ((oldblock[which] != markblock[which]) || \ + (oldpixel[which] != markpixel[which])) { \ + printf("----- SetBound:\noldblock[%d]=%d, oldpixel[%d]=%d\nmarkblock[%d]=%d, markpixel[%d]=%d\n-----", \ + which,oldblock[which],which,oldpixel[which], \ + which,markblock[which],which,markpixel[which]); \ + } \ + return +#else +#define RETURN return +#endif + + if (markgram != gram) { + xmarkClear(); + markgram = gram; + } else if (which < XMARK_TEMP_BOUND) { + oldblock[which]=markblock[which]; + oldpixel[which]=markpixel[which]; + } + + /* Start at the top, fastforward to first span not too high. */ + for (i=0,xb=gram->blocks ; + (inumblocks) && (xb->y2 < y) ; + i++,xb++) ; + + /* the point is after the end */ + if (i==gram->numblocks) { + markblock[which]=i; + markchar[which]=0; + markpixel[which]=0; + RETURN; + } + + /* is the point before the beginning of the line? */ + if (x <= xb->x1) { + markblock[which]=i; + markchar[which]=0; + markpixel[which]=0; + RETURN; + } + + /* is the point in the nether space between this line and the last? */ + if (y < xb->y1) { + markblock[which]=i; + markchar[which]=0; + markpixel[which]=0; + RETURN; + } + + for (yofs=xb->y1;(inumblocks) && (xb->y1 == yofs);i++,xb++) { + + if (x <= xb->x2) { + markblock[which]=i; + + xofs=xb->x1; + if ((x < xofs) || (y < xb->y1)) { + markchar[which]=0; + RETURN; + } + font = xb->font; +#ifdef X_HAVE_UTF8_STRING + Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen, + NULL, NULL, -1, &num_chars, NULL, NULL); +#else + XwcTextPerCharExtents(font, (wchar_t *)xb->wstr, xb->wlen, + NULL, NULL, -1, &num_chars, NULL, NULL); +#endif + ink = malloc(num_chars * sizeof(XRectangle)); + logical = malloc(num_chars * sizeof(XRectangle)); +#ifdef X_HAVE_UTF8_STRING + Xutf8TextPerCharExtents(font, xb->wstr, xb->wlen, + ink, logical, num_chars, &num_chars, NULL, NULL); +#else + XwcTextPerCharExtents(font, (wchar_t *)xb->wstr, xb->wlen, + ink, logical, num_chars, &num_chars, NULL, NULL); +#endif + for (i=0;ix1; + free(ink); + free(logical); + RETURN; + } + } + free(ink); + free(logical); + } + } + + /* The endpoint is after the end of the block if the loop ends */ + markblock[which]=i; + markchar[which]=0; + markpixel[which]=0; + RETURN; +} + +/* needs both bounds to be valid (!= -1) */ +static int +xmarkNearest(int x, + int y) +{ + int middle; + + xmarkSetBound(markgram,x,y,XMARK_TEMP_BOUND); + middle=(ENDBLOCK+STARTBLOCK)/2; + + if (markblock[XMARK_TEMP_BOUND] < middle) + return(XMARK_START_BOUND); + else if (markblock[XMARK_TEMP_BOUND] > middle) + return(XMARK_END_BOUND); + else { + middle=(ENDCHAR+STARTCHAR)/2; + if (markchar[XMARK_TEMP_BOUND] < middle) + return(XMARK_START_BOUND); + else + return(XMARK_END_BOUND); + } +} + +static void +xmarkExpose(Display *dpy, + Window w, + x_gram *gram, + unsigned int b1, + unsigned int p1, + unsigned int b2, + unsigned int p2) +{ +#define swap(x,y) temp=(x); (x)=(y); (y)=temp + unsigned int i,temp; + XEvent event; +#define expose (event.xexpose) + + if (((int)b1==-1) || ((int)p1==-1) || ((int)b2==-1) || ((int)p2==-1)) + return; + + if ((b1 > b2) || ((b1 == b2) && (p1 > p2))) { + swap(b1,b2); + swap(p1,p2); + } + +#if defined(_IBMR2) && !defined(__GNUC__) && defined(RS6000_OPT_BUG) + /* A version of the AIX 3.1 RS/6000 C compiler needs this to prevent + a core dump in the loop below. */ + &b1; +#endif + + expose.type=Expose; + expose.display=dpy; + expose.window=w; + + for (i=b1;i<=b2;i++) { + if (b1==b2) { + expose.x=gram->blocks[i].x1+p1; + expose.y=gram->blocks[i].y1; + expose.width=p2-p1; + expose.height=gram->blocks[i].y2-gram->blocks[i].y1; + expose.count=0; + } else if (i==b1) { + expose.x=gram->blocks[i].x1+p1; + expose.y=gram->blocks[i].y1; + expose.width=gram->blocks[i].x2-p1; + expose.height=gram->blocks[i].y2-gram->blocks[i].y1; + expose.count=b2-i; + } else if (i==b2) { + expose.x=gram->blocks[i].x1; + expose.y=gram->blocks[i].y1; + expose.width=p2; + expose.height=gram->blocks[i].y2-gram->blocks[i].y1; + expose.count=b2-i; + } else { + expose.x=gram->blocks[i].x1; + expose.y=gram->blocks[i].y1; + expose.width=gram->blocks[i].x2-gram->blocks[i].x1; + expose.height=gram->blocks[i].y2-gram->blocks[i].y1; + expose.count=b2-i; + } + +#ifdef MARK_DEBUG + if (expose.width && expose.height) { + printf("---- markExpose:\nb1=%d p1=%d b2=%d p2=%d\n",b1,p1,b2,p2); + printf("x=%d y=%d w=%d h=%d\n-----", + expose.x,expose.y,expose.width,expose.height); + } +#endif + if ((expose.width && expose.height) || (expose.count == 0)) + XSendEvent(dpy,w,True,ExposureMask,&event); + } +} + +/* Public functions: */ + +void +xmarkRedraw(Display *dpy, + Window w, + x_gram *gram, + int range) +{ +#define ob1 ((unsigned int) oldblock[XMARK_START_BOUND]) +#define ob2 ((unsigned int) oldblock[XMARK_END_BOUND]) +#define nb1 ((unsigned int) markblock[XMARK_START_BOUND]) +#define nb2 ((unsigned int) markblock[XMARK_END_BOUND]) +#define op1 ((unsigned int) oldpixel[XMARK_START_BOUND]) +#define op2 ((unsigned int) oldpixel[XMARK_END_BOUND]) +#define np1 ((unsigned int) markpixel[XMARK_START_BOUND]) +#define np2 ((unsigned int) markpixel[XMARK_END_BOUND]) + + if (range==XMARK_REDRAW_CURRENT) { + if (!markgram) return; + xmarkExpose(dpy,w,gram,nb1,np1,nb2,np2); + } else if (range==XMARK_REDRAW_OLD) { + if (!oldgram) return; + xmarkExpose(dpy,w,gram,ob1,op1,ob2,op2); + } else if (range==XMARK_REDRAW_START) { + if (!markgram) return; + xmarkExpose(dpy,w,gram,ob1,op1,nb1,np1); + } else if (range==XMARK_REDRAW_END) { + if (!markgram) return; + xmarkExpose(dpy,w,gram,ob2,op2,nb2,np2); + } +#ifdef DEBUG + else { + printf("xmarkRedraw: This shouldn't happen!\n"); + } +#endif +} + +/* needs both bounds to be valid (!= -1) */ +int +xmarkSecond(void) +{ + if (STARTBLOCK > ENDBLOCK) + return(XMARK_START_BOUND); + else if (STARTBLOCK < ENDBLOCK) + return(XMARK_END_BOUND); + else { + if (STARTCHAR > ENDCHAR) + return(XMARK_START_BOUND); + else if (STARTCHAR < ENDCHAR) + return(XMARK_END_BOUND); + else + return(XMARK_END_BOUND); + } +} + +void +xmarkClear(void) +{ + oldblock[0]=markblock[0]; + oldblock[1]=markblock[1]; + oldpixel[0]=markpixel[0]; + oldpixel[1]=markpixel[1]; + oldgram=markgram; + + markblock[0] = -1; + markblock[1] = -1; + markchar[0] = -1; + markchar[1] = -1; + markpixel[0] = -1; + markpixel[1] = -1; + markgram=NULL; +} + +int +xmarkExtendFromFirst(x_gram *gram, + int x, + int y) +{ + if (markgram != gram) { + xmarkClear(); + markgram = gram; + } + + if (STARTBLOCK == -1) { + xmarkStart(gram,x,y); + xmarkEnd(gram,x,y); + return(XMARK_REDRAW_CURRENT); + } else if (ENDBLOCK == -1) { + xmarkEnd(gram,x,y); + return(XMARK_REDRAW_CURRENT); + } else { + xmarkSetBound(gram,x,y,XMARK_END_BOUND); + return(XMARK_REDRAW_END); + } +} + +int +xmarkExtendFromNearest(x_gram *gram, + int x, + int y) +{ + int bound; + + if (markgram != gram) { + xmarkClear(); + markgram = gram; + } + + if (STARTBLOCK == -1) { + xmarkStart(gram,x,y); + xmarkEnd(gram,x,y); + return(XMARK_REDRAW_CURRENT); + } else if (ENDBLOCK == -1) { + xmarkEnd(gram,x,y); + return(XMARK_REDRAW_CURRENT); + } else { + xmarkSetBound(gram,x,y,bound=xmarkNearest(x,y)); + return(bound==XMARK_START_BOUND?XMARK_REDRAW_START:XMARK_REDRAW_END); + } +} + +char * +xmarkGetText(void) +{ + int i, idx, len; + int last_y = -1; + string temp; + string text_so_far = string_Copy(""); + char *text = markgram->text; + int startblock,endblock,startchar,endchar; + + if (xmarkValid()) { + if (xmarkSecond() == XMARK_END_BOUND) { + startblock=STARTBLOCK; + endblock=ENDBLOCK; + startchar=STARTCHAR; + endchar=ENDCHAR; + } else { + startblock=ENDBLOCK; + endblock=STARTBLOCK; + startchar=ENDCHAR; + endchar=STARTCHAR; + } + + for (i=startblock; i<=endblock; i++) { + if (last_y != -1 && last_y != markgram->blocks[i].y) + text_so_far = string_Concat2(text_so_far, "\n"); + idx = markgram->blocks[i].strindex; + len = markgram->blocks[i].strlen; + if (startblock == endblock) + temp = string_CreateFromData(text+idx+startchar, + endchar-startchar); + else if (i==startblock) + temp = string_CreateFromData(text+idx+startchar,len-startchar); + else if (i==endblock) + temp = string_CreateFromData(text+idx,endchar); + else + temp = string_CreateFromData(text+idx,len); + text_so_far = string_Concat2(text_so_far, temp); + free(temp); + last_y = markgram->blocks[i].y; + } + } + + return(text_so_far); +} + +#endif /* X_DISPLAY_MISSING */ diff --git a/zwgc/xmark.h b/zwgc/xmark.h new file mode 100644 index 0000000..55c00c2 --- /dev/null +++ b/zwgc/xmark.h @@ -0,0 +1,52 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef _XMARK_H_ +#define _XMARK_H_ + +#define XMARK_START_BOUND 0 +#define XMARK_END_BOUND 1 +#define XMARK_TEMP_BOUND 2 + +#define XMARK_REDRAW_CURRENT 1 +#define XMARK_REDRAW_OLD 2 +#define XMARK_REDRAW_START 3 +#define XMARK_REDRAW_END 4 + +#define xmarkStart(gram,x,y) xmarkSetBound(gram,x,y,XMARK_START_BOUND) +#define xmarkEnd(gram,x,y) xmarkSetBound(gram,x,y,XMARK_END_BOUND) + +extern int markblock[]; +extern int markchar[]; +extern int markpixel[]; +extern x_gram *markgram; + +#define STARTBLOCK (markblock[XMARK_START_BOUND]) +#define ENDBLOCK (markblock[XMARK_END_BOUND]) +#define STARTCHAR (markchar[XMARK_START_BOUND]) +#define ENDCHAR (markchar[XMARK_END_BOUND]) +#define STARTPIXEL (markpixel[XMARK_START_BOUND]) +#define ENDPIXEL (markpixel[XMARK_END_BOUND]) + +extern void xmarkSetBound(x_gram *, int, int, int); +extern int xmarkSecond(void); +extern void xmarkRedraw(Display *, Window, x_gram *, int); +extern void xmarkClear(void); +extern int xmarkExtendFromFirst(x_gram *, int, int); +extern int xmarkExtendFromNearest(x_gram *, int, int); +extern char *xmarkGetText(void); + +#endif diff --git a/zwgc/xrevstack.c b/zwgc/xrevstack.c new file mode 100644 index 0000000..d9fc8a0 --- /dev/null +++ b/zwgc/xrevstack.c @@ -0,0 +1,271 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xrevstack_c[] = "$Id$"; +#endif + +#include + +#ifndef X_DISPLAY_MISSING + +#ifndef TRUEREVSTACK +#include +#include "X_gram.h" +#include "xrevstack.h" + +x_gram *bottom_gram = NULL; +x_gram *unlinked = NULL; +int reverse_stack = 0; + +void +add_to_bottom(x_gram *gram) +{ + if (bottom_gram) { + bottom_gram->below = gram; + gram->below = NULL; + gram->above = bottom_gram; + bottom_gram = gram; + } else { + gram->above = NULL; + gram->below = NULL; + bottom_gram = gram; + } +} + +/*ARGSUSED*/ +void +pull_to_top(x_gram *gram) +{ +} + +/*ARGSUSED*/ +void +push_to_bottom(x_gram *gram) +{ +} + +void +delete_gram(x_gram *gram) +{ + if (gram == bottom_gram) { + if (gram->above) { + bottom_gram = gram->above; + bottom_gram->below = NULL; + } else { + bottom_gram = NULL; + } + } else if (gram == unlinked) { + if (gram->above) { + unlinked = gram->above; + unlinked->below = NULL; + } else { + unlinked = NULL; + } + } else { + if (gram->above) + gram->above->below = gram->below; + gram->below->above = gram->above; + } + + /* fix up above & below pointers so that calling delete_gram + again is safe */ + gram->below = gram; + gram->above = gram; +} + +void +unlink_gram(x_gram *gram) +{ + delete_gram(gram); + + if (unlinked) { + unlinked->below = gram; + gram->below = NULL; + gram->above = unlinked; + unlinked = gram; + } else { + gram->above = NULL; + gram->below = NULL; + unlinked = gram; + } +} + +#endif + +#ifdef TRUEREVSTACK + +#include "X_gram.h" +#include "zwgc.h" +#include + +x_gram *bottom_gram=NULL; +static x_gram *top_gram=NULL; + +#ifdef DEBUG +void +print_gram_list(char *str) +{ + x_gram *gram; + char buf[80]; + + if (zwgc_debug) { + printf("----- From function %s: Top of tree\n",str); + if (top_gram) + if (top_gram->above) + printf("Tree munged: something above top_gram\n"); + for (gram=top_gram;gram;gram=gram->below) { + strncpy(buf,gram->text,63); + buf[63]='\0'; + printf("wid %lx txt: %s\n",(long) gram->w,buf); + } + if (bottom_gram) + if (bottom_gram->below) + printf("Tree munged: something below bottom_gram\n"); + printf("----- Bottom of tree\n"); + } +} +#endif + +void +pull_to_top(x_gram *gram) +{ + if (gram==top_gram) { + /* already here */ + return; + } else if (top_gram==NULL) { + /* no grams at all. Make gram both top and bottom */ + top_gram=gram; + bottom_gram=gram; + } else if (gram==bottom_gram) { + /* bottom gram is special case */ + bottom_gram=bottom_gram->above; + bottom_gram->below=NULL; + top_gram->above=gram; + gram->below=top_gram; + top_gram=gram; + } else { + /* normal case of a gram in the middle */ + gram->above->below=gram->below; + gram->below->above=gram->above; + top_gram->above=gram; + gram->below=top_gram; + gram->above=NULL; + top_gram=gram; + } +#ifdef DEBUG + print_gram_list("pull_to_top"); +#endif +} + +void +push_to_bottom(x_gram *gram) +{ + if (gram==bottom_gram) { + /* already here */ + return; + } else if (bottom_gram==NULL) { + /* no grams at all. Make gram both top and bottom */ + gram->above=NULL; + gram->below=NULL; + top_gram=gram; + bottom_gram=gram; + } else if (gram==top_gram) { + /* top gram is special case */ + top_gram=top_gram->below; + top_gram->above=NULL; + bottom_gram->below=gram; + gram->above=bottom_gram; + bottom_gram=gram; + } else { + /* normal case of a gram in the middle */ + gram->above->below=gram->below; + gram->below->above=gram->above; + bottom_gram->below=gram; + gram->above=bottom_gram; + gram->below=NULL; + bottom_gram=gram; + } +#ifdef DEBUG + print_gram_list("push_to_bottom"); +#endif +} + +void +unlink_gram(x_gram *gram) +{ + if (top_gram==bottom_gram) { + /* the only gram in the stack */ + top_gram=NULL; + bottom_gram=NULL; + } else if (gram==top_gram) { + top_gram=gram->below; + top_gram->above=NULL; + } else if (gram==bottom_gram) { + bottom_gram=gram->above; + bottom_gram->below=NULL; + } else { + gram->above->below=gram->below; + gram->below->above=gram->above; + } +#ifdef DEBUG + print_gram_list("unlink_gram"); +#endif +} + +#ifdef notdef +void +add_to_top(x_gram *gram) +{ + if (top_gram==NULL) { + gram->above=NULL; + gram->below=NULL; + top_gram=gram; + bottom_gram=gram; + } else { + top_gram->above=gram; + gram->above=NULL; + gram->below=top_gram; + top_gram=gram; + } +#ifdef DEBUG + print_gram_list("add_to_top"); +#endif +} +#endif + +void +add_to_bottom(x_gram *gram) +{ + if (bottom_gram==NULL) { + gram->above=NULL; + gram->below=NULL; + top_gram=gram; + bottom_gram=gram; + } else { + bottom_gram->below=gram; + gram->above=bottom_gram; + gram->below=NULL; + bottom_gram=gram; + } +#ifdef DEBUG + print_gram_list("add_to_bottom"); +#endif +} + +#endif /* TRUEREVSTACK */ + +#endif /* X_DISPLAY_MISSING */ + diff --git a/zwgc/xrevstack.h b/zwgc/xrevstack.h new file mode 100644 index 0000000..20d1fe9 --- /dev/null +++ b/zwgc/xrevstack.h @@ -0,0 +1,33 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#ifndef _XREVSTACK_H_ +#define _XREVSTACK_H_ + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xrevstack_h[] = "$Id$"; +#endif + +#include + +extern x_gram *bottom_gram; /* for testing against NULL */ +extern x_gram *unlinked; +extern int reverse_stack; /* is reverse stack on? */ + +extern void add_to_bottom(x_gram *); +extern void delete_gram(x_gram *); +extern void unlink_gram(x_gram *); +extern void pull_to_top(x_gram *); +extern void push_to_bottom(x_gram *); + +#endif /* _XREVSTACK_H_ */ diff --git a/zwgc/xselect.c b/zwgc/xselect.c new file mode 100644 index 0000000..45ac997 --- /dev/null +++ b/zwgc/xselect.c @@ -0,0 +1,214 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xselect_c[] = "$Id$"; +#endif + +#include + +/* xselect.c - ICCCM compliant cut-and-paste */ +/* also includes some other ICCCMisms, such as the WM_PROTOCOL handling */ + +#ifndef X_DISPLAY_MISSING + +#include +#include +#include +#include "new_string.h" +#include "xselect.h" + +extern char *getSelectedText(void); + +static Time ownership_start = CurrentTime; +static Time ownership_end = CurrentTime; +Atom XA_WM_PROTOCOLS,XA_WM_DELETE_WINDOW; +static Atom ZA_TARGETS,ZA_MULTIPLE,ZA_TIMESTAMP,ZA_ATOM_PAIR; + +static struct _ZAtom { + Atom *patom; + char *name; +} ZAtom[] = { + {&XA_WM_PROTOCOLS,"WM_PROTOCOLS"}, + {&XA_WM_DELETE_WINDOW,"WM_DELETE_WINDOW"}, + {&ZA_TARGETS,"TARGETS"}, + {&ZA_MULTIPLE,"MULTIPLE"}, + {&ZA_TIMESTAMP,"TIMESTAMP"}, + {&ZA_ATOM_PAIR,"ATOM_PAIR"} +}; +#define NumZAtoms (sizeof(ZAtom)/sizeof(struct _ZAtom)) + +/* internal static functions */ + +static void +xselNotify(Display *dpy, + XSelectionRequestEvent *selreq, + Atom property) +{ + XSelectionEvent ev; + + ev.type=SelectionNotify; + ev.requestor=selreq->requestor; + ev.selection=selreq->selection; + ev.target=selreq->target; + ev.property=property; + ev.time=selreq->time; + + XSendEvent(dpy,ev.requestor,False,0,(XEvent *) &ev); +} + +/* pRequestAtoms and RequestAtoms should have the same size. */ +static Atom *pRequestAtoms[] = { + &ZA_TARGETS,&ZA_MULTIPLE,&ZA_TIMESTAMP,NULL +}; +static Atom RequestAtoms[] = { + None,None,None,XA_STRING +}; +#define NumRequestAtoms (sizeof(RequestAtoms)/sizeof(Atom)) +#define PROP(prop,targ) ((prop)!=None?(prop):(targ)) +#define ChangeProp(type,format,data,size) \ + XChangeProperty(dpy,w,PROP(property,target),(type),(format), \ + PropModeReplace, (unsigned char *) (data),(size)) + +static void +xselSetProperties(Display *dpy, + Window w, + Atom property, + Atom target, + XSelectionRequestEvent *selreq) +{ + if (target==ZA_TARGETS) { + + ChangeProp(XA_ATOM,32,RequestAtoms,NumRequestAtoms); + XSync(dpy,0); + } else if (target==ZA_MULTIPLE) { + Atom atype; + int aformat; + unsigned char *alistp; /* Avoid strict aliasing violation, we hope */ + Atom *alist; + unsigned long alistsize,i; + + XGetWindowProperty(dpy,w,property,0L,0L,False,ZA_ATOM_PAIR,&atype, + &aformat,&i,&alistsize,&alistp); + + if (alistsize) + XGetWindowProperty(dpy,w,property,0L,alistsize/sizeof(Atom),False, + ZA_ATOM_PAIR,&atype,&aformat,&alistsize,&i, &alistp); + + alist = (Atom *)alistp; + alistsize/=(sizeof(Atom)/4); + for (i=0;ixselectionrequest); + +#ifdef DEBUG + if ((selreq->owner != w) || (selreq->selection != XA_PRIMARY)) + fprintf(stderr,"SelectionRequest event has bogus field values\n"); +#endif + + if ((ownership_start == CurrentTime) || + (((selreq->time != CurrentTime) && + (selreq->time < ownership_start)) || + ((ownership_end != CurrentTime) && + (ownership_end > ownership_start) && + (selreq->time > ownership_end)))) + xselNotify(dpy,selreq,None); + else + xselSetProperties(dpy,selreq->requestor,selreq->property,selreq->target, + selreq); + + return(1); +} + +void +xselOwnershipLost(Time when) +{ + ownership_end = when; +} + +/*ARGSUSED*/ +void +xselGiveUpOwnership(Display *dpy, + Window w) +{ + XSetSelectionOwner(dpy,XA_PRIMARY,None,ownership_start); + + ownership_end=ownership_start; /* Is this right? what should I use? */ +} + +#endif /* X_DISPLAY_MISSING */ + diff --git a/zwgc/xselect.h b/zwgc/xselect.h new file mode 100644 index 0000000..f8fa964 --- /dev/null +++ b/zwgc/xselect.h @@ -0,0 +1,28 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef _XSELECT_H_ +#define _XSELECT_H_ + +extern void xicccmInitAtoms(Display *); +extern int xselGetOwnership(Display *, Window, Time); +extern int xselProcessSelection(Display *, Window, XEvent *); +extern void xselOwnershipLost(Time); +extern void xselGiveUpOwnership(Display *, Window); + +extern Atom XA_WM_PROTOCOLS, XA_WM_DELETE_WINDOW; + +#endif diff --git a/zwgc/xshow.c b/zwgc/xshow.c new file mode 100644 index 0000000..afe1037 --- /dev/null +++ b/zwgc/xshow.c @@ -0,0 +1,833 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_xshow_c[] = "$Id$"; +#endif + +#include + +#ifndef X_DISPLAY_MISSING + +#include +#include +#include +#include +#include "pointer_dictionary.h" +#include "new_memory.h" +#include "new_string.h" +#include "formatter.h" +#include "variables.h" +#include "zwgc.h" +#include "X_driver.h" +#include "X_fonts.h" +#include "X_gram.h" +#include "xmode_stack.h" +#ifdef CMU_ZWGCPLUS +#include +#include "xrevstack.h" +#include "plus.h" +#include "xcut.h" +#endif + +#define max(a,b) ((a)>(b)?(a):(b)) + +XContext desc_context; + +extern int internal_border_width; +extern unsigned long default_bgcolor; +extern unsigned long default_fgcolor; + +void +xshowinit(void) +{ + desc_context = XUniqueContext(); +} + +struct res_dict_type { + pointer_dictionary dict; + char * resname_suffix; + char * resclass; +}; + +static char * +xres_get_resource(struct res_dict_type *restype, + char *style) +{ + char *desc; + pointer_dictionary_binding *binding; + int exists; + char *value; + + desc=string_Concat("style.", style); + desc=string_Concat2(desc, restype->resname_suffix); + + if (!restype->dict) + restype->dict = pointer_dictionary_Create(37); + binding = pointer_dictionary_Define(restype->dict, desc, &exists); + + if (exists) { + free(desc); + return((string) binding->value); + } else { + value=get_string_resource(desc, restype->resclass); + free(desc); + if (value==NULL) + pointer_dictionary_Delete(restype->dict, binding); + else + binding->value=(pointer) value; + return value; /* If resource returns NULL, return NULL also */ + } +} + +static struct res_dict_type geometry_resources = { + NULL, ".geometry", "StyleKey.Style1.Style2.Style3.GeometryKey", +}; + +static struct res_dict_type bgcolor_resources = { + NULL, ".background", "StyleKey.Style1.Style2.Style3.BackgroundKey", +}; + +#define xres_get_geometry(style) xres_get_resource(&geometry_resources,style) +#define xres_get_bgcolor(style) xres_get_resource(&bgcolor_resources,style) + +static struct res_dict_type fgcolor_resources = { + NULL, ".foreground", + "StyleKey.Style1.Style2.Style3.SubstyleKey.Substyle.ForegroundKey", +}; + +/*ARGSUSED*/ +static char * +mode_to_colorname (Display *dpy, + char *style, + xmode *mode) +{ + char *desc, *result; + + desc = string_Concat (style, ".substyle."); + desc = string_Concat2 (desc, mode->substyle); + result = xres_get_resource (&fgcolor_resources, desc); + free (desc); + return result; +} + +static void +fixup_and_draw(Display *dpy, + char *style, + xauxblock *auxblocks, + xblock *blocks, + int num, + xlinedesc *lines, + int numlines, + int beepcount) +{ + int gram_xalign = 1; + int gram_yalign = 1; + int gram_xpos, gram_ypos, gram_xsize, gram_ysize; + + x_gram *gram; + int strindex = 0; + + int line, block=0; + int maxwidth=0, chars=0, maxascent, maxdescent; + int ssize, lsize,csize, rsize, width = 0; + int i, ascent, descent; + + int yofs = internal_border_width; + int lofs, cofs, rofs; + int ystart,yend; + + char *bgstr, *geometry, xpos[10], ypos[10], xfrom, yfrom; + XFontSetExtents *fse; + + gram = (x_gram *)malloc(sizeof(x_gram)); + + /* Find total lengths of left, center, and right parts. Also find the + length of the longest line and the total number of characters. */ + + for (line = 0; line < numlines; line++) { + lsize = csize = rsize = 0; + maxascent = maxdescent = 0; + + /* add up sizes for each block, get max ascent and descent */ + + for (i = 0; i < lines[line].numblock; i++, block++) { + chars += auxblocks[block].len; +#ifdef X_HAVE_UTF8_STRING + ssize = Xutf8TextEscapement(auxblocks[block].font, + blocks[block].wstr, + blocks[block].wlen); +#else + ssize = XwcTextEscapement(auxblocks[block].font, + (wchar_t *)blocks[block].wstr, + blocks[block].wlen); +#endif + auxblocks[block].width = ssize; + fse = XExtentsOfFontSet(auxblocks[block].font); + ascent = -fse->max_logical_extent.y; + descent = fse->max_logical_extent.y + fse->max_logical_extent.height; + if (ascent > maxascent) + maxascent = ascent; + if (descent > maxdescent) + maxdescent = descent; + switch (auxblocks[block].align) { + case LEFTALIGN: + lsize += ssize; + break; + + case CENTERALIGN: + csize += ssize; + break; + + case RIGHTALIGN: + rsize += ssize; + break; + } + } + + /* save what we need to do size fixups */ + + if (maxascent > lines[line].ascent) + lines[line].ascent = maxascent; + if (maxdescent > lines[line].descent) + lines[line].descent = maxdescent; + lines[line].lsize = lsize; + lines[line].csize = csize; + lines[line].rsize = rsize; + + /* get width of line and see if it is bigger than the max width */ + + switch ((lsize ? 1 : 0) + (csize ?2 : 0) + (rsize ? 4 : 0)) { +#ifdef DEBUG + default: + abort(); +#endif + + case 0: + width = 0; + break; + + case 1: + width = lsize; + break; + + case 2: + width = csize; + break; + + case 3: + /* in all these cases, we just want to add the width of *any* + space, so the first font will do just fine. */ + /* XXX implicit assumption that a line must have at least one + block, so that there is indeed a reasonable font in + auxblocks[0].font */ + width = lsize * 2 + csize + XmbTextEscapement(auxblocks[0].font, " ", 1); + break; + + case 4: + width = rsize; + break; + + case 5: + width = lsize + rsize + XmbTextEscapement(auxblocks[0].font, " ", 1); + break; + + case 6: + width = csize + rsize * 2 + XmbTextEscapement(auxblocks[0].font, " ", 1); + break; + + case 7: + width = max(lsize, rsize) * 2 + csize + + XmbTextEscapement(auxblocks[0].font, " ", 1) * 2; + break; + } + if (width > maxwidth) + maxwidth = width; + } + + /* fixup x,y for each block, create big string and indices into it */ + /* set x1,y1,x2,y2 of each block also. */ + + gram->text = (char *)malloc(chars); + block = 0; + + for (line = 0; line < numlines; line++) { + lofs = internal_border_width; + cofs = ((maxwidth - lines[line].csize) >> 1) + internal_border_width; + rofs = maxwidth - lines[line].rsize + internal_border_width; + ystart = yofs; + yofs += lines[line].ascent; + yend = yofs + lines[line].descent + 1; /* +1 because lines look scrunched + without it. */ + + for (i = 0; i < lines[line].numblock; i++, block++) { + blocks[block].font = auxblocks[block].font; + switch (auxblocks[block].align) { + case LEFTALIGN: + blocks[block].x = lofs; + blocks[block].x1 = lofs; + lofs += auxblocks[block].width; + blocks[block].x2 = lofs; + break; + + case CENTERALIGN: + blocks[block].x = cofs; + blocks[block].x1 = cofs; + cofs += auxblocks[block].width; + blocks[block].x2 = cofs; + break; + + case RIGHTALIGN: + blocks[block].x = rofs; + blocks[block].x1 = rofs; + rofs += auxblocks[block].width; + blocks[block].x2 = rofs; + break; + } + blocks[block].y = yofs; + blocks[block].y1 = ystart; + blocks[block].y2 = yend; + blocks[block].strindex = strindex; + blocks[block].strlen = auxblocks[block].len; + strncpy(gram->text + strindex, auxblocks[block].str, + auxblocks[block].len); + strindex += blocks[block].strlen; + } + + yofs = yend; + + } + + geometry = var_get_variable("X_geometry"); + if (geometry[0] == '\0') + geometry = xres_get_geometry(style); + if (geometry == NULL) + geometry = var_get_variable("default_X_geometry"); + if (geometry[0] == '\0') + geometry = "+0+0"; + + sscanf(geometry, "%c%[0123456789c]%c%[0123456789c]", &xfrom, xpos, + &yfrom, ypos); + + if (xpos[0] == 'c') { + gram_xalign = 0; + gram_xpos = 0; + } else + gram_xpos = atoi(xpos); + if (xfrom == '-') + gram_xalign *= -1; + + if (ypos[0] == 'c') { + gram_yalign = 0; + gram_ypos = 0; + } else + gram_ypos = atoi(ypos); + if (yfrom == '-') + gram_yalign *= -1; + + bgstr = var_get_variable("X_background"); + if (bgstr[0] == '\0') + bgstr = xres_get_bgcolor(style); + if (bgstr == NULL) + bgstr = var_get_variable("default_X_background"); + if (bgstr[0]=='\0') + gram->bgcolor = default_bgcolor; + + if (bgstr && bgstr[0]) + gram->bgcolor = x_string_to_color(bgstr, default_bgcolor); + + gram_xsize = maxwidth + (internal_border_width << 1); + gram_ysize = yofs + internal_border_width; + gram->numblocks = num; + gram->blocks = blocks; +#ifdef CMU_ZWGCPLUS + gram->notice = get_stored_notice(); +#endif + + x_gram_create(dpy, gram, gram_xalign, gram_yalign, gram_xpos, + gram_ypos, gram_xsize, gram_ysize, beepcount); +} + +/* Silly almost-but-not-quite-useless helper function */ +static char * +no_dots_downcase_var(char *str) +{ + register char *var, *var2; + + var = string_Downcase(var_get_variable(str)); + var2 = var; + while (*var++) + if (*var == '.') + *var = '_'; + return(var2); +} + +inline static XFontSet +mode_to_font(Display *dpy, char *style, xmode *mode) { + return get_font(dpy, + style, + mode->font ? mode->font : mode->substyle, + mode->size, + mode->bold + mode->italic * 2); +} + +inline static int +envmatch(desctype *desc, char *str) { + int len = strlen(str); + return desc->len == len && strncasecmp(desc->str, str, len) == 0; +} + +void +xshow(Display *dpy, desctype *desc, int numstr, int numnl) +{ + XFontSet font; + XFontSetExtents *fse; + xmode_stack modes = xmode_stack_create(); + xmode curmode; + xlinedesc *lines; + xblock *blocks; + xauxblock *auxblocks; + int nextblock=0; + int line=0,linestart=0; + char *style; + int free_style = 0; + int beepcount = 0; + char *notice_charset = var_get_variable("notice_charset"); + int i; + + lines = (xlinedesc *)malloc(sizeof(xlinedesc) * (numnl + 1)); + + blocks = (xblock *)malloc(sizeof(xblock) * numstr); + auxblocks = (xauxblock *)malloc(sizeof(xauxblock) * numstr); + + memset(&curmode, 0, sizeof(curmode)); + curmode.bold = 0; + curmode.italic = 0; + curmode.size = MEDIUM_SIZE; + curmode.align = LEFTALIGN; + curmode.expcolor = 0; + curmode.substyle = string_Copy("default"); + curmode.font = NULL; + + style = var_get_variable("style"); + if (style[0] == '\0') { + style = string_Concat(no_dots_downcase_var("class"), "."); + style = string_Concat2(style, no_dots_downcase_var("instance")); + style = string_Concat2(style, "."); + style = string_Concat2(style, no_dots_downcase_var("sender")); + string_Downcase(style); + free_style = 1; + } + + for (; desc->code != DT_EOF; desc = desc->next) { + switch (desc->code) { + case DT_ENV: + xmode_stack_push(modes, curmode); + curmode.substyle = string_Copy(curmode.substyle); + if (curmode.font) + curmode.font = string_Copy(curmode.font); + if (envmatch(desc, "roman")) { + curmode.bold = 0; + curmode.italic = 0; + } else if (envmatch(desc, "bold") || envmatch(desc, "b")) + curmode.bold = 1; + else if (envmatch(desc, "italic") || envmatch(desc, "i")) + curmode.italic = 1; + else if (envmatch(desc, "large")) + curmode.size = LARGE_SIZE; + else if (envmatch(desc, "medium")) + curmode.size = MEDIUM_SIZE; + else if (envmatch(desc, "small")) + curmode.size = SMALL_SIZE; + else if (envmatch(desc, "left") || envmatch(desc, "l")) + curmode.align = LEFTALIGN; + else if (envmatch(desc, "center") || envmatch(desc, "c")) + curmode.align = CENTERALIGN; + else if (envmatch(desc, "right") || envmatch(desc, "r")) + curmode.align = RIGHTALIGN; + else if (envmatch(desc, "beep")) + beepcount++; + else if (envmatch(desc, "font")) { + /* lookahead needed. desc->next->str should be the + font name, and desc->next->next->code should be + a DT_END*/ + if ((desc->next) && + (desc->next->next) && + (desc->next->code == DT_STR) && + (desc->next->next->code == DT_END)) { + + /* Since @font mutates the current environment, we have + to pop the environment that this case usually pushes */ + free(curmode.substyle); + curmode = xmode_stack_top(modes); + xmode_stack_pop(modes); + + /* mutating... */ + curmode.size = SPECIAL_SIZE; /* This is an @font() */ + curmode.font = string_CreateFromData(desc->next->str, + desc->next->len); + /* skip over the rest of the @font */ + desc = desc->next->next; + } + } else if (envmatch(desc, "color")) { + /* lookahead needed. desc->next->str should be the + font name, and desc->next->next->code should be + a DT_END*/ + if ((desc->next) && + (desc->next->next) && + (desc->next->code == DT_STR) && + (desc->next->next->code == DT_END)) { + char *colorname; + + /* Since @font mutates the current environment, we have + to pop the environment that this case usually pushes */ + free(curmode.substyle); + curmode = xmode_stack_top(modes); + xmode_stack_pop(modes); + + /* mutating... */ + colorname = string_CreateFromData(desc->next->str, + desc->next->len); + curmode.color = x_string_to_color(colorname, default_fgcolor); + free(colorname); + curmode.expcolor = 1; + /* skip over the rest of the @font */ + desc = desc->next->next; + } + } else if (desc->len > 0) { /* avoid @{...} */ + free(curmode.substyle); + if (curmode.font) { + free(curmode.font); + curmode.font = NULL; + } + curmode.substyle = string_CreateFromData(desc->str, desc->len); + } + break; + + case DT_STR: + auxblocks[nextblock].align = curmode.align; + auxblocks[nextblock].font = mode_to_font(dpy, style, &curmode); + auxblocks[nextblock].str = desc->str; + auxblocks[nextblock].len = desc->len; + i = ZTransliterate(desc->str, desc->len, + strcmp(notice_charset, "UNKNOWN") ? + notice_charset : "ISO-8859-1", +#ifdef X_HAVE_UTF8_STRING + "UTF-8", +#else + "UTF-16BE", +#endif + &blocks[nextblock].wstr, + &blocks[nextblock].wlen); + if (i) { + var_set_variable("error", strerror(i)); +#ifdef X_HAVE_UTF8_STRING + blocks[nextblock].wlen = desc->len; + blocks[nextblock].wstr = strdup(desc->str); +#else + blocks[nextblock].wlen = desc->len * 2; + blocks[nextblock].wstr = malloc(blocks[nextblock].wlen); + for (i = 0; i < desc->len; i++) + *(short *)&(blocks[nextblock].wstr[i * 2]) = htons((short)(unsigned char)desc->str[i]); + /* XXX */ +#endif + } +#ifndef X_HAVE_UTF8_STRING + blocks[nextblock].wlen /= 2; +#endif + if (curmode.expcolor) + blocks[nextblock].fgcolor = curmode.color; + else + blocks[nextblock].fgcolor = + x_string_to_color(mode_to_colorname(dpy, style, &curmode), + default_fgcolor); + nextblock++; + break; + + case DT_END: + free(curmode.substyle); + curmode = xmode_stack_top(modes); + xmode_stack_pop(modes); + break; + + case DT_NL: + lines[line].startblock = linestart; + lines[line].numblock = nextblock-linestart; + font = mode_to_font(dpy, style, &curmode); + fse = XExtentsOfFontSet(font); + lines[line].ascent = -fse->max_logical_extent.y; + lines[line].descent = fse->max_logical_extent.y + + fse->max_logical_extent.height; + line++; + linestart = nextblock; + break; + } + } + + /* case DT_EOF: will drop through to here. */ + + if (linestart != nextblock) { + lines[line].startblock = linestart; + lines[line].numblock = nextblock-linestart; + font = mode_to_font(dpy, style, &curmode); + lines[line].ascent = 0; + lines[line].descent = 0; + line++; + } + + free(curmode.substyle); + fixup_and_draw(dpy, style, auxblocks, blocks, nextblock, lines, line, + beepcount); + free(lines); + free(auxblocks); + if (free_style) + free(style); +} + +static void +xhandleevent(Display *dpy, + Window w, + XEvent *event) +{ + XPointer gramp; /* Avoid strict aliasing violation */ + x_gram *gram; + + if (XFindContext(dpy, w, desc_context, &gramp)) + return; + gram = (x_gram *)gramp; + + if (event->type == Expose) + x_gram_expose(dpy, w, gram,&(event->xexpose)); + else + xcut(dpy, event, desc_context); + + XFlush(dpy); +} + +void +x_get_input(Display *dpy) +{ + XEvent event; + + dprintf1("Entering x_get_input(%lx).\n",(unsigned long)dpy); + + /* + * Kludge to get around lossage in XPending: + * + * (the problem: XPending on a partial packet returns 0 without + * reading in the packet. This causes a problem when the X server + * dies in the middle of sending a packet.) + */ + if (XPending(dpy)==0) + XNoOp(dpy); /* Ensure server is still with us... */ + + while (XPending(dpy)) { + XNextEvent(dpy,&event); + xhandleevent(dpy, event.xany.window, &event); + } +} + +#ifdef CMU_ZWGCPLUS +void +plus_window_deletions(ZNotice_t *notice) +{ + x_gram *tmp, *fry; + char *val; + int done; + static char class_nm[NAMESIZE], instance_nm[NAMESIZE], recip_nm[NAMESIZE]; + + if (!x_dpy) + return; + + val = var_get_variable("delete_window"); + +#ifdef DEBUG_DELETION + fprintf(stderr, "delete_window(%s)\n", val); +#endif + if (val) { + if (!strcmp(val, "this")) { + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (tmp->notice == notice) { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "s")) { + /* I cheated. This is really sender, not class */ + strcpy(class_nm, notice->z_sender); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "ns")) { + /* I cheated. This is really sender, not class */ + strcpy(class_nm, notice->z_sender); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_sender, class_nm)) { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "r")) { + strcpy(recip_nm, notice->z_recipient); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "nr")) { + strcpy(recip_nm, notice->z_recipient); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!!strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "cir")) { + strcpy(class_nm, notice->z_class); + strcpy(instance_nm, notice->z_class_inst); + strcpy(recip_nm, notice->z_recipient); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm) + && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) + && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) + { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "ci")) { + strcpy(class_nm, notice->z_class); + strcpy(instance_nm, notice->z_class_inst); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class_inst, instance_nm) + && !strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) + { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "cr")) { + strcpy(class_nm, notice->z_class); + strcpy(recip_nm, notice->z_recipient); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm) && + !strcasecmp(((ZNotice_t *)(tmp->notice))->z_recipient, recip_nm)) + { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "c")) { + strcpy(class_nm, notice->z_class); + do { + done = 1; + tmp = bottom_gram; + while (tmp) { + if (!strcasecmp(((ZNotice_t *)(tmp->notice))->z_class, class_nm)) { + fry = tmp; + tmp = tmp->above; + xdestroygram(x_dpy, fry->w, desc_context, fry); + done = 0; + } else { + tmp = tmp->above; + } + } + } while (!done); + } + else if (!strcmp(val, "all")) { + while (bottom_gram) { + xdestroygram(x_dpy, bottom_gram->w, desc_context, bottom_gram); + } + } + } +} +#endif +#endif /* X_DISPLAY_MISSING */ diff --git a/zwgc/zephyr.c b/zwgc/zephyr.c new file mode 100644 index 0000000..6acfe81 --- /dev/null +++ b/zwgc/zephyr.c @@ -0,0 +1,267 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + +#include + +#if (!defined(lint) && !defined(SABER)) +static const char rcsid_zephyr_c[] = "$Id$"; +#endif + +#include + +/****************************************************************************/ +/* */ +/* Module containing code dealing with zephyr: */ +/* */ +/****************************************************************************/ + +#include +#include +#include "new_string.h" +#include "zephyr.h" +#include "error.h" +#include "mux.h" +#include "subscriptions.h" +#include "variables.h" +#include "pointer.h" +#include "main.h" +#ifndef X_DISPLAY_MISSING +#include "X_driver.h" +#endif +#ifdef CMU_ZWGCPLUS +#include "plus.h" +#endif + +#ifdef DEBUG +extern int zwgc_debug; +#endif /* DEBUG */ + +static int zephyr_inited = 0; +static unsigned short zephyr_port = 0; + +/* + * Internal Routine: + * + * string get_zwgc_port_number_filename() + * Effects: Returns the filename that the zwgc port # is/should be + * stored in, based on the user's uid & the environment + * variable WGFILE. The returned string points into a + * static buffer that may change on further calls to this + * routine or getenv. The returned string should not be + * modified in any way. + */ + +static string +get_zwgc_port_number_filename(void) +{ + static char buffer[40]; + char *temp; + + temp = getenv("WGFILE"); + if (temp) + return(temp); + else { + sprintf(buffer, "/tmp/wg.%d", getuid()); + return(buffer); + } +} + +/* + * Write out the port number to the wg file. + */ + +void +write_wgfile(void) +{ + char *name = get_zwgc_port_number_filename(); + FILE *port_file; + + port_file = fopen(name, "w"); + if (port_file) { + fprintf(port_file, "%d\n", zephyr_port); + fclose(port_file); + } else { + fprintf(stderr, "zwgc: error while opening %s for writing: ", name); + perror(""); + } +} + +/* + * + */ + +struct notice_handler_ptr { + void (*notice_handler)(ZNotice_t *); +}; + +static void +handle_zephyr_input(struct notice_handler_ptr *nhp) +{ + ZNotice_t *notice; + struct sockaddr_in from; + int complete_packets_ready; + + for (;;) { + errno = 0; + if ( (complete_packets_ready=ZPending()) < 0 ) + FATAL_TRAP( errno, "while calling ZPending()" ); + + if (complete_packets_ready==0) + return; + + notice = malloc(sizeof(ZNotice_t)); + + TRAP( ZReceiveNotice(notice, &from), "while getting zephyr notice" ); + if (!error_code) { + notice->z_auth = ZCheckAuthentication(notice, &from); + nhp->notice_handler(notice); + } +#ifdef CMU_ZWGCPLUS + if (get_list_refcount(notice) <= 0) { + /* no windows created */ + if (!get_notice_fake(notice)) + list_del_notice(notice); + } +#endif + } +} + +/* + * + */ + +void zephyr_init(void (*notice_handler)(ZNotice_t *)) +{ + struct notice_handler_ptr *nhp; + char *temp; + char *exposure; + char *tty = NULL; + FILE *port_file; + + /* + * Initialize zephyr. If error, print error message & exit. + */ + nhp = malloc(sizeof(struct notice_handler_ptr)); + if (!nhp) { + fprintf(stderr, "Out of memory setting up zephyr notice handler.\n"); + exit(3); + } + FATAL_TRAP( ZInitialize(), "while initializing Zephyr" ); + FATAL_TRAP( ZOpenPort(&zephyr_port), "while opening Zephyr port" ); + + /* + * Save away our port number in a special place so that zctl and + * other clients can send us control messages: <<<>>> + */ + temp = get_zwgc_port_number_filename(); + port_file = fopen(temp, "r"); + if (port_file) { + fprintf(stderr, "zwgc: windowgram file already exists. If you are\n"); + fprintf(stderr, "zwgc: not already running zwgc, delete %s\n", temp); + fprintf(stderr, "zwgc: and try again.\n"); + exit(1); + } + write_wgfile(); + + /* Set hostname and tty for locations. If we support X, use the + * display string for the default tty name. */ + if (location_override) + tty = location_override; +#ifndef X_DISPLAY_MISSING + else if (x_dpy) + tty = DisplayString(x_dpy); +#endif + error_code = ZInitLocationInfo(NULL, tty); + TRAP( error_code, "while initializing location information" ); + + /* + * Retrieve the user's desired exposure level (from the zephyr variable + * "exposure"), convert it to the proper internal form then + * set the user's location using it. If the exposure level is + * not one of the allowed ones, print an error and treat it as + * EXPOSE_NONE. + */ + temp = ZGetVariable("exposure"); + if (temp) { + if (!(exposure = ZParseExposureLevel(temp))) { + ERROR2("invalid exposure level %s, using exposure level none instead.\n", temp); + exposure = EXPOSE_NONE; + } + } else + exposure = EXPOSE_OPSTAFF; + error_code = ZSetLocation(exposure); /* <<<>>> */ + if (error_code != ZERR_LOGINFAIL) + TRAP( error_code, "while setting location" ); + + /* + * If the exposure level isn't EXPOSE_NONE, turn on recieving notices. + * (this involves reading in the subscription file, etc.) + */ + if (string_Neq(exposure, EXPOSE_NONE)) + zwgc_startup(); + + /* + * Set $realm to our realm and $user to our zephyr username: + */ + var_set_variable("realm", (char *)ZGetRealm()); /* XXX should propagate the + * const */ + var_set_variable("user", ZGetSender()); + + /* + * <<<>>> + */ + nhp->notice_handler = notice_handler; + mux_add_input_source(ZGetFD(), (void (*)(void *))handle_zephyr_input, nhp); + zephyr_inited = 1; + return; +} + +/* + * + */ + +void finalize_zephyr(void) /* <<<>>> */ +{ + string temp; + + if (zephyr_inited) { + /* + * Remove the file containing our port # since it is no longer needed: + */ + errno = 0; + temp = get_zwgc_port_number_filename(); + unlink(temp); + if (errno) { + fprintf(stderr, "zwgc: error while trying to delete %s: ", temp); + perror(""); + } + + /* + * Cancel our subscriptions, unset our location, and close our zephyr + * connection: + */ +#ifdef DEBUG + if (zwgc_debug) { + TRAP( ZUnsetLocation(), "while unsetting location" ); + TRAP( ZCancelSubscriptions(0), "while canceling subscriptions" ); + } else { +#endif /* DEBUG */ + (void) ZUnsetLocation(); + (void) ZCancelSubscriptions(0); +#ifdef DEBUG + } +#endif /* DEBUG */ + ZClosePort(); + } + return; +} diff --git a/zwgc/zephyr.h b/zwgc/zephyr.h new file mode 100644 index 0000000..1e714a3 --- /dev/null +++ b/zwgc/zephyr.h @@ -0,0 +1,26 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifndef zephyr_MODULE +#define zephyr_MODULE + +#include + +extern void zephyr_init(void(*)(ZNotice_t *)); +extern void finalize_zephyr(void); +extern void write_wgfile(void); + +#endif diff --git a/zwgc/zwgc.1.in b/zwgc/zwgc.1.in new file mode 100644 index 0000000..88a7ba4 --- /dev/null +++ b/zwgc/zwgc.1.in @@ -0,0 +1,1067 @@ +.\" $Id$ +.\" # end of TP (cf }N below) +.\" # copied here, since we use @ in some of our tags, and that +.\" # messes up \w and \h +.de }1 +.ds ]X \&\\*(]B\\ +.nr )E 0 +.if !"\\$1"" .nr )I \\$1n +.}f +.ll \\n(LLu +.in \\n()Ru+\\n(INu+\\n()Iu +.ti \\n(INu +.ie !\\n()Iu+\\n()Ru-\w'\\*(]X'u-3p \{\\*(]X +.br\} +.el \\*(]X\h@|\\n()Iu+\\n()Ru@\c +.}f +.. +.de }N +.if \\n()E .br +.di +.if "\\n()E"0" .}f +.if "\\n()E"1" .}1 +.if "\\n()E"2" .}2 +.nr )E 0 +.. +.\" # tagged paragraph (paragraph with hanging label, but no para spacing) +.de TQ +.if !"\\$1"" .nr )I \\$1n +.ne 1.1v +.in \\n()Ru +.nr )E 1 +.ns +.it 1 }N +.di ]B +.. +.TH ZWGC 1 "November 30, 1989" "MIT Project Athena" +.SH NAME +zwgc \- Zephyr Windowgram Client program +.SH SYNOPSIS +.B zwgc +[ \-reenter ] [ \-nofork ] [ \-ttymode ] [ \-f +.I filename +] [ \-subfile +.I filename +] [ \-loc +.I text +] [ \-default +.I portname +] [ \-disable +.I portname +] ... [ output driver options ] +[ X Toolkit options... ] +.SH DESCRIPTION +.I Zwgc +is the main +.I zephyr(1) +client. It is responsible for receiving selected zephyr notices on +behalf of the user, formatting them, and displaying them using +one or more of the output devices. + +.SS "Selection of Zephyr Notices" +.PP +.I Zwgc +subscribes to various notice classes and instances on behalf of the +user. Only notices in the subscription list will be received. The +subscription list is composed of the default subscriptions (stored on +the server), the user's subscriptions file, and any subscriptions made +using +.IR zctl (1). +The user's subscription file defaults to +.IR $HOME/.zephyr.subs , +or it can be specified with the \-subfile +option. If "\-" is specified as the subscription filename, the +subscriptions will be read from standard input. + +.PP +The +.I zctl +command is used to manipulate and change subscriptions. See the +.IR zctl (1) +man page for details. + +.SS "Zephyr Description Files" +.PP +.I Zwgc +formats its output messages according to the commands in its +description file. The user's description file +.RI ( $HOME/.zwgc.desc +by default, or whatever is specified by \-f) is read, or the system file +is read if the user's does not exist. +.PP +Every time a notice is received, +.I zwgc +runs through the description file, and executes the appropriate commands. + +.SS "Zephyr Description File Syntax" +.PP +A description file is simply a list of commands. Whitespace (spaces, +tabs, and line breaks) is used +to separate tokens. The type and amount of whitespace separating tokens +is irrelevant. +Comments can be delimited by # and newline (for line-oriented comments, +e.g. "# this is a comment" on a line by itself) or by /* and */ (e.g. "/* +this is a comment */"). + +.SH "DESCRIPTION LANGUAGE" +.SS Expressions +Expressions are used by certain commands. +They are composed from string literals, variable references, +function calls, and operators. Parentheses can be used anywhere in an +expression to group expressions or increase readability. +.PP +String literals are specified by putting the contents in "double quotes". +.PP +Variables are set using the +.B set +command (see "COMMANDS", below). They are +referenced in an expression by using the form +.IR $varname . +Some variables are set by default for each notice. +All other variables retain their values between notice interpretations, +so that if you set a variable, it retains that value until later +modified. +.PP +Functions are called using a C-like syntax, +\fBfname\fR(\fIexpr1\fR,\fIexpr2\fR), where +.B fname +is the +function name and +.IB expr n +are the arguments. +.PP +Binary operators use infix notation, such as "a == b". +.PP +Some commands use an expression list (exprlist), which is simply a set +of expressions separated by whitespace (e.g. $var1 "lit1" $var2). + +.SS "Default variables" +.PP +The following variables are always available: +.TP 5 +.B 1, ... +Numeric variables are assigned values corresponding to that field in the +notice (the body of each notice is conceptually an array of fields, each +terminated with a null character). If the number is greater than the +number of fields actually in the notice, the value is "". For example, +the standard zwrite messages have two fields: $1 is the signature, and +$2 is the text of the message. +.TP 5 +.B auth +An indication of the authenticity of the notice. ``yes'' means the +notice is authentic, ``no'' means it is not, and ``forged'' means that +the message claimed to be authentic but the verification of the claim +failed. The ``forged'' indication usually appears when a user has +changed his Kerberos tickets with +.IR kinit (1) +but has not run ``zctl sub'' to +register this change with the Zephyr servers. +.TP +.B class +The class of the current notice. +.TP +.B date +The date on which the notice was sent. +.TP +.B default +The default output format for the current notice +.TP +.B error +An error message from the port read/write commands. +.TP +.B fromhost +The full name of the host from which the notice appears to have been +sent. +.I This is not fully reliable, +as the information used to determine this hostname is not guaranteed to +be correct (even for authentic messages). +.TP +.B fullsender +The notice sender's name, including the zephyr realm name. +.TP +.B instance +The instance of the current notice. +.TP +.B kind +The kind of notice. +.TP +.B message +The full text of the message, with nulls converted to newlines. +.TP +.B number_of_fields +The number of fields in the message (a string representation of a +decimal number). +.TP +.B opcode +The opcode of the current notice. +.TP +.B output_driver +The name of the output driver in use. +.TP +.B port +The port from which the notice was sent. +.TP +.B realm +The local zephyr realm. +.TP +.B recipient +The recipient for the current notice. If the notice is a multicast +(sent to several people), the recipient is set to ``*''. +.TP +.B sender +Usually a shortened version of fullsender. If the realm of the sender +is equal to the realm of the recipient, +.I sender +omits the realm name. +.TP +.B time +The time of day at which the notice was sent. +.TP +.B user +The full zephyr name of the user (e.g. marc@ATHENA.MIT.EDU). +.TP +.B version +The current version of +.IR zwgc . +.TP +.B zephyr_version +The protocol version of the notice. +.PP +All of these variables (except for error, output_driver, and version) +are re-set before each notice is processed. + +.SS Functions +.PP +Following is a list of functions available for use in the description +file. +.TP 5 +.BI buffer () +The contents of the current output buffer. +.TP +.BI downcase (expr) +Returns the value of \fIexpr\fR, converted to lower case. +.TP +.BI get (expr) +Returns a line from the port named \fIexpr\fR. If there is no text +waiting on the port (e.g. the program connected to the port has not +printed any output), this function will wait until it can read a line of +text from the port. +.TP +.BI getenv (expr) +Returns the value of the environment variable \fIexpr\fR, or the empty +string if it does not exist. + +.TP +.BI lany "(expr1, expr2), " rany "(expr1, expr2)" +Return a number of characters equal to the length of +.I expr2 +from the beginning +.RB ( lany ) +or end +.RB ( rany ) +of +.I expr1 +(e.g. lany("1234567890","foo") would return "123"). +If +.I expr1 +is a variable reference, the variable +is modified to remove the characters returned. +If +.I expr2 +is longer than +.IR expr1 , +the value of +.I expr1 +is returned (and +.I expr1 +is set to "", if a variable). +.TP +.BI lbreak "(expr1, expr2), " rbreak "(expr1, expr2)" +.I Expr2 +defines a set of characters. The function returns the longest +initial +.RB ( lbreak ) +or final +.RB ( rbreak ) +string from +.I expr1 +composed of characters +.I not +in this set (e.g. lbreak("characters", "tuv") would return "charac"). If +.I expr1 +is a variable reference, the variable +is modified to remove the characters returned. If no characters +in +.IR expr2 " are in " "expr1, " then " expr1 " +is returned (and +.I expr1 +is set to "", if a variable). +.TP +.BI lspan "(expr1, expr2), " rspan "(expr1, expr2)" +These functions are the negation of the +.B break +functions; the returned string consists of characters +.I in +the set defined by +.I expr2 +.TP +.BI protect (expr) +Returns a string which will be evaluated identically to \fIexpr\fR, +but will not affect any surrounding environments. That is, any +characters which could close outside environments are quoted, and any +environments in \fIexpr\fR which are not closed at the end are closed. +.TP +.BI substitute (expr) +Evaluates variable references of the form \fI$variable\fR in expr and +converts $$ to $. +.TP +.BI upcase (expr) +Returns the value of \fIexpr\fR, converted to upper case. +.TP +.BI verbatim (expr) +Returns a string that will be displayed exactly as \fIexpr\fR looks. +Anything which could be mistaken for an environment is quoted. +.TP +.BI stylestrip (expr) +Returns \fIexpr\fR with all environments stripped out. +.TP +.BI zvar (expr) +Returns the value of the zephyr variable \fIexpr\fR, +or the empty +string if it does not exist. [Zephyr variables +can be set and examined with +.IR zctl (1).] + +.SS Operators +.PP +Following is a list of operators which can be used in the description +file to compose expressions: +.TP +.IB expr1 " + " expr2 +String concatenation of +.IR expr1 " and " expr2 +.TP +.IB expr1 " == " expr2 +True if the two expressions are equal, false otherwise. +.TP +.IB expr1 " =~ " expr2 +True if the regular expression pattern +.IR expr2 " matches " expr1. +.TP +.IB expr1 " !~ " expr2 +Negation of "=~". +.TP +.IB expr1 " != " expr2 +Negation of "==" +.TP +\fIexpr1\fB and \fIexpr2\fR, \fIexpr1\fB & \fIexpr2\fR +True if +.IR expr1 " and " expr2 +are both true. +.TP +\fIexpr1\fB or \fIexpr2\fR, \fIexpr1\fB | \fIexpr2\fR +True if either of +.IR expr1 " or " expr2 +are true. +.TP +\fB! \fIexpr1\fR, \fBnot \fIexpr1\fR +The logical negation of +.I expr1. + +.SS Commands +.PP +Following is a list of the commands usable in the description +language: +.TP 5 +.BI appendport " expr1 expr2" +Creates a port called \fIexpr1\fR. All output to the port will be +appended to the file \fIexpr2\fR. There is no input. If the file is +created, its mode is set to read-write, owner only (no access for others). +.TP +.B break +Exits the innermost if, case, or while block. +.TP +\fBcase \fIexpr1\fR [ ((\fBmatch \fIexpr\fR [,\fIexpr ...\fR]) | \fBdefault\fR)\fI commands \fR] ... \fBendcase\fR +Evaluates \fIexpr1\fR. Then, each of the match expressions is +evaluated in order. The first time an expression matches \fIexpr1\fR, +then the body of commands under it is executed, and the rest of the case +statement is skipped. This compare is case-insensitive. default always +matches, so it should always appear as the last set of commands. See +the default description file for an example of use. +.TP +.B clearbuf +Clears the output buffer (see below for details on buffering). +.TP +.BI closeinput " expr" +Closes the file associated with \fIexpr\fR. +.TP +.BI closeoutput " expr" +Sends an EOF (end-of-file) to the process if \fIexpr\fR was a port created by +execport, or closes the file if it was created by outputport or +appendport. +.TP +.BI closeport " expr" +Closes both input and output of \fIexpr\fR as defined above. +.TP +.BI fields " variable1 ..." +sets the list of variables to be equal to the fields in the +notice. If there are more variables than fields, the extra +variables are left empty. +.TP +.BI exec " exprlist" +Executes a program without any input or output. A command named by +\fIexprlist\fR is executed. Each expression is used as an argument to +the program; the first expression names the program (it may be either an +absolute pathname, or a program name; the user's PATH is searched to +find simple program names). +.TP +.BI execport " expr1 exprlist" +Creates a port called \fIexpr1\fR. A command named by \fIexprlist\fR +is executed, as described above for \fBexec\fR. +All output to the port is sent to the standard input +of the process. Reading from the port will return the standard output +of the process. +.TP +.B exit +Completes processing of the current notice. The remainder of the +description file is ignored after execution of this command. +.\" hack because the following line otherwise breaks because it is too long. +.TP +\fBif \fIexpr1 \fBthen \fIcommands1\fR [\fBelseif \fIexpr2 \fBthen \fIcommands2\fR] ... [\fBelse \fIcommandsn\fR] \fBendif\fR +If \fIexpr1\fR evaluates to true, execute \fIcommands1\fI, etc. [A conditional +construct, similar to the constructs in the C shell (csh).] +.TP +.BI inputport " expr1 expr2" +Creates a port called \fIexpr1\fR. All input from the port comes from +the file \fIexpr2\fR. There is no output. +.TP +.B noop +does nothing +.TP +.BI outputport " expr1 expr2" +Creates a port called \fIexpr1\fR. The file \fIexpr2\fR will be +truncated, or created if it does not exist. All output to the port +will be appended to the file \fIexpr2\fR. There is no input. If the file is +created, its mode is set to read-write, owner only (no access for others). +.TP +.BI print " expr1 ..." +adds the values of the expressions to the current output buffer. The +values of the expressions are separated by spaces in the output. +.TP +.B put \fR[\fIexpr \fR[\fIexprlist\fR]] +Sends data to a port. If \fIexpr\fR is provided, then it is used as the +port, otherwise the port used is the +port corresponding to the default output device. +If \fIexprlist\fR is provided, the expressions in the list are sent to +the port, separated by spaces. If it is omitted, then the contents +of the output buffer are sent as the data. +.TP +.BI set " variable " = " expr" +sets +.I variable +equal to +.IR expr . +Variable can later be +referenced by +.IR $variable . +.TP +.BI show " text " endshow +Appends text to the output buffer. This command is special, because +the string does not need to be quoted. Whitespace at the beginning or +end of the lines of text is ignored. The \fIendshow\fR must appear as +the first token on a line (it may only be preceded on that line by whitespace). +Variable substitutions and formatting commands +(but not expressions or functions) are processed in the text. Example: +.nf +show + this is some text + from: $sender +endshow +.fi +.TP +.BI while " expr " do " statements " endwhile +Executes \fIstatements\fR until \fIexpr\fR is false. + +.SH PORTS +.PP +Ports are an abstraction encompassing all I/O forms of which +zwgc is capable. There are pre-existing output ports corresponding to each +of the output devices, and more ports can be created with the +port commands described above. + +.SH OUTPUT +The output is usually collected in the +.I "output buffer" +and saved until a +.I put +command sends the output to an output device (such as an X display or a +terminal). The output buffer is implicitly cleared after each notice is +completely processed. + +.PP +Output devices are implemented as output ports. A message is +displayed in a device-dependent manner when a string is output to the +port corresponding to the output device. Formatting commands are +embedded in the text as @ commands of the form @command(text). +Command names are case-insensitive and consist of alphanumeric +characters and underscores. Valid brackets are () [] {} and <>. +If the command name is empty (such as in +.RB `` @(foo) ''), +then a new +environment with no changes is created (This is useful to temporarily +change some parameter of the output, such as the font). +.PP +The following output devices are supported: +.TP 5 +stdout +Sends the string to standard output exactly as is. +.TP +stderr +Sends the string to standard error exactly as is. +.TP +plain +Sends the string with all formatting environments removed to standard +output. +.TP +tty +Does formatting on the message according to @ commands embedded in the +text. The output, +with appropriate mode-changing sequences, is sent to the standard output. +The appropriate characteristics of the display are taken from +the TERMCAP entry (see +.IR termcap (5)) +for the terminal named by the TERM environment variable. +Supported @ commands are: +.RS 10 +.TP 15 +@roman +Roman (plain) letters (turns off all special modes). +.TP +@b or @bold +Bold letters. If not available, reverse video, else underline. +.TP +@i or @italic +Italic letters (underlining, if available). +.TP +@beep +"bl" termcap entry, else "^G" (beep the terminal); limited to once per +message. +.TP +@l or @left +left aligned +.TP +@c or @center +center aligned +.TP +@r or @right +right aligned +.RE +.IP "" 5 +Other @-commands are silently ignored. +.TP 5 +X +Displays one window per string output to the port. The output is +formatted according to @ commands embedded in the string. Supported +@ commands are: +.RS 10 +.TP 15 +@roman +turns off @italic and @bold +.TP +@b or @bold +turns on boldface +.TP +@i or @italic +turns on italics +.TP +@l or @left +left aligned +.TP +@c or @center +center aligned +.TP +@r or @right +right aligned +.TP +@large +large type size +.TP +@medium +medium type size +.TP +@small +small type size +.TP +@beep +Ring the X bell (limited to once per message) +.TP +@font +sets the current font to the font specified in the contents of the +environment (e.g. @font(fixed)). This will remain in effect for the +rest of the environment (a temporary change can be achieved by enclosing the +font-change in an @(...) environment). If the named font is not +available, the font ``fixed'' is used instead. +.TP +@color +sets the color to the color specified in the contents of the +environment. The color name should appear in the X color name database. +This color will remain in effect for the rest of the environment. If +the named color is not available, the default foreground color is used. +.RE +.IP "" 5 +Any other environment name not corresponding to the above environment +names will set the current ``substyle.'' +.IP +The attributes of a given block of text are determined by any active +environments, evaluated in the context of the current style and +substyle. +.IP +The style is specific to each window. Its name has three dot +(``.'') separated fields, which are by default the values of the class, +instance, and recipient variables, with all dots changed to underscores +(``_'') and all letters converted to lowercase. The style can be +altered by setting the +.I style +variable. Note that it \fBmust always\fR have exactly two ``.'' +characters in it. +.IP +The substyle is determined by @ commands in the message text. +.IP +Zwgc variables which the X output device reads are: +.RS 10 +.TP 15 +default_X_geometry +default geometry for notices, set from resources +.TP +X_geometry +overrides geometry in resource file, if set +.TP +default_X_background +default background color for notices, set from resources +.TP +X_background +overrides bgcolor in resource file, if set +.TP +style +style, as described above +.RE +.IP "" 5 +The expected geometry values are described below. +.IP +The fonts and color for a piece of text are determined by the styles +defined in the X resources file. The following resources relating to +text style are used by zwgc: +.RS 10 +.TP 10 +zwgc.style.\fIstylenames\fR.geometry +geometry for messages of the specified style +.TP +zwgc.style.\fIstylenames\fR.background +background color for messages of the specified style +.TP +zwgc.style.\fIstylenames\fR.substyle.\fIsubstylename\fR.fontfamily +fontfamily name for the specified style and substyle +.TP +zwgc.style.\fIstylenames\fR.substyle.\fIsubstylename\fR.foreground +foreground color for the specified style and substyle +.TP +zwgc.fontfamily.\fIfontfamilyname\fR.\fIsize\fR.\fIface\fR +specifies the fonts for a given fontfamily. \fIsize\fR is one +of small, medium, or large, and \fIface\fR is one of roman, +bold, italic, or bolditalic. +.RE +.IP "" 5 +The best way to get started in customizing X resources for +.I zwgc +is to examine the default application resources and other users' +resources to understand how they specify the default appearance. + +.SH "X RESOURCES" +Other X resources used by +.I zwgc +are listed below. +Entries like +.sp +.nf +.in +5 +zwgc*option: value +Zwgc*option: value +zwgc.option: value +*option: value +\&.option: value +.in -5 +.fi +.sp +will work. +.PP +An entry labeled with zwgc*option in any of the sources takes precedence +over Zwgc*option, which takes precedence over *option entries. +The following sources are searched in order: +.nf +.in +5 +command-line arguments (\-xrm) +contents of file named by XENVIRONMENT environment variable +X server resource database (see \fIxrdb\fR(1)) +application resources file +.in -5 +.fi +.PP +Logical values can be ( Yes On True T ) or ( No Off False nil ). +.TP 15 +\fBOPTION:\fR +\fBMEANING [default]:\fR +.TP +cursorCode +number of a code from the cursorfont (should be an even integer, see +\fI\fR) to use for the windows. +.TP +foreground +Primary foreground color +.TP +Foreground +Secondary foreground color (if foreground not set) [BlackPixel is the default if neither is set] +.TP +background +Primary background color +.TP +Background +Secondary background color (if background not set) [WhitePixel is the +default if neither is set] +.TP +borderColor +Primary border color +.TP +BorderColor +Secondary border color (if borderColor not set) [BlackPixel is the +default if neither is set] +.TP +pointerColor +Primary mouse pointer color [foreground color is the default if not set] +.TP +reverseVideo +(logical) Toggles foreground and background (and border, if it matches +foreground or background). +.TP +ReverseVideo +Secondary toggle, if reverseVideo is not set. [off is the default if +neither is set] +.TP +borderWidth +Primary border width selector +.TP +BorderWidth +Secondary border width selector (if borderWidth is not set) [1 is the +default value if neither is set] +.TP +internalBorder +Primary border between edge and text +.TP +InternalBorder +Secondary selector (if internalBorder not set) [2 is the default value +if neither is set] +.TP +geometry +Primary POSITION (not size) geometry specifier. +The geometry should be of the form "{+|\-}x{+|\-}y", specifying an (x,y) +coordinate for a corner of the window displaying the notice. The +interpretation of positive and negative location specifications follows +the X conventions. A special location of `c' for either x or y +indicates that the window should be centered along that axis. Example: +a geometry of "+0+c" specifies the window should be at the top of the +screen, centered horizontally. +.TP +Geometry +Secondary position specifer. [+0+0 is the default if neither is set.] +.TP +resetSaver +(logical) Primary value to force screen to unsave when a message first +appears. +.TP +ResetSaver +(logical) Secondary value to force screen to unsave. [default True] +.TP +reverseStack +(logical) Primary value to specify that zwgc should attempt to stack +WindowGram windows such that the oldest messages +normally show on top. Some X window managers may silently ignore +.IR zwgc 's +attempts to restack its windows. This option can cause some unusual +interactions with other windows if the user manually restacks either the +other windows or the WindowGram windows. +.TP +ReverseStack +Secondary value to enable reverse stacking. [default False] +.TP +title +(string) Primary window title +.TP +Title +Secondary window title [defaults to the last pathname component +of the program name, usually "zwgc"] +.TP +transient +(logical) Primary value which determines if zephyrgram windows will be +created with the \fBWM_TRANSIENT_FOR\fR property set. If this +resource is true, the property will be set, telling certain +windowmanagers to treat zephyrgram windows specially. For instance, +\fItwm\fR will not put decorations on transient windows, \fImwm\fR +will not let you iconify them, and \fIuwm\fR ignores the resource +entirely. +.TP +Transient +Secondary transient determining value [default False] +.TP +allDesktops +(logical) Primary value which determines if zephyrgram windows should +appear on all desktops, for those window managers which support multiple +desktops (sometimes referred to as workspaces). When this resource is +true (the default), +.I zwgc +sets the \fB_NET_WM_DESKTOP\fR property to 0xFFFFFFFF for each zephyrgram +window, indicating that it should appear on all desktops. +.TP +AllDesktops +Secondary value determining whether zephyrgram windows should appear +on all desktops. +.TP +scrollDelete +(logical) If true, scrolling over a zgram will cause it +to be deleted +.TP +ScrollDelete +Secondary value to enable deletion of a zgram by scrolling over it +[default False] +.TP +enableDelete +(logical) If true, zwgc creates a WM_PROTOCOLS property on all zgrams, with +WM_DELETE_WINDOW as contents. +.TP +EnableDelete +Secondary value to enable WM_DELETE_WINDOW protocol on zgrams [default False] +.TP +minTimeToLive +Primary value which specifies the minimum amount of time (``minimum time to +live'') a WindowGram must be on-screen (in milliseconds) until it can +be destroyed. This feature is useful to avoid accidentally clicking +on new WindowGrams when trying to delete old ones. +.TP +MinTimeToLive +Secondary value of ``minimum time to live.'' +.TP +iconName +(string) Primary icon name +.TP +IconName +Secondary icon name [defaults to the last pathname component +of the program name, usually "zwgc"] +.TP +name +(string) Primary window class name +.TP +name +Secondary window class name [defaults to the last pathname component +of the program name, usually "zwgc"] +.TP +synchronous +(logical) Primary X synchronous mode specifier. On means to put the X +library into synchronous mode. +.TP +Synchronous +Secondary X synchronous mode specifier. [default is `off'] +.PP +The window class is always "Zwgc". +.SH X BUTTONS +.PP +Clicking and releasing any button without the shift key depressed while +the pointer remains inside a WindowGram window will cause it to +disappear. If the pointer leaves the window +while the button is depressed, the window does not disappear; this +provides a way to avoid accidentally losing messages. +.PP +If the control button is held down while clicking on a WindowGram, +then that WindowGram and all windowgrams under the point where the +button is released will be erased. +.PP +.B WARNING: +If you do this with too many WindowGrams under the mouse, it is +possible for your subscriptions to be lost. If \fIzctl retrieve\fR +returns nothing, then issue a \fIzctl load\fR command to re-subscribe +to your default set of subscriptions. If you use znol, then \fIznol +\-q &\fR will restore the subscriptions you need for \fIznol\fR. +.PP +Portions of the text of a message may be selected for "pasting" into other X +applications by using the shift key in cooperation with the pointer +buttons. +Holding the Shift key while depressing Button1 (usually the left button) +will set a marker at the +text under the pointer. Dragging the pointer with Shift-Button1 still +depressed extends the selection from the start point, until the button +is released. The end of the selection may also be +indicated by releasing Button1, holding down the Shift key, and pressing +Button3 (usually the right button) at the desired endpoint of the selection. +The selection will appear with the text and background colors reversed. + +.SH ADDITIONAL X FEATURES +If +.I zwgc +receives a WM_DELETE_WINDOW, it destroys the zephyrgram as if it were +clicked on. +.PP +If a zephyrgram is unmapped, it is removed from the stacking order +used by reverseStack. + +.SH COMMAND LINE +.I zwgc +is normally invoked from +.IR $HOME/.xsession +in the foreground. When it has successfully set your location and +obtained subscriptions, it will put itself into the background (unless +the \-nofork option has been specified). At this point it is safe to +invoke additional zephyr commands, such as +.IR znol (1). +(You can also put these commands in the +.I initprogs +Zephyr variable; the value of this variable is passed as the argument to +the +.IR system (3) +library call during initialization.) +.I zwgc +will exit with an exit +status of 0 if it was able to open the X display successfully or 1 if it +couldn't open the display and the Zephyr variable +.I fallback +was set to ``false''. If +.I fallback +is set to ``true'', +.I zwgc +will fall back to ``ttymode'' (making the tty driver the default output +device) if it can't open the X display. If +.I fallback +is not set and the display cannot be opened, +.I zwgc +prints an explanatory message and exits with a status of 1. +.PP +If the +.I \-ttymode +option is specified, +.I zwgc +will ignore any X display and use the terminal as its primary output +device. This flag overrides any setting of the fallback variable. +.PP +If the +.I \-loc +option is specified, +.I zwgc +will use the specified string as the tty field for the location it +sets. This allows users to potentially specify more useful auxiliary +information than their ttys or display names. +.PP +The +.I \-reenter +option is provided for compatibility with the previous version of +.IR zwgc . +.PP +.I zwgc +will exit cleanly (unset location and cancel subscriptions) on: +.nf + SIGTERM + SIGHUP + XIOError (with a message to stderr) +.fi +SIGHUP is what it expects to get upon logout. Also, the signals +SIGINT, SIGQUIT, and SIGTSTP are ignored because they can be sent +inadvertently, and bizarre side-effects can result. If you want them +to be acted on, then run +.I zwgc -nofork & +.PP +If +.I zwgc +receives a SIGUSR1, it will rewrite the file used to store the +WindowGram port number ($WGFILE or /tmp/wg.\fIuid\fR), in the event +that the file has been lost. +.SH CONTROL MESSAGES +In order to allow some special user controls over the behavior of +.IR zwgc , +certain Zephyr control notices can be sent directly to +.I zwgc +using the +.IR zctl (1) +program. Currently implemented controls are +.TP 15 +wg_read +tell +.I zwgc +to re-read the current description file. +.TP +wg_shutdown +tell +.I zwgc +to cancel all subscriptions and stop acting on incoming notices. +.I zwgc +saves the subscriptions that were in effect at the time of the shutdown +so that it can restore them later if needed. +.TP +wg_startup +tell +.I zwgc +to restart from being shutdown and reinstall the saved subscriptions. +.PP +Other control messages may be implemented in the future. + +.SH EXAMPLES +For an example of a description file, see +.IR @datadir@/zephyr/zwgc.desc . +For an example of X resources, see +.IR @datadir@/zephyr/zwgc_resources . + +.SH BUGS +The X selection code can highlight the wrong portions of messages +containing formatted text placed with the @center() or @right() +directives. +.PP +If you are using Kerberos support and get new tickets (using +``kinit''), you must send a subscription notice to the server (using a +command such as ``zctl load /dev/null'') or all received Zephyr +notices will appear to be unauthentic. (If all received Zephyr +notices appear to be forged, your tickets have probably expired, in +which case you must get new tickets and then run ``zctl load +/dev/null''.) +.SH FILES +.TP 15 +$HOME/.zwgc.desc +Default location of user's description file +.TP +@datadir@/zephyr/zwgc.desc +System-wide description file +.TP +@datadir@/zephyr/zwgc_resources +Default X application resources. +.TP +$ZEPHYR_VARS or $HOME/.zephyr.vars +File containing variable definitions +.TP +$HOME/.zephyr.subs +Supplementary subscription file +.TP +$HOME/.Xresources +Standard X resources file +.TP +$WGFILE or /tmp/wg.\fIuid\fR +File used to store WindowGram port number for other clients +.SH SEE ALSO +csh(1), kinit(1), xrdb(1), zctl(1), zephyr(1), znol(1), X(1), getenv(3), +system(3), termcap(5), zephyrd(8), zhm(8) +.br +Project Athena Technical Plan Section E.4.1, `Zephyr Notification Service' +.SH AUTHORS +.nf +John Carr (MIT/Project Athena) +Marc Horowitz (MIT/Project Athena) +Mark Lillibridge (MIT/Project Athena) +.fi +.SH RESTRICTIONS +Copyright (c) 1989 by the Massachusetts Institute of Technology. +All Rights Reserved. +.br +.I zephyr(1) +specifies the terms and conditions for redistribution. diff --git a/zwgc/zwgc.desc b/zwgc/zwgc.desc new file mode 100644 index 0000000..48c7fe3 --- /dev/null +++ b/zwgc/zwgc.desc @@ -0,0 +1,136 @@ +# Copyright 1989, 1990 Massachusetts Institute of Technology +# +# For copying and distribution information, see the file +# "mit-copyright.h". +# +# $Id$ +# +# +# Default WindowGram description file +# + +# Opcode "ping" is used by sender programs to see if the message would +# really get sent, or if the recipient has logged out. No useful +# information is normally contained in these messages, so we discard them. +if (upcase($opcode) == "PING") then exit endif + +# +# AUTHENTICATION information +# +# $auth can be either Yes, No, or Forged +# +# "Yes" means that the sender field present in the notice was verified by +# Kerberos authentication +# +# "No" means that either the sender did not include any authentication +# information, or the authentication information was not verified by the +# Zephyr Server before the notice was sent to you. +# +# "Forged" means that the Server claims that the sender of the notice +# was verified by Kerberos authentication, but your WindowGram client +# could not verify this. This stage of verification is done by a cryptographic +# checksum. The most probable cause of the failure of the checksum +# provided by the Server to match the checksum generated by your +# WindowGram client is that you changed Kerberos tickets, and the Server +# was using an old value to compute the cryptographic checksum. You can +# update the Server's value by typing 'zctl load' to your prompt. +# +# By default, notices which appear forged are labeled as 'UNAUTHENTIC' +# to avoid confusion as to what 'Forged' really means. +# To change this display, change the last word in the line following +# 'match "forged" to something other than "UNAUTHENTIC". +case $auth +match "yes" + set aval = "Authentic" +match "no","forged" + set aval = "@b(@large(UNAUTHENTIC))" +endcase + +case $class +match "WG_CTL_CLASS" + exit +match "message" + if (downcase($recipient) == downcase($user)) then + case $instance + match "PERSONAL" + set type = "Personal" + match "URGENT" + set type = "Urgent" + default + set type = $instance + endcase + else + set type = "Instance "+$instance + endif + + if ($number_of_fields == "1") then + fields body + set signature = "" + else + fields signature body + endif + if ($signature =~ "^[Ff]rom: .*") then + set dummy = lany($signature,"From: ") + endif + if ($signature =~ "\n$") then + set dummy = rany($signature,"\n") + endif + if ($signature == "") then + set ftext = "From: @bold("+protect($sender)+")" + else + set ftext = "From: @bold(@{"+protect($signature)+"} <"+ + protect($sender)+">)" + endif + + print "@center(@bold("+$aval+") "+$type+" message at "+$time+ + " on "+$date+"\n"+$ftext+" on "+$fromhost+"\nTo: "+ + $recipient+")\n\n" + print $body + put + exit + +match "login" + case $opcode + match "USER_LOGIN" + set log = "logged in" + match "USER_LOGOUT" + set log = "logged out" + default + set log = "unknown opcode" + endcase + + fields host when tty + print "@center(@bold("+$sender+") "+$log+")\n" + print "@center(on @bold("+$host+") on "+$tty+")\n" + print "@center(at "+$when+")" + put + exit + +default + if (downcase($class) == "filsys" and downcase($opcode) == "shutdown") then + set format = "From $sender:\n@bold(Shutdown message from $1 at $time)\n"+ + "@center(System going down, message is:)\n\n$2\n\n@center(@bold($3))" + elseif (downcase($class) == "filsys") then + set format = "@bold(Filesystem Operation Message for $instance:)\n"+ + "From: @bold($sender) at $time $date\n$message" + elseif (downcase($class) == "mail" and downcase($instance) == "popret") then + set format = "You have new mail:\n\nFrom: $1\nTo: $2\nSubject: $3" + elseif (downcase($class) == "mail") then + set format = "From Post Office $1:\n$2" + elseif (downcase($class) == "syslog") then + set format = "From $sender:\nSyslog message from $instance, level "+ + "$opcode:\n$message" + elseif ($number_of_fields == "1") then + set format = "Class $class, Instance $instance:\nTo: @bold($recipient) "+ + "at $time $date\nFrom: @bold($sender)\n\n$message" + else + set format = "Class $class, Instance $instance:\nTo: @bold($recipient) "+ + "at $time $date\nFrom: @bold($1) <$sender>\n\n$2" + endif + + print "(Authentication: @bold("+$aval+") from host: "+$fromhost+")\n" + print substitute($format) + put + exit + +endcase diff --git a/zwgc/zwgc.el b/zwgc/zwgc.el new file mode 100644 index 0000000..0b7acf2 --- /dev/null +++ b/zwgc/zwgc.el @@ -0,0 +1,184 @@ +; zwgc.el +; +; This file is part of the Project Athena Zephyr Notification System. +; Created by: Mark W. Eichin +; $Id$ +; Copyright (c) 1988 by the Massachusetts Institute of Technology. +; For copying and distribution information, see the file +; "mit-copyright.h". +; +; Emacs mode for running zwgc in a sub process of emacs. It pops up a +; window for every new message; if you make bells appear between each +; message, it will be able to seperate them. If you move the mouse +; into the message window and hit `delete' it will delete the current +; message; if there are other messages, it will show them, if not, it +; will make the window go away. +; +; Invoke with M-x zwgc. +; +; Also included is M-x zsend, which prompts for a user name and a +; message to send to them. If the message is blank, a buffer is popped +; up to edit the message in. If a prefix argument is given, zsend +; prompts for an instance instead. If the user name is blank, the last +; one is reused. +; +; The following should be added to your .zephyr.desc file if you want +; to take advantage of the zwgc message seperation features: +; does $mode +; match tty +; beep +; endmatch +; enddoes +; +(defvar zwgc_el-RCS-id) +(setq zwgc_el-RCS-id "$Id$") +; +; + +(defun narrow-to-string (str) + "narrow and put up a string..." + (interactive "sString: ") + (narrow-to-region (point) (point)) + (insert str)) + +(defvar zwgc-prog "/usr/etc/zwgc" + "*Program to run as the zwgc process. Should set it for the machine type.") + +(defun zwgc-wakeup (proc string) + "Procedure called when zwgc spits something out" + (let (start-limit) + (save-excursion (set-buffer (get-buffer "*zwgc*")) + (setq start-limit (point)) + (goto-char (point-max)) + (if (= 7 (string-to-char string)) + (progn + (ding 1) + (message "got one!") + (narrow-to-string string)) + (insert string)) + (search-backward "\007" start-limit t) + (while (search-forward "\015" (point-max) t) ;flush ^M's + (delete-backward-char 1))) + (Special-pop-up-window (get-buffer "*zwgc*")) + )) + +(defun zwgc () + "emacs mode for running zwgc in a sub process of emacs. It pops up a +window for every new message; if you make bells appear between each +message, it will be able to seperate them. If you move the mouse into +the message window and hit `delete' it will delete the current +message; if there are other messages, it will show them, if not, it +will make the window go away." + (interactive) + (require 'shell) + (let ((buffer (get-buffer-create "*zwgc*")) proc status) + (setq proc (get-buffer-process buffer)) + (if proc + (setq status (process-status proc))) + (save-excursion + (set-buffer buffer) + (if (memq status '(run stop)) + nil + (if proc (delete-process proc)) + (setq proc (start-process "Zwgc" buffer + zwgc-prog "-disable" "X" + "-default" "plain" "-nofork")) + (set-process-filter proc 'zwgc-wakeup)) + (shell-mode) + (local-set-key "\177" 'zwgc-punt) + ) + )) + + +(defun Special-pop-up-window (buffer &optional max-height) + "Pop up a window that is just big enough to hold the current buffer." + (interactive "bBuffer to pop: ") + (let* ((retwin (selected-window)) + (pop-up-windows t) + (window-min-height 1)) + (pop-to-buffer buffer) + (setq lines (1+ (count-lines (point-min) (point-max)))) + (enlarge-window (- lines (window-height (selected-window)))) + (goto-char (point-min)) + (other-window 1) + )) + +(defun zwgc-punt () + "Delete the current ZephyrGram from the *zwgc* buffer." + (interactive) + (let ((window-min-height 1)) + (display-buffer (get-buffer "*zwgc*")) + (delete-region (point-min) (point-max)) + (widen) + (if (not (search-backward "\007" nil t)) + (delete-windows-on "*zwgc*") + (narrow-to-region (point) (point-max)) + (enlarge-window (- (1+ (count-lines (point-min) (point-max))) + (window-height (selected-window)))) + (goto-char (point-min)) + ))) +;; +;; [eichin:19880309.2005EST] +;; zsend.el +;; Send zephyrgrams from emacs... +;; + +(defvar *who* "" "last user sent to with zsend") + +(defun zsend (&optional who message) + "zsend prompts for a user name and a message to send to them as a +ZephyrGram. If the message is blank, a buffer is popped up to edit the +message in. If a prefix argument is given, zsend prompts for an +instance instead. If the user name is blank, the last one is reused." + (interactive + (list (if current-prefix-arg ; is this portable??? + (cons 'instance (read-input "Instance:")) + (cons 'who (read-input "Who:"))) +; (select-window (minibuffer-window)) +; (enlarge-window 4) + (read-input "Message:"))) + (save-excursion + (let ((tempbuf (get-buffer-create " *zephyr*send*"))) + (switch-to-buffer tempbuf) + (local-set-key "\C-c\C-c" 'exit-recursive-edit) + (erase-buffer) + (if (and (equal (cdr who) "") + (equal *who* "")) + (message "Please specify user at least once.") + (if (not (equal (cdr who) "")) + (setq *who* who) ; save *who* for next time + (setq who *who*)) ; or, use the old value + (if (not (equal message "")) + (progn + (insert message) + (zwrite who)) + (progn + (recursive-edit) + (zwrite who))))))) + + +(defun zwrite (who) + "Send a ZephyrGram to user WHO, zsend is the user interface to this." + (if (eq 'who (car who)) + (call-process-region (point-min) (point-max) ;range + "/usr/athena/zwrite" ;process + t ;delete-p + t ;output-p + nil ;redisplay-p + "-q" ;args -- ignore server responses. + (cdr who)) + (call-process-region (point-min) (point-max) ;range + "/usr/athena/zwrite" ;process + t ;delete-p + t ;output-p + nil ;redisplay-p + "-q" ;args -- ignore server responses. + "-i" ;[eichin:19880312.0015EST] + (cdr who))) + (if (not (equal (point-max) 1)) + (message (buffer-substring 1 (1- (point-max)))))) + +; suggested binding (control-meta-z) +;(global-set-key "\M-\C-z" 'zsend) + + diff --git a/zwgc/zwgc.h b/zwgc/zwgc.h new file mode 100644 index 0000000..6164bf2 --- /dev/null +++ b/zwgc/zwgc.h @@ -0,0 +1,28 @@ +/* This file is part of the Project Athena Zephyr Notification System. + * It is one of the source files comprising zwgc, the Zephyr WindowGram + * client. + * + * Created by: Marc Horowitz + * + * $Id$ + * + * Copyright (c) 1989 by the Massachusetts Institute of Technology. + * For copying and distribution information, see the file + * "mit-copyright.h". + */ + + +#include + +#ifdef DEBUG + +extern int zwgc_debug; +#define dprintf(x) if (zwgc_debug) printf(x) +#define dprintf1(x,y) if (zwgc_debug) printf(x,y) + +#else + +#define dprintf(x) +#define dprintf1(x,y) + +#endif diff --git a/zwgc/zwgc_resources b/zwgc/zwgc_resources new file mode 100644 index 0000000..668fca5 --- /dev/null +++ b/zwgc/zwgc_resources @@ -0,0 +1,102 @@ +! Copyright 1989 Massachusetts Institute of Technology +! +! For copying and distribution information, see the file +! "mit-copyright.h". +! +! $Id$ +! +! +! Zwgc application specific global resources: +! + +*style*substyle.default.fontfamily: default +*style.message.personal*substyle.title.fontfamily: huge + +*style*geometry: +0+0 + +! +! The following is the adobe-courier font family. Availiable sizes are +! 80, 100, 120, 140, 180, and 240. This family used to be courier. +! + +*fontfamily.default.small.roman: *-courier-medium-r-*-80-*-m-*,* +*fontfamily.default.small.bold: *-courier-bold-r-*-80-*-m-*,* +*fontfamily.default.small.italic: *-courier-medium-o-*-80-*-m-*,* +*fontfamily.default.small.bolditalic: *-courier-bold-o-*-80-*-m-*,* + +*fontfamily.default.medium.roman: *-courier-medium-r-*-120-*-m-*,* +*fontfamily.default.medium.bold: *-courier-bold-r-*-120-*-m-*,* +*fontfamily.default.medium.italic: *-courier-medium-o-*-120-*-m-*,* +*fontfamily.default.medium.bolditalic: *-courier-bold-o-*-120-*-m-*,* + +*fontfamily.default.large.roman: *-courier-medium-r-*-240-*-m-*,* +*fontfamily.default.large.bold: *-courier-bold-r-*-240-*-m-*,* +*fontfamily.default.large.italic: *-courier-medium-o-*-240-*-m-*,* +*fontfamily.default.large.bolditalic: *-courier-bold-o-*-240-*-m-*,* + +! +! The following is the adobe-courier font family. Availiable sizes are +! 80, 100, 120, 140, 180, and 240. This family used to be courier. +! + +*fontfamily.courier.small.roman: *-courier-medium-r-*-80-*-m-*,* +*fontfamily.courier.small.bold: *-courier-bold-r-*-80-*-m-*,* +*fontfamily.courier.small.italic: *-courier-medium-o-*-80-*-m-*,* +*fontfamily.courier.small.bolditalic: *-courier-bold-o-*-80-*-m-*,* + +*fontfamily.courier.medium.roman: *-courier-medium-r-*-120-*-m-*,* +*fontfamily.courier.medium.bold: *-courier-bold-r-*-120-*-m-*,* +*fontfamily.courier.medium.italic: *-courier-medium-o-*-120-*-m-*,* +*fontfamily.courier.medium.bolditalic: *-courier-bold-o-*-120-*-m-*,* + +*fontfamily.courier.large.roman: *-courier-medium-r-*-240-*-m-*,* +*fontfamily.courier.large.bold: *-courier-bold-r-*-240-*-m-*,* +*fontfamily.courier.large.italic: *-courier-medium-o-*-240-*-m-*,* +*fontfamily.courier.large.bolditalic: *-courier-bold-o-*-240-*-m-*,* + +! +! The following is the adobe-times font family. Availiable sizes are +! 80, 100, 120, 140, 180, and 240. This family used to be times-roman. +! +*fontfamily.times.small.roman: *-times-medium-r-*-80-*-p-*,* +*fontfamily.times.small.bold: *-times-bold-r-*-80-*-p-*,* +*fontfamily.times.small.italic: *-times-medium-i-*-80-*-p-*,* +*fontfamily.times.small.bolditalic: *-times-bold-i-*-80-*-p-*,* + +*fontfamily.times.medium.roman: *-times-medium-r-*-120-*-p-*,* +*fontfamily.times.medium.bold: *-times-bold-r-*-120-*-p-*,* +*fontfamily.times.medium.italic: *-times-medium-i-*-120-*-p-*,* +*fontfamily.times.medium.bolditalic: *-times-bold-i-*-120-*-p-*,* + +*fontfamily.times.large.roman: *-times-medium-r-*-240-*-p-*,* +*fontfamily.times.large.bold: *-times-bold-r-*-240-*-p-*,* +*fontfamily.times.large.italic: *-times-medium-i-*-240-*-p-*,* +*fontfamily.times.large.bolditalic: *-times-bold-i-*-240-*-p-*,* + +! +! The following is the adobe-helvetica font family. Availiable sizes are +! 80, 100, 120, 140, 180, and 240. This family used to be helvetica. +! +*fontfamily.helvetica.small.roman: *-helvetica-medium-r-*-80-*-p-*,* +*fontfamily.helvetica.small.bold: *-helvetica-bold-r-*-80-*-p-*,* +*fontfamily.helvetica.small.italic: *-helvetica-medium-o-*-80-*-p-*,* +*fontfamily.helvetica.small.bolditalic: *-helvetica-bold-o-*-80-*-p-*,* + +*fontfamily.helvetica.medium.roman: *-helvetica-medium-r-*-120-*-p-*,* +*fontfamily.helvetica.medium.bold: *-helvetica-bold-r-*-120-*-p-*,* +*fontfamily.helvetica.medium.italic: *-helvetica-medium-o-*-120-*-p-*,* +*fontfamily.helvetica.medium.bolditalic:*-helvetica-bold-o-*-120-*-p-*,* + +*fontfamily.helvetica.large.roman: *-helvetica-medium-r-*-240-*-p-*,* +*fontfamily.helvetica.large.bold: *-helvetica-bold-r-*-240-*-p-*,* +*fontfamily.helvetica.large.italic: *-helvetica-medium-o-*-240-*-p-*,* +*fontfamily.helvetica.large.bolditalic: *-helvetica-bold-o-*-240-*-p-*,* + +! +! Quick hack... +! + +*fontfamily.huge*roman: *-charter-medium-r-*-33-*-p-*,* +*fontfamily.huge*bold: *-charter-bold-r-*-33-*-p-*,* +*fontfamily.huge*italic: *-charter-medium-i-*-33-*-p-*,* +*fontfamily.huge*bolditalic: *-charter-bold-i-*-33-*-p-*,*